mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-07-10 11:21:36 +00:00
prettier: client
This commit is contained in:
parent
f2102a0a23
commit
3beb8905c4
74 changed files with 520 additions and 652 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'absicons';
|
font-family: 'absicons';
|
||||||
src: url('~static/fonts/absicons/absicons.eot?2jfq33');
|
src: url('~static/fonts/absicons/absicons.eot?2jfq33');
|
||||||
src: url('~static/fonts/absicons/absicons.eot?2jfq33#iefix') format('embedded-opentype'),
|
src:
|
||||||
|
url('~static/fonts/absicons/absicons.eot?2jfq33#iefix') format('embedded-opentype'),
|
||||||
url('~static/fonts/absicons/absicons.ttf?2jfq33') format('truetype'),
|
url('~static/fonts/absicons/absicons.ttf?2jfq33') format('truetype'),
|
||||||
url('~static/fonts/absicons/absicons.woff?2jfq33') format('woff'),
|
url('~static/fonts/absicons/absicons.woff?2jfq33') format('woff'),
|
||||||
url('~static/fonts/absicons/absicons.svg?2jfq33#absicons') format('svg');
|
url('~static/fonts/absicons/absicons.svg?2jfq33#absicons') format('svg');
|
||||||
|
|
@ -26,81 +27,81 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-books-1:before {
|
.icon-books-1:before {
|
||||||
content: "\e905";
|
content: '\e905';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-microphone-1:before {
|
.icon-microphone-1:before {
|
||||||
content: "\e902";
|
content: '\e902';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-radio:before {
|
.icon-radio:before {
|
||||||
content: "\e903";
|
content: '\e903';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-podcast:before {
|
.icon-podcast:before {
|
||||||
content: "\e904";
|
content: '\e904';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-audiobookshelf:before {
|
.icon-audiobookshelf:before {
|
||||||
content: "\e900";
|
content: '\e900';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-database:before {
|
.icon-database:before {
|
||||||
content: "\e906";
|
content: '\e906';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-microphone-2:before {
|
.icon-microphone-2:before {
|
||||||
content: "\e901";
|
content: '\e901';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-headphones:before {
|
.icon-headphones:before {
|
||||||
content: "\e910";
|
content: '\e910';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-music:before {
|
.icon-music:before {
|
||||||
content: "\e911";
|
content: '\e911';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-video:before {
|
.icon-video:before {
|
||||||
content: "\e914";
|
content: '\e914';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-microphone-3:before {
|
.icon-microphone-3:before {
|
||||||
content: "\e91e";
|
content: '\e91e';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-book-1:before {
|
.icon-book-1:before {
|
||||||
content: "\e91f";
|
content: '\e91f';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-books-2:before {
|
.icon-books-2:before {
|
||||||
content: "\e920";
|
content: '\e920';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-file-picture:before {
|
.icon-file-picture:before {
|
||||||
content: "\e927";
|
content: '\e927';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-database-1:before {
|
.icon-database-1:before {
|
||||||
content: "\e964";
|
content: '\e964';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-rocket:before {
|
.icon-rocket:before {
|
||||||
content: "\e9a5";
|
content: '\e9a5';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-power:before {
|
.icon-power:before {
|
||||||
content: "\e9b5";
|
content: '\e9b5';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-star:before {
|
.icon-star:before {
|
||||||
content: "\e9d9";
|
content: '\e9d9';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-heart:before {
|
.icon-heart:before {
|
||||||
content: "\e9da";
|
content: '\e9da';
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-rss:before {
|
.icon-rss:before {
|
||||||
content: "\ea9b";
|
content: '\ea9b';
|
||||||
}
|
}
|
||||||
|
|
@ -92,11 +92,10 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Firefox */
|
/* Firefox */
|
||||||
input[type=number] {
|
input[type='number'] {
|
||||||
-moz-appearance: textfield;
|
-moz-appearance: textfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.tracksTable {
|
.tracksTable {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -174,7 +173,10 @@ input[type=number] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-shadow-book {
|
.box-shadow-book {
|
||||||
box-shadow: 4px 1px 8px #11111166, -4px 1px 8px #11111166, 1px -4px 8px #11111166;
|
box-shadow:
|
||||||
|
4px 1px 8px #11111166,
|
||||||
|
-4px 1px 8px #11111166,
|
||||||
|
1px -4px 8px #11111166;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shadow-height {
|
.shadow-height {
|
||||||
|
|
@ -182,7 +184,9 @@ input[type=number] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-shadow-book3d {
|
.box-shadow-book3d {
|
||||||
box-shadow: 4px 1px 8px #11111166, 1px -4px 8px #11111166;
|
box-shadow:
|
||||||
|
4px 1px 8px #11111166,
|
||||||
|
1px -4px 8px #11111166;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-shadow-side {
|
.box-shadow-side {
|
||||||
|
|
@ -204,7 +208,6 @@ Bookshelf Label
|
||||||
color: #fce3a6;
|
color: #fce3a6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.cover-bg {
|
.cover-bg {
|
||||||
width: calc(100% + 40px);
|
width: calc(100% + 40px);
|
||||||
height: calc(100% + 40px);
|
height: calc(100% + 40px);
|
||||||
|
|
|
||||||
|
|
@ -2,247 +2,124 @@
|
||||||
This is borrowed from koodo-reader https://github.com/troyeguo/koodo-reader/tree/master/src
|
This is borrowed from koodo-reader https://github.com/troyeguo/koodo-reader/tree/master/src
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const isTitle = (
|
export const isTitle = (line, isContainDI = false, isContainChapter = false, isContainCHAPTER = false) => {
|
||||||
line,
|
|
||||||
isContainDI = false,
|
|
||||||
isContainChapter = false,
|
|
||||||
isContainCHAPTER = false
|
|
||||||
) => {
|
|
||||||
return (
|
return (
|
||||||
line.length < 30 &&
|
line.length < 30 &&
|
||||||
line.indexOf("[") === -1 &&
|
line.indexOf('[') === -1 &&
|
||||||
line.indexOf("(") === -1 &&
|
line.indexOf('(') === -1 &&
|
||||||
(line.startsWith("CHAPTER") ||
|
(line.startsWith('CHAPTER') ||
|
||||||
line.startsWith("Chapter") ||
|
line.startsWith('Chapter') ||
|
||||||
line.startsWith("序章") ||
|
line.startsWith('序章') ||
|
||||||
line.startsWith("前言") ||
|
line.startsWith('前言') ||
|
||||||
line.startsWith("声明") ||
|
line.startsWith('声明') ||
|
||||||
line.startsWith("聲明") ||
|
line.startsWith('聲明') ||
|
||||||
line.startsWith("写在前面的话") ||
|
line.startsWith('写在前面的话') ||
|
||||||
line.startsWith("后记") ||
|
line.startsWith('后记') ||
|
||||||
line.startsWith("楔子") ||
|
line.startsWith('楔子') ||
|
||||||
line.startsWith("后序") ||
|
line.startsWith('后序') ||
|
||||||
line.startsWith("寫在前面的話") ||
|
line.startsWith('寫在前面的話') ||
|
||||||
line.startsWith("後記") ||
|
line.startsWith('後記') ||
|
||||||
line.startsWith("後序") ||
|
line.startsWith('後序') ||
|
||||||
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(
|
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(line) ||
|
||||||
line
|
(line.startsWith('第') && startWithDI(line)) ||
|
||||||
) ||
|
(line.startsWith('卷') && startWithJUAN(line)) ||
|
||||||
(line.startsWith("第") && startWithDI(line)) ||
|
|
||||||
(line.startsWith("卷") && startWithJUAN(line)) ||
|
|
||||||
startWithRomanNum(line) ||
|
startWithRomanNum(line) ||
|
||||||
(!isContainDI &&
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf('第') > -1 && (line[line.indexOf('第') - 1] === ' ' || line[line.indexOf('第') - 1] === ' ' || line[line.indexOf('第') - 1] === '、' || line[line.indexOf('第') - 1] === ':' || line[line.indexOf('第') - 1] === ':') && startWithDI(line.substr(line.indexOf('第')))) ||
|
||||||
!isContainChapter &&
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf(' ') && startWithNumAndSpace(line)) ||
|
||||||
!isContainCHAPTER &&
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf(' ') && startWithNumAndSpace(line)) ||
|
||||||
line.indexOf("第") > -1 &&
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf('、') && startWithNumAndPause(line)) ||
|
||||||
(line[line.indexOf("第") - 1] === " " ||
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf(':') && startWithNumAndColon(line)) ||
|
||||||
line[line.indexOf("第") - 1] === " " ||
|
(!isContainDI && !isContainChapter && !isContainCHAPTER && line.indexOf(':') && startWithNumAndColon(line)))
|
||||||
line[line.indexOf("第") - 1] === "、" ||
|
)
|
||||||
line[line.indexOf("第") - 1] === ":" ||
|
}
|
||||||
line[line.indexOf("第") - 1] === ":") &&
|
|
||||||
startWithDI(line.substr(line.indexOf("第")))) ||
|
|
||||||
(!isContainDI &&
|
|
||||||
!isContainChapter &&
|
|
||||||
!isContainCHAPTER &&
|
|
||||||
line.indexOf(" ") &&
|
|
||||||
startWithNumAndSpace(line)) ||
|
|
||||||
(!isContainDI &&
|
|
||||||
!isContainChapter &&
|
|
||||||
!isContainCHAPTER &&
|
|
||||||
line.indexOf(" ") &&
|
|
||||||
startWithNumAndSpace(line)) ||
|
|
||||||
(!isContainDI &&
|
|
||||||
!isContainChapter &&
|
|
||||||
!isContainCHAPTER &&
|
|
||||||
line.indexOf("、") &&
|
|
||||||
startWithNumAndPause(line)) ||
|
|
||||||
(!isContainDI &&
|
|
||||||
!isContainChapter &&
|
|
||||||
!isContainCHAPTER &&
|
|
||||||
line.indexOf(":") &&
|
|
||||||
startWithNumAndColon(line)) ||
|
|
||||||
(!isContainDI &&
|
|
||||||
!isContainChapter &&
|
|
||||||
!isContainCHAPTER &&
|
|
||||||
line.indexOf(":") &&
|
|
||||||
startWithNumAndColon(line)))
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const startWithDI = (line) => {
|
const startWithDI = (line) => {
|
||||||
let keywords = [
|
let keywords = ['章', '节', '回', '節', '卷', '部', '輯', '辑', '話', '集', '话', '篇']
|
||||||
"章",
|
let flag = false
|
||||||
"节",
|
|
||||||
"回",
|
|
||||||
"節",
|
|
||||||
"卷",
|
|
||||||
"部",
|
|
||||||
"輯",
|
|
||||||
"辑",
|
|
||||||
"話",
|
|
||||||
"集",
|
|
||||||
"话",
|
|
||||||
"篇",
|
|
||||||
];
|
|
||||||
let flag = false;
|
|
||||||
for (let i = 0; i < keywords.length; i++) {
|
for (let i = 0; i < keywords.length; i++) {
|
||||||
if (
|
if ((line.indexOf(keywords[i]) > -1 && (line[line.indexOf(keywords[i]) + 1] === ' ' || line[line.indexOf(keywords[i]) + 1] === ' ' || line[line.indexOf(keywords[i]) + 1] === '、' || line[line.indexOf(keywords[i]) + 1] === ':' || line[line.indexOf(keywords[i]) + 1] === ':')) || !line[line.indexOf(keywords[i]) + 1]) {
|
||||||
(line.indexOf(keywords[i]) > -1 &&
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(1, line.indexOf(keywords[i])).trim()) || /^\d+$/.test(line.substring(1, line.indexOf(keywords[i])).trim())) {
|
||||||
(line[line.indexOf(keywords[i]) + 1] === " " ||
|
flag = true
|
||||||
line[line.indexOf(keywords[i]) + 1] === " " ||
|
|
||||||
line[line.indexOf(keywords[i]) + 1] === "、" ||
|
|
||||||
line[line.indexOf(keywords[i]) + 1] === ":" ||
|
|
||||||
line[line.indexOf(keywords[i]) + 1] === ":")) ||
|
|
||||||
!line[line.indexOf(keywords[i]) + 1]
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(1, line.indexOf(keywords[i])).trim()
|
|
||||||
) ||
|
|
||||||
/^\d+$/.test(line.substring(1, line.indexOf(keywords[i])).trim())
|
|
||||||
) {
|
|
||||||
flag = true;
|
|
||||||
}
|
}
|
||||||
if (flag) break;
|
if (flag) break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return flag;
|
return flag
|
||||||
};
|
}
|
||||||
const startWithJUAN = (line) => {
|
const startWithJUAN = (line) => {
|
||||||
if (
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(1, line.indexOf(' '))) || /^\d+$/.test(line.substring(1, line.indexOf(' ')))) return true
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(1, line.indexOf(' '))) || /^\d+$/.test(line.substring(1, line.indexOf(' ')))) return true
|
||||||
line.substring(1, line.indexOf(" "))
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(1)) || /^\d+$/.test(line.substring(1))) return true
|
||||||
) ||
|
return false
|
||||||
/^\d+$/.test(line.substring(1, line.indexOf(" ")))
|
}
|
||||||
)
|
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(1, line.indexOf(" "))
|
|
||||||
) ||
|
|
||||||
/^\d+$/.test(line.substring(1, line.indexOf(" ")))
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(1)
|
|
||||||
) ||
|
|
||||||
/^\d+$/.test(line.substring(1))
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const startWithRomanNum = (line) => {
|
const startWithRomanNum = (line) => {
|
||||||
if (
|
if (/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(line.substring(0, line.indexOf(' ')))) return true
|
||||||
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(
|
if (/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(line.substring(0, line.indexOf('.')))) return true
|
||||||
line.substring(0, line.indexOf(" "))
|
if (/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(line.trim())) return true
|
||||||
)
|
return false
|
||||||
)
|
}
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(
|
|
||||||
line.substring(0, line.indexOf("."))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(
|
|
||||||
line.trim()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
const startWithNumAndSpace = (line) => {
|
const startWithNumAndSpace = (line) => {
|
||||||
if (
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(0, line.indexOf(' ')))) return true
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(0, line.indexOf(' ')))) return true
|
||||||
line.substring(0, line.indexOf(" "))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(0, line.indexOf(" "))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (/^\d+$/.test(line.substring(0, line.indexOf(" ")))) return true;
|
if (/^\d+$/.test(line.substring(0, line.indexOf(' ')))) return true
|
||||||
if (/^\d+$/.test(line.substring(0, line.indexOf(" ")))) return true;
|
if (/^\d+$/.test(line.substring(0, line.indexOf(' ')))) return true
|
||||||
return false;
|
return false
|
||||||
};
|
}
|
||||||
const startWithNumAndColon = (line) => {
|
const startWithNumAndColon = (line) => {
|
||||||
if (
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(0, line.indexOf(':')))) return true
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(0, line.indexOf(':')))) return true
|
||||||
line.substring(0, line.indexOf(":"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
if (
|
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(0, line.indexOf(":"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (/^\d+$/.test(line.substring(0, line.indexOf(":")))) return true;
|
if (/^\d+$/.test(line.substring(0, line.indexOf(':')))) return true
|
||||||
if (/^\d+$/.test(line.substring(0, line.indexOf(":")))) return true;
|
if (/^\d+$/.test(line.substring(0, line.indexOf(':')))) return true
|
||||||
return false;
|
return false
|
||||||
};
|
}
|
||||||
const startWithNumAndPause = (line) => {
|
const startWithNumAndPause = (line) => {
|
||||||
if (
|
if (/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(line.substring(0, line.indexOf('、')))) return true
|
||||||
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
|
|
||||||
line.substring(0, line.indexOf("、"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (/^\d+$/.test(line.substring(0, line.indexOf("、")))) return true;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
if (/^\d+$/.test(line.substring(0, line.indexOf('、')))) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
class HtmlParser {
|
class HtmlParser {
|
||||||
bookDoc;
|
bookDoc
|
||||||
contentList;
|
contentList
|
||||||
contentTitleList;
|
contentTitleList
|
||||||
constructor(bookDoc) {
|
constructor(bookDoc) {
|
||||||
this.bookDoc = bookDoc;
|
this.bookDoc = bookDoc
|
||||||
this.contentList = [];
|
this.contentList = []
|
||||||
this.contentTitleList = [];
|
this.contentTitleList = []
|
||||||
this.getContent(bookDoc);
|
this.getContent(bookDoc)
|
||||||
}
|
}
|
||||||
getContent(bookDoc) {
|
getContent(bookDoc) {
|
||||||
this.contentList = Array.from(
|
this.contentList = Array.from(bookDoc.querySelectorAll('h1,h2,h3,h4,h5,b,font')).filter((item, index) => {
|
||||||
bookDoc.querySelectorAll("h1,h2,h3,h4,h5,b,font")
|
return isTitle(item.innerText.trim())
|
||||||
).filter((item, index) => {
|
})
|
||||||
return isTitle(item.innerText.trim());
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i = 0; i < this.contentList.length; i++) {
|
for (let i = 0; i < this.contentList.length; i++) {
|
||||||
let random = Math.floor(Math.random() * 900000) + 100000;
|
let random = Math.floor(Math.random() * 900000) + 100000
|
||||||
this.contentTitleList.push({
|
this.contentTitleList.push({
|
||||||
label: this.contentList[i].innerText,
|
label: this.contentList[i].innerText,
|
||||||
id: "title" + random,
|
id: 'title' + random,
|
||||||
href: "#title" + random,
|
href: '#title' + random,
|
||||||
subitems: [],
|
subitems: []
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
for (let i = 0; i < this.contentList.length; i++) {
|
for (let i = 0; i < this.contentList.length; i++) {
|
||||||
this.contentList[i].id = this.contentTitleList[i].id;
|
this.contentList[i].id = this.contentTitleList[i].id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getAnchoredDoc() {
|
getAnchoredDoc() {
|
||||||
return this.bookDoc;
|
return this.bookDoc
|
||||||
}
|
}
|
||||||
getContentList() {
|
getContentList() {
|
||||||
return this.contentTitleList.filter((item, index) => {
|
return this.contentTitleList.filter((item, index) => {
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
return item.label !== this.contentTitleList[index - 1].label;
|
return item.label !== this.contentTitleList[index - 1].label
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HtmlParser;
|
export default HtmlParser
|
||||||
|
|
|
||||||
|
|
@ -4,447 +4,440 @@ This is borrowed from koodo-reader https://github.com/troyeguo/koodo-reader/tree
|
||||||
|
|
||||||
function ab2str(buf) {
|
function ab2str(buf) {
|
||||||
if (buf instanceof ArrayBuffer) {
|
if (buf instanceof ArrayBuffer) {
|
||||||
buf = new Uint8Array(buf);
|
buf = new Uint8Array(buf)
|
||||||
}
|
}
|
||||||
return new TextDecoder("utf-8").decode(buf);
|
return new TextDecoder('utf-8').decode(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
var domParser = new DOMParser();
|
var domParser = new DOMParser()
|
||||||
|
|
||||||
class Buffer {
|
class Buffer {
|
||||||
capacity;
|
capacity
|
||||||
fragment_list;
|
fragment_list
|
||||||
imageArray;
|
imageArray
|
||||||
cur_fragment;
|
cur_fragment
|
||||||
constructor(capacity) {
|
constructor(capacity) {
|
||||||
this.capacity = capacity;
|
this.capacity = capacity
|
||||||
this.fragment_list = [];
|
this.fragment_list = []
|
||||||
this.imageArray = [];
|
this.imageArray = []
|
||||||
this.cur_fragment = new Fragment(capacity);
|
this.cur_fragment = new Fragment(capacity)
|
||||||
this.fragment_list.push(this.cur_fragment);
|
this.fragment_list.push(this.cur_fragment)
|
||||||
}
|
}
|
||||||
write(byte) {
|
write(byte) {
|
||||||
var result = this.cur_fragment.write(byte);
|
var result = this.cur_fragment.write(byte)
|
||||||
if (!result) {
|
if (!result) {
|
||||||
this.cur_fragment = new Fragment(this.capacity);
|
this.cur_fragment = new Fragment(this.capacity)
|
||||||
this.fragment_list.push(this.cur_fragment);
|
this.fragment_list.push(this.cur_fragment)
|
||||||
this.cur_fragment.write(byte);
|
this.cur_fragment.write(byte)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
get(idx) {
|
get(idx) {
|
||||||
var fi = 0;
|
var fi = 0
|
||||||
while (fi < this.fragment_list.length) {
|
while (fi < this.fragment_list.length) {
|
||||||
var frag = this.fragment_list[fi];
|
var frag = this.fragment_list[fi]
|
||||||
if (idx < frag.size) {
|
if (idx < frag.size) {
|
||||||
return frag.get(idx);
|
return frag.get(idx)
|
||||||
}
|
}
|
||||||
idx -= frag.size;
|
idx -= frag.size
|
||||||
fi += 1;
|
fi += 1
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
size() {
|
size() {
|
||||||
var s = 0;
|
var s = 0
|
||||||
for (var i = 0; i < this.fragment_list.length; i++) {
|
for (var i = 0; i < this.fragment_list.length; i++) {
|
||||||
s += this.fragment_list[i].size;
|
s += this.fragment_list[i].size
|
||||||
}
|
}
|
||||||
return s;
|
return s
|
||||||
}
|
}
|
||||||
shrink() {
|
shrink() {
|
||||||
var total_buffer = new Uint8Array(this.size());
|
var total_buffer = new Uint8Array(this.size())
|
||||||
var offset = 0;
|
var offset = 0
|
||||||
for (var i = 0; i < this.fragment_list.length; i++) {
|
for (var i = 0; i < this.fragment_list.length; i++) {
|
||||||
var frag = this.fragment_list[i];
|
var frag = this.fragment_list[i]
|
||||||
if (frag.full()) {
|
if (frag.full()) {
|
||||||
total_buffer.set(frag.buffer, offset);
|
total_buffer.set(frag.buffer, offset)
|
||||||
} else {
|
} else {
|
||||||
total_buffer.set(frag.buffer.slice(0, frag.size), offset);
|
total_buffer.set(frag.buffer.slice(0, frag.size), offset)
|
||||||
}
|
}
|
||||||
offset += frag.size;
|
offset += frag.size
|
||||||
}
|
}
|
||||||
return total_buffer;
|
return total_buffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var copagesne_uint8array = function (buffers) {
|
var copagesne_uint8array = function (buffers) {
|
||||||
var total_size = 0;
|
var total_size = 0
|
||||||
for (let i = 0; i < buffers.length; i++) {
|
for (let i = 0; i < buffers.length; i++) {
|
||||||
var buffer = buffers[i];
|
var buffer = buffers[i]
|
||||||
total_size += buffer.length;
|
total_size += buffer.length
|
||||||
}
|
}
|
||||||
var total_buffer = new Uint8Array(total_size);
|
var total_buffer = new Uint8Array(total_size)
|
||||||
var offset = 0;
|
var offset = 0
|
||||||
for (let i = 0; i < buffers.length; i++) {
|
for (let i = 0; i < buffers.length; i++) {
|
||||||
buffer = buffers[i];
|
buffer = buffers[i]
|
||||||
total_buffer.set(buffer, offset);
|
total_buffer.set(buffer, offset)
|
||||||
offset += buffer.length;
|
offset += buffer.length
|
||||||
}
|
}
|
||||||
return total_buffer;
|
return total_buffer
|
||||||
};
|
}
|
||||||
|
|
||||||
class Fragment {
|
class Fragment {
|
||||||
buffer;
|
buffer
|
||||||
capacity;
|
capacity
|
||||||
size;
|
size
|
||||||
constructor(capacity) {
|
constructor(capacity) {
|
||||||
this.buffer = new Uint8Array(capacity);
|
this.buffer = new Uint8Array(capacity)
|
||||||
this.capacity = capacity;
|
this.capacity = capacity
|
||||||
this.size = 0;
|
this.size = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
write(byte) {
|
write(byte) {
|
||||||
if (this.size >= this.capacity) {
|
if (this.size >= this.capacity) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
this.buffer[this.size] = byte;
|
this.buffer[this.size] = byte
|
||||||
this.size += 1;
|
this.size += 1
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
full() {
|
full() {
|
||||||
return this.size === this.capacity;
|
return this.size === this.capacity
|
||||||
}
|
}
|
||||||
get(idx) {
|
get(idx) {
|
||||||
return this.buffer[idx];
|
return this.buffer[idx]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var uncompression_lz77 = function (data) {
|
var uncompression_lz77 = function (data) {
|
||||||
var length = data.length;
|
var length = data.length
|
||||||
var offset = 0; // Current offset into data
|
var offset = 0 // Current offset into data
|
||||||
var buffer = new Buffer(data.length);
|
var buffer = new Buffer(data.length)
|
||||||
|
|
||||||
while (offset < length) {
|
while (offset < length) {
|
||||||
var char = data[offset];
|
var char = data[offset]
|
||||||
offset += 1;
|
offset += 1
|
||||||
|
|
||||||
if (char === 0) {
|
if (char === 0) {
|
||||||
buffer.write(char);
|
buffer.write(char)
|
||||||
} else if (char <= 8) {
|
} else if (char <= 8) {
|
||||||
for (var i = offset; i < offset + char; i++) {
|
for (var i = offset; i < offset + char; i++) {
|
||||||
buffer.write(data[i]);
|
buffer.write(data[i])
|
||||||
}
|
}
|
||||||
offset += char;
|
offset += char
|
||||||
} else if (char <= 0x7f) {
|
} else if (char <= 0x7f) {
|
||||||
buffer.write(char);
|
buffer.write(char)
|
||||||
} else if (char <= 0xbf) {
|
} else if (char <= 0xbf) {
|
||||||
var next = data[offset];
|
var next = data[offset]
|
||||||
offset += 1;
|
offset += 1
|
||||||
var distance = (((char << 8) | next) >> 3) & 0x7ff;
|
var distance = (((char << 8) | next) >> 3) & 0x7ff
|
||||||
var lz_length = (next & 0x7) + 3;
|
var lz_length = (next & 0x7) + 3
|
||||||
|
|
||||||
var buffer_size = buffer.size();
|
var buffer_size = buffer.size()
|
||||||
for (let i = 0; i < lz_length; i++) {
|
for (let i = 0; i < lz_length; i++) {
|
||||||
buffer.write(buffer.get(buffer_size - distance));
|
buffer.write(buffer.get(buffer_size - distance))
|
||||||
buffer_size += 1;
|
buffer_size += 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
buffer.write(32);
|
buffer.write(32)
|
||||||
buffer.write(char ^ 0x80);
|
buffer.write(char ^ 0x80)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return buffer;
|
return buffer
|
||||||
};
|
}
|
||||||
|
|
||||||
class MobiFile {
|
class MobiFile {
|
||||||
view;
|
view
|
||||||
buffer;
|
buffer
|
||||||
offset;
|
offset
|
||||||
header;
|
header
|
||||||
palm_header;
|
palm_header
|
||||||
mobi_header;
|
mobi_header
|
||||||
reclist;
|
reclist
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
this.view = new DataView(data);
|
this.view = new DataView(data)
|
||||||
this.buffer = this.view.buffer;
|
this.buffer = this.view.buffer
|
||||||
this.offset = 0;
|
this.offset = 0
|
||||||
this.header = null;
|
this.header = null
|
||||||
}
|
}
|
||||||
|
|
||||||
parse() { }
|
parse() {}
|
||||||
|
|
||||||
getUint8() {
|
getUint8() {
|
||||||
var v = this.view.getUint8(this.offset);
|
var v = this.view.getUint8(this.offset)
|
||||||
this.offset += 1;
|
this.offset += 1
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
getUint16() {
|
getUint16() {
|
||||||
var v = this.view.getUint16(this.offset);
|
var v = this.view.getUint16(this.offset)
|
||||||
this.offset += 2;
|
this.offset += 2
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
getUint32() {
|
getUint32() {
|
||||||
var v = this.view.getUint32(this.offset);
|
var v = this.view.getUint32(this.offset)
|
||||||
this.offset += 4;
|
this.offset += 4
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
getStr(size) {
|
getStr(size) {
|
||||||
var v = ab2str(this.buffer.slice(this.offset, this.offset + size));
|
var v = ab2str(this.buffer.slice(this.offset, this.offset + size))
|
||||||
this.offset += size;
|
this.offset += size
|
||||||
return v;
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
skip(size) {
|
skip(size) {
|
||||||
this.offset += size;
|
this.offset += size
|
||||||
}
|
}
|
||||||
|
|
||||||
setoffset(_of) {
|
setoffset(_of) {
|
||||||
this.offset = _of;
|
this.offset = _of
|
||||||
}
|
}
|
||||||
|
|
||||||
get_record_extrasize(data, flags) {
|
get_record_extrasize(data, flags) {
|
||||||
var pos = data.length - 1;
|
var pos = data.length - 1
|
||||||
var extra = 0;
|
var extra = 0
|
||||||
for (var i = 15; i > 0; i--) {
|
for (var i = 15; i > 0; i--) {
|
||||||
if (flags & (1 << i)) {
|
if (flags & (1 << i)) {
|
||||||
var res = this.buffer_get_varlen(data, pos);
|
var res = this.buffer_get_varlen(data, pos)
|
||||||
var size = res[0];
|
var size = res[0]
|
||||||
var l = res[1];
|
var l = res[1]
|
||||||
pos = res[2];
|
pos = res[2]
|
||||||
pos -= size - l;
|
pos -= size - l
|
||||||
extra += size;
|
extra += size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flags & 1) {
|
if (flags & 1) {
|
||||||
var a = data[pos];
|
var a = data[pos]
|
||||||
extra += (a & 0x3) + 1;
|
extra += (a & 0x3) + 1
|
||||||
}
|
}
|
||||||
return extra;
|
return extra
|
||||||
}
|
}
|
||||||
|
|
||||||
// data should be uint8array
|
// data should be uint8array
|
||||||
buffer_get_varlen(data, pos) {
|
buffer_get_varlen(data, pos) {
|
||||||
var l = 0;
|
var l = 0
|
||||||
var size = 0;
|
var size = 0
|
||||||
var byte_count = 0;
|
var byte_count = 0
|
||||||
var mask = 0x7f;
|
var mask = 0x7f
|
||||||
var stop_flag = 0x80;
|
var stop_flag = 0x80
|
||||||
var shift = 0;
|
var shift = 0
|
||||||
for (var i = 0; ; i++) {
|
for (var i = 0; ; i++) {
|
||||||
var byte = data[pos];
|
var byte = data[pos]
|
||||||
size |= (byte & mask) << shift;
|
size |= (byte & mask) << shift
|
||||||
shift += 7;
|
shift += 7
|
||||||
l += 1;
|
l += 1
|
||||||
byte_count += 1;
|
byte_count += 1
|
||||||
pos -= 1;
|
pos -= 1
|
||||||
|
|
||||||
var to_stop = byte & stop_flag;
|
var to_stop = byte & stop_flag
|
||||||
if (byte_count >= 4 || to_stop > 0) {
|
if (byte_count >= 4 || to_stop > 0) {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return [size, l, pos];
|
return [size, l, pos]
|
||||||
}
|
}
|
||||||
// 读出文本内容
|
// 读出文本内容
|
||||||
read_text() {
|
read_text() {
|
||||||
var text_end = this.palm_header.record_count;
|
var text_end = this.palm_header.record_count
|
||||||
var buffers = [];
|
var buffers = []
|
||||||
for (var i = 1; i <= text_end; i++) {
|
for (var i = 1; i <= text_end; i++) {
|
||||||
buffers.push(this.read_text_record(i));
|
buffers.push(this.read_text_record(i))
|
||||||
}
|
}
|
||||||
var all = copagesne_uint8array(buffers);
|
var all = copagesne_uint8array(buffers)
|
||||||
return ab2str(all);
|
return ab2str(all)
|
||||||
}
|
}
|
||||||
|
|
||||||
read_text_record(i) {
|
read_text_record(i) {
|
||||||
var flags = this.mobi_header.extra_flags;
|
var flags = this.mobi_header.extra_flags
|
||||||
var begin = this.reclist[i].offset;
|
var begin = this.reclist[i].offset
|
||||||
var end = this.reclist[i + 1].offset;
|
var end = this.reclist[i + 1].offset
|
||||||
|
|
||||||
var data = new Uint8Array(this.buffer.slice(begin, end));
|
var data = new Uint8Array(this.buffer.slice(begin, end))
|
||||||
var ex = this.get_record_extrasize(data, flags);
|
var ex = this.get_record_extrasize(data, flags)
|
||||||
|
|
||||||
data = new Uint8Array(this.buffer.slice(begin, end - ex));
|
data = new Uint8Array(this.buffer.slice(begin, end - ex))
|
||||||
if (this.palm_header.compression === 2) {
|
if (this.palm_header.compression === 2) {
|
||||||
var buffer = uncompression_lz77(data);
|
var buffer = uncompression_lz77(data)
|
||||||
return buffer.shrink();
|
return buffer.shrink()
|
||||||
} else {
|
} else {
|
||||||
return data;
|
return data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 从buffer中读出image
|
// 从buffer中读出image
|
||||||
read_image(idx) {
|
read_image(idx) {
|
||||||
var first_image_idx = this.mobi_header.first_image_idx;
|
var first_image_idx = this.mobi_header.first_image_idx
|
||||||
var begin = this.reclist[first_image_idx + idx].offset;
|
var begin = this.reclist[first_image_idx + idx].offset
|
||||||
var end = this.reclist[first_image_idx + idx + 1].offset;
|
var end = this.reclist[first_image_idx + idx + 1].offset
|
||||||
var data = new Uint8Array(this.buffer.slice(begin, end));
|
var data = new Uint8Array(this.buffer.slice(begin, end))
|
||||||
return new Blob([data.buffer]);
|
return new Blob([data.buffer])
|
||||||
}
|
}
|
||||||
|
|
||||||
load() {
|
load() {
|
||||||
this.header = this.load_pdbheader();
|
this.header = this.load_pdbheader()
|
||||||
this.reclist = this.load_reclist();
|
this.reclist = this.load_reclist()
|
||||||
this.load_record0();
|
this.load_record0()
|
||||||
}
|
}
|
||||||
|
|
||||||
load_pdbheader() {
|
load_pdbheader() {
|
||||||
var header = {};
|
var header = {}
|
||||||
header.name = this.getStr(32);
|
header.name = this.getStr(32)
|
||||||
header.attr = this.getUint16();
|
header.attr = this.getUint16()
|
||||||
header.version = this.getUint16();
|
header.version = this.getUint16()
|
||||||
header.ctime = this.getUint32();
|
header.ctime = this.getUint32()
|
||||||
header.mtime = this.getUint32();
|
header.mtime = this.getUint32()
|
||||||
header.btime = this.getUint32();
|
header.btime = this.getUint32()
|
||||||
header.mod_num = this.getUint32();
|
header.mod_num = this.getUint32()
|
||||||
header.appinfo_offset = this.getUint32();
|
header.appinfo_offset = this.getUint32()
|
||||||
header.sortinfo_offset = this.getUint32();
|
header.sortinfo_offset = this.getUint32()
|
||||||
header.type = this.getStr(4);
|
header.type = this.getStr(4)
|
||||||
header.creator = this.getStr(4);
|
header.creator = this.getStr(4)
|
||||||
header.uid = this.getUint32();
|
header.uid = this.getUint32()
|
||||||
header.next_rec = this.getUint32();
|
header.next_rec = this.getUint32()
|
||||||
header.record_num = this.getUint16();
|
header.record_num = this.getUint16()
|
||||||
return header;
|
return header
|
||||||
}
|
}
|
||||||
|
|
||||||
load_reclist() {
|
load_reclist() {
|
||||||
var reclist = [];
|
var reclist = []
|
||||||
for (var i = 0; i < this.header.record_num; i++) {
|
for (var i = 0; i < this.header.record_num; i++) {
|
||||||
var record = {};
|
var record = {}
|
||||||
record.offset = this.getUint32();
|
record.offset = this.getUint32()
|
||||||
// TODO(zz) change
|
// TODO(zz) change
|
||||||
record.attr = this.getUint32();
|
record.attr = this.getUint32()
|
||||||
reclist.push(record);
|
reclist.push(record)
|
||||||
}
|
}
|
||||||
return reclist;
|
return reclist
|
||||||
}
|
}
|
||||||
load_record0() {
|
load_record0() {
|
||||||
this.palm_header = this.load_record0_header();
|
this.palm_header = this.load_record0_header()
|
||||||
this.mobi_header = this.load_mobi_header();
|
this.mobi_header = this.load_mobi_header()
|
||||||
}
|
}
|
||||||
|
|
||||||
load_record0_header() {
|
load_record0_header() {
|
||||||
var p_header = {};
|
var p_header = {}
|
||||||
var first_record = this.reclist[0];
|
var first_record = this.reclist[0]
|
||||||
this.setoffset(first_record.offset);
|
this.setoffset(first_record.offset)
|
||||||
|
|
||||||
p_header.compression = this.getUint16();
|
p_header.compression = this.getUint16()
|
||||||
this.skip(2);
|
this.skip(2)
|
||||||
p_header.text_length = this.getUint32();
|
p_header.text_length = this.getUint32()
|
||||||
p_header.record_count = this.getUint16();
|
p_header.record_count = this.getUint16()
|
||||||
p_header.record_size = this.getUint16();
|
p_header.record_size = this.getUint16()
|
||||||
p_header.encryption_type = this.getUint16();
|
p_header.encryption_type = this.getUint16()
|
||||||
this.skip(2);
|
this.skip(2)
|
||||||
|
|
||||||
return p_header;
|
return p_header
|
||||||
}
|
}
|
||||||
|
|
||||||
load_mobi_header() {
|
load_mobi_header() {
|
||||||
var mobi_header = {};
|
var mobi_header = {}
|
||||||
|
|
||||||
var start_offset = this.offset;
|
var start_offset = this.offset
|
||||||
|
|
||||||
mobi_header.identifier = this.getUint32();
|
mobi_header.identifier = this.getUint32()
|
||||||
mobi_header.header_length = this.getUint32();
|
mobi_header.header_length = this.getUint32()
|
||||||
mobi_header.mobi_type = this.getUint32();
|
mobi_header.mobi_type = this.getUint32()
|
||||||
mobi_header.text_encoding = this.getUint32();
|
mobi_header.text_encoding = this.getUint32()
|
||||||
mobi_header.uid = this.getUint32();
|
mobi_header.uid = this.getUint32()
|
||||||
mobi_header.generator_version = this.getUint32();
|
mobi_header.generator_version = this.getUint32()
|
||||||
|
|
||||||
this.skip(40);
|
this.skip(40)
|
||||||
|
|
||||||
mobi_header.first_nonbook_index = this.getUint32();
|
mobi_header.first_nonbook_index = this.getUint32()
|
||||||
mobi_header.full_name_offset = this.getUint32();
|
mobi_header.full_name_offset = this.getUint32()
|
||||||
mobi_header.full_name_length = this.getUint32();
|
mobi_header.full_name_length = this.getUint32()
|
||||||
|
|
||||||
mobi_header.language = this.getUint32();
|
mobi_header.language = this.getUint32()
|
||||||
mobi_header.input_language = this.getUint32();
|
mobi_header.input_language = this.getUint32()
|
||||||
mobi_header.output_language = this.getUint32();
|
mobi_header.output_language = this.getUint32()
|
||||||
mobi_header.min_version = this.getUint32();
|
mobi_header.min_version = this.getUint32()
|
||||||
mobi_header.first_image_idx = this.getUint32();
|
mobi_header.first_image_idx = this.getUint32()
|
||||||
|
|
||||||
mobi_header.huff_rec_index = this.getUint32();
|
mobi_header.huff_rec_index = this.getUint32()
|
||||||
mobi_header.huff_rec_count = this.getUint32();
|
mobi_header.huff_rec_count = this.getUint32()
|
||||||
mobi_header.datp_rec_index = this.getUint32();
|
mobi_header.datp_rec_index = this.getUint32()
|
||||||
mobi_header.datp_rec_count = this.getUint32();
|
mobi_header.datp_rec_count = this.getUint32()
|
||||||
|
|
||||||
mobi_header.exth_flags = this.getUint32();
|
mobi_header.exth_flags = this.getUint32()
|
||||||
|
|
||||||
this.skip(36);
|
this.skip(36)
|
||||||
|
|
||||||
mobi_header.drm_offset = this.getUint32();
|
mobi_header.drm_offset = this.getUint32()
|
||||||
mobi_header.drm_count = this.getUint32();
|
mobi_header.drm_count = this.getUint32()
|
||||||
mobi_header.drm_size = this.getUint32();
|
mobi_header.drm_size = this.getUint32()
|
||||||
mobi_header.drm_flags = this.getUint32();
|
mobi_header.drm_flags = this.getUint32()
|
||||||
|
|
||||||
this.skip(8);
|
this.skip(8)
|
||||||
|
|
||||||
// TODO (zz) fdst_index
|
// TODO (zz) fdst_index
|
||||||
this.skip(4);
|
this.skip(4)
|
||||||
|
|
||||||
this.skip(46);
|
this.skip(46)
|
||||||
|
|
||||||
mobi_header.extra_flags = this.getUint16();
|
mobi_header.extra_flags = this.getUint16()
|
||||||
|
|
||||||
this.setoffset(start_offset + mobi_header.header_length);
|
this.setoffset(start_offset + mobi_header.header_length)
|
||||||
|
|
||||||
return mobi_header;
|
return mobi_header
|
||||||
}
|
}
|
||||||
load_exth_header() {
|
load_exth_header() {
|
||||||
// TODO
|
// TODO
|
||||||
return {};
|
return {}
|
||||||
}
|
}
|
||||||
extractContent(s) {
|
extractContent(s) {
|
||||||
var span = document.createElement("span");
|
var span = document.createElement('span')
|
||||||
span.innerHTML = s;
|
span.innerHTML = s
|
||||||
return span.textContent || span.innerText;
|
return span.textContent || span.innerText
|
||||||
}
|
}
|
||||||
render(isElectron = false) {
|
render(isElectron = false) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.load();
|
this.load()
|
||||||
var content = this.read_text();
|
var content = this.read_text()
|
||||||
var bookDoc = domParser.parseFromString(content, "text/html")
|
var bookDoc = domParser.parseFromString(content, 'text/html').documentElement
|
||||||
.documentElement;
|
let lines = Array.from(bookDoc.querySelectorAll('p,b,font,h3,h2,h1'))
|
||||||
let lines = Array.from(
|
let parseContent = []
|
||||||
bookDoc.querySelectorAll("p,b,font,h3,h2,h1")
|
|
||||||
);
|
|
||||||
let parseContent = [];
|
|
||||||
for (let i = 0, len = lines.length; i < len - 1; i++) {
|
for (let i = 0, len = lines.length; i < len - 1; i++) {
|
||||||
lines[i].innerText &&
|
lines[i].innerText && lines[i].innerText !== parseContent[parseContent.length - 1] && parseContent.push(lines[i].innerText)
|
||||||
lines[i].innerText !== parseContent[parseContent.length - 1] &&
|
let imgDoms = lines[i].getElementsByTagName('img')
|
||||||
parseContent.push(lines[i].innerText);
|
|
||||||
let imgDoms = lines[i].getElementsByTagName("img");
|
|
||||||
if (imgDoms.length > 0) {
|
if (imgDoms.length > 0) {
|
||||||
for (let i = 0; i < imgDoms.length; i++) {
|
for (let i = 0; i < imgDoms.length; i++) {
|
||||||
parseContent.push("#image");
|
parseContent.push('#image')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleImage = async () => {
|
const handleImage = async () => {
|
||||||
var imgDoms = bookDoc.getElementsByTagName("img");
|
var imgDoms = bookDoc.getElementsByTagName('img')
|
||||||
parseContent.push("~image");
|
parseContent.push('~image')
|
||||||
for (let i = 0; i < imgDoms.length; i++) {
|
for (let i = 0; i < imgDoms.length; i++) {
|
||||||
const src = await this.render_image(imgDoms, i);
|
const src = await this.render_image(imgDoms, i)
|
||||||
parseContent.push(
|
parseContent.push(src + ' ' + imgDoms[i].width + ' ' + imgDoms[i].height)
|
||||||
src + " " + imgDoms[i].width + " " + imgDoms[i].height
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (imgDoms.length > 200 || !isElectron) {
|
if (imgDoms.length > 200 || !isElectron) {
|
||||||
resolve(bookDoc);
|
resolve(bookDoc)
|
||||||
} else {
|
} else {
|
||||||
resolve(parseContent.join("\n \n"));
|
resolve(parseContent.join('\n \n'))
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
handleImage();
|
handleImage()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
render_image = (imgDoms, i) => {
|
render_image = (imgDoms, i) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
var imgDom = imgDoms[i];
|
var imgDom = imgDoms[i]
|
||||||
var idx = +imgDom.getAttribute("recindex");
|
var idx = +imgDom.getAttribute('recindex')
|
||||||
var blob = this.read_image(idx - 1);
|
var blob = this.read_image(idx - 1)
|
||||||
var imgReader = new FileReader();
|
var imgReader = new FileReader()
|
||||||
imgReader.onload = (e) => {
|
imgReader.onload = (e) => {
|
||||||
imgDom.src = e.target?.result;
|
imgDom.src = e.target?.result
|
||||||
resolve(e.target?.result);
|
resolve(e.target?.result)
|
||||||
};
|
}
|
||||||
imgReader.onerror = function (err) {
|
imgReader.onerror = function (err) {
|
||||||
reject(err);
|
reject(err)
|
||||||
};
|
}
|
||||||
imgReader.readAsDataURL(blob);
|
imgReader.readAsDataURL(blob)
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default MobiFile;
|
export default MobiFile
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-symbols.fill {
|
.material-symbols.fill {
|
||||||
font-variation-settings:
|
font-variation-settings: 'FILL' 1;
|
||||||
'FILL' 1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cyrillic-ext */
|
/* cyrillic-ext */
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,6 @@
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.menu-enter,
|
.menu-enter,
|
||||||
.menu-leave-active {
|
.menu-leave-active {
|
||||||
transform: translateY(-15px);
|
transform: translateY(-15px);
|
||||||
|
|
@ -70,7 +68,6 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.list-complete-item {
|
.list-complete-item {
|
||||||
transition: all 0.8s ease;
|
transition: all 0.8s ease;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ trix-toolbar .trix-button--icon::before {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
content: "";
|
content: '';
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
|
|
@ -209,7 +209,9 @@ trix-toolbar .trix-dialog {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
padding: 15px 10px;
|
padding: 15px 10px;
|
||||||
background: rgb(48, 48, 48);
|
background: rgb(48, 48, 48);
|
||||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
box-shadow:
|
||||||
|
0 10px 15px -3px rgba(0, 0, 0, 0.1),
|
||||||
|
0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||||
border: 1px solid rgb(112, 112, 112);
|
border: 1px solid rgb(112, 112, 112);
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
|
|
@ -230,7 +232,7 @@ trix-toolbar .trix-input--dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
trix-toolbar .trix-input--dialog.validate:invalid {
|
trix-toolbar .trix-input--dialog.validate:invalid {
|
||||||
box-shadow: #F00 0px 0px 1.5px 1px;
|
box-shadow: #f00 0px 0px 1.5px 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
trix-toolbar .trix-button--dialog {
|
trix-toolbar .trix-button--dialog {
|
||||||
|
|
@ -317,7 +319,7 @@ trix-editor .attachment__progress {
|
||||||
transition: opacity 200ms ease-in;
|
transition: opacity 200ms ease-in;
|
||||||
}
|
}
|
||||||
|
|
||||||
trix-editor .attachment__progress[value="100"] {
|
trix-editor .attachment__progress[value='100'] {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -399,7 +401,7 @@ trix-editor .trix-button--remove::before {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
content: "";
|
content: '';
|
||||||
background-image: url(data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.4L17.6%205%2012%2010.6%206.4%205%205%206.4l5.6%205.6L5%2017.6%206.4%2019l5.6-5.6%205.6%205.6%201.4-1.4-5.6-5.6z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E);
|
background-image: url(data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.4L17.6%205%2012%2010.6%206.4%205%205%206.4l5.6%205.6L5%2017.6%206.4%2019l5.6-5.6%205.6%205.6%201.4-1.4-5.6-5.6z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E);
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
@ -467,8 +469,8 @@ trix-editor .attachment__metadata .attachment__size {
|
||||||
padding-left: 0.6em;
|
padding-left: 0.6em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trix-content [dir=rtl] blockquote,
|
.trix-content [dir='rtl'] blockquote,
|
||||||
.trix-content blockquote[dir=rtl] {
|
.trix-content blockquote[dir='rtl'] {
|
||||||
border-width: 0;
|
border-width: 0;
|
||||||
border-right-width: 0.3em;
|
border-right-width: 0.3em;
|
||||||
margin-right: 0.3em;
|
margin-right: 0.3em;
|
||||||
|
|
@ -479,7 +481,7 @@ trix-editor .attachment__metadata .attachment__size {
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trix-content [dir=rtl] li {
|
.trix-content [dir='rtl'] li {
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -520,7 +522,7 @@ trix-editor .attachment__metadata .attachment__size {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.trix-content .attachment__caption .attachment__name+.attachment__size::before {
|
.trix-content .attachment__caption .attachment__name + .attachment__size::before {
|
||||||
content: ' · ';
|
content: ' · ';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,7 +643,6 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#toolbar {
|
#toolbar {
|
||||||
box-shadow: 0px 8px 6px #111111aa;
|
box-shadow: 0px 8px 6px #111111aa;
|
||||||
|
|
|
||||||
|
|
@ -175,4 +175,3 @@ export default {
|
||||||
mounted() {}
|
mounted() {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,4 +132,3 @@ export default {
|
||||||
mounted() {}
|
mounted() {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,6 @@ export default {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.dir-item.dir-selected {
|
.dir-item.dir-selected {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
|
|
||||||
|
|
@ -133,4 +133,3 @@ export default {
|
||||||
mounted() {}
|
mounted() {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,4 +121,3 @@ export default {
|
||||||
background-color: #2f2f2f;
|
background-color: #2f2f2f;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ export default {
|
||||||
let txtWidth = ctx.measureText(text).width
|
let txtWidth = ctx.measureText(text).width
|
||||||
while (txtWidth > maxWidth) {
|
while (txtWidth > maxWidth) {
|
||||||
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
||||||
if (text.endsWith('...')) text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
if (text.endsWith('...'))
|
||||||
|
text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
||||||
else text = text.slice(0, -3) // First check remove last 3 chars
|
else text = text.slice(0, -3) // First check remove last 3 chars
|
||||||
text += '...'
|
text += '...'
|
||||||
txtWidth = ctx.measureText(text).width
|
txtWidth = ctx.measureText(text).width
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,8 @@ export default {
|
||||||
let txtWidth = ctx.measureText(text).width
|
let txtWidth = ctx.measureText(text).width
|
||||||
while (txtWidth > maxWidth) {
|
while (txtWidth > maxWidth) {
|
||||||
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
||||||
if (text.endsWith('...')) text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
if (text.endsWith('...'))
|
||||||
|
text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
||||||
else text = text.slice(0, -3) // First check remove last 3 chars
|
else text = text.slice(0, -3) // First check remove last 3 chars
|
||||||
text += '...'
|
text += '...'
|
||||||
txtWidth = ctx.measureText(text).width
|
txtWidth = ctx.measureText(text).width
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ export default {
|
||||||
let txtWidth = ctx.measureText(text).width
|
let txtWidth = ctx.measureText(text).width
|
||||||
while (txtWidth > maxWidth) {
|
while (txtWidth > maxWidth) {
|
||||||
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
console.warn(`Text "${text}" is greater than max width ${maxWidth} (width:${txtWidth})`)
|
||||||
if (text.endsWith('...')) text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
if (text.endsWith('...'))
|
||||||
|
text = text.slice(0, -4) // Repeated checks remove 1 char at a time
|
||||||
else text = text.slice(0, -3) // First check remove last 3 chars
|
else text = text.slice(0, -3) // First check remove last 3 chars
|
||||||
text += '...'
|
text += '...'
|
||||||
txtWidth = ctx.measureText(text).width
|
txtWidth = ctx.measureText(text).width
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,9 @@ export default {
|
||||||
background-color: #272727;
|
background-color: #272727;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
color: transparent;
|
color: transparent;
|
||||||
transition: color, background-color 0.5s ease;
|
transition:
|
||||||
|
color,
|
||||||
|
background-color 0.5s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-provider-api-key:hover {
|
.custom-provider-api-key:hover {
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ export default {
|
||||||
|
|
||||||
var firstBookPath = Path.dirname(firstBookFile.filepath)
|
var firstBookPath = Path.dirname(firstBookFile.filepath)
|
||||||
|
|
||||||
var dirs = firstBookPath.split('/').filter(d => !!d && d !== '.')
|
var dirs = firstBookPath.split('/').filter((d) => !!d && d !== '.')
|
||||||
if (dirs.length) {
|
if (dirs.length) {
|
||||||
audiobook.title = dirs.pop()
|
audiobook.title = dirs.pop()
|
||||||
if (dirs.length > 1) {
|
if (dirs.length > 1) {
|
||||||
|
|
@ -189,7 +189,7 @@ export default {
|
||||||
var firstAudioFile = podcast.itemFiles[0]
|
var firstAudioFile = podcast.itemFiles[0]
|
||||||
if (!firstAudioFile.filepath) return podcast // No path
|
if (!firstAudioFile.filepath) return podcast // No path
|
||||||
var firstPath = Path.dirname(firstAudioFile.filepath)
|
var firstPath = Path.dirname(firstAudioFile.filepath)
|
||||||
var dirs = firstPath.split('/').filter(d => !!d && d !== '.')
|
var dirs = firstPath.split('/').filter((d) => !!d && d !== '.')
|
||||||
if (dirs.length) {
|
if (dirs.length) {
|
||||||
podcast.title = dirs.length > 1 ? dirs[1] : dirs[0]
|
podcast.title = dirs.length > 1 ? dirs[1] : dirs[0]
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -212,13 +212,15 @@ export default {
|
||||||
}
|
}
|
||||||
var ignoredFiles = itemData.ignoredFiles
|
var ignoredFiles = itemData.ignoredFiles
|
||||||
var index = 1
|
var index = 1
|
||||||
var items = itemData.items.filter((ab) => {
|
var items = itemData.items
|
||||||
if (!ab.itemFiles.length) {
|
.filter((ab) => {
|
||||||
if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles)
|
if (!ab.itemFiles.length) {
|
||||||
if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles)
|
if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles)
|
||||||
}
|
if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles)
|
||||||
return ab.itemFiles.length
|
}
|
||||||
}).map(ab => this.cleanItem(ab, mediaType, index++))
|
return ab.itemFiles.length
|
||||||
|
})
|
||||||
|
.map((ab) => this.cleanItem(ab, mediaType, index++))
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
ignoredFiles
|
ignoredFiles
|
||||||
|
|
@ -259,7 +261,7 @@ export default {
|
||||||
|
|
||||||
otherFiles.forEach((file) => {
|
otherFiles.forEach((file) => {
|
||||||
var dir = Path.dirname(file.filepath)
|
var dir = Path.dirname(file.filepath)
|
||||||
var findItem = Object.values(itemMap).find(b => dir.startsWith(b.path))
|
var findItem = Object.values(itemMap).find((b) => dir.startsWith(b.path))
|
||||||
if (findItem) {
|
if (findItem) {
|
||||||
findItem.otherFiles.push(file)
|
findItem.otherFiles.push(file)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -270,18 +272,18 @@ export default {
|
||||||
var items = []
|
var items = []
|
||||||
var index = 1
|
var index = 1
|
||||||
// If book media type and all files are audio files then treat each one as an audiobook
|
// If book media type and all files are audio files then treat each one as an audiobook
|
||||||
if (itemMap[''] && !otherFiles.length && mediaType === 'book' && !itemMap[''].itemFiles.some(f => f.filetype !== 'audio')) {
|
if (itemMap[''] && !otherFiles.length && mediaType === 'book' && !itemMap[''].itemFiles.some((f) => f.filetype !== 'audio')) {
|
||||||
items = itemMap[''].itemFiles.map((audioFile) => {
|
items = itemMap[''].itemFiles.map((audioFile) => {
|
||||||
return this.cleanItem({ itemFiles: [audioFile], otherFiles: [], ignoredFiles: [] }, mediaType, index++)
|
return this.cleanItem({ itemFiles: [audioFile], otherFiles: [], ignoredFiles: [] }, mediaType, index++)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
items = Object.values(itemMap).map(i => this.cleanItem(i, mediaType, index++))
|
items = Object.values(itemMap).map((i) => this.cleanItem(i, mediaType, index++))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
ignoredFiles: ignoredFiles
|
ignoredFiles: ignoredFiles
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { buildCastLoadRequest, castLoadMedia } from "./castUtils"
|
import { buildCastLoadRequest, castLoadMedia } from './castUtils'
|
||||||
import EventEmitter from 'events'
|
import EventEmitter from 'events'
|
||||||
|
|
||||||
export default class CastPlayer extends EventEmitter {
|
export default class CastPlayer extends EventEmitter {
|
||||||
|
|
@ -37,8 +37,7 @@ export default class CastPlayer extends EventEmitter {
|
||||||
initialize() {
|
initialize() {
|
||||||
this.player = this.ctx.$root.castPlayer
|
this.player = this.ctx.$root.castPlayer
|
||||||
this.playerController = this.ctx.$root.castPlayerController
|
this.playerController = this.ctx.$root.castPlayerController
|
||||||
this.playerController.addEventListener(
|
this.playerController.addEventListener(cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, this.evtMediaInfoChanged.bind(this))
|
||||||
cast.framework.RemotePlayerEventType.MEDIA_INFO_CHANGED, this.evtMediaInfoChanged.bind(this))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
evtMediaInfoChanged() {
|
evtMediaInfoChanged() {
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
timeoutRetry: {
|
timeoutRetry: {
|
||||||
maxNumRetry: 4,
|
maxNumRetry: 4,
|
||||||
retryDelayMs: 0,
|
retryDelayMs: 0,
|
||||||
maxRetryDelayMs: 0,
|
maxRetryDelayMs: 0
|
||||||
},
|
},
|
||||||
errorRetry: {
|
errorRetry: {
|
||||||
maxNumRetry: 8,
|
maxNumRetry: 8,
|
||||||
|
|
@ -160,7 +160,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
}
|
}
|
||||||
return retry
|
return retry
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +194,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
|
|
||||||
setDirectPlay() {
|
setDirectPlay() {
|
||||||
// Set initial track and track time offset
|
// Set initial track and track time offset
|
||||||
var trackIndex = this.audioTracks.findIndex(t => this.startTime >= t.startOffset && this.startTime < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => this.startTime >= t.startOffset && this.startTime < t.startOffset + t.duration)
|
||||||
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
this.currentTrackIndex = trackIndex >= 0 ? trackIndex : 0
|
||||||
|
|
||||||
this.loadCurrentTrack()
|
this.loadCurrentTrack()
|
||||||
|
|
@ -270,7 +270,7 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
// Seeking Direct play
|
// Seeking Direct play
|
||||||
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
if (time < this.currentTrack.startOffset || time > this.currentTrack.startOffset + this.currentTrack.duration) {
|
||||||
// Change Track
|
// Change Track
|
||||||
var trackIndex = this.audioTracks.findIndex(t => time >= t.startOffset && time < (t.startOffset + t.duration))
|
var trackIndex = this.audioTracks.findIndex((t) => time >= t.startOffset && time < t.startOffset + t.duration)
|
||||||
if (trackIndex >= 0) {
|
if (trackIndex >= 0) {
|
||||||
this.startTime = time
|
this.startTime = time
|
||||||
this.currentTrackIndex = trackIndex
|
this.currentTrackIndex = trackIndex
|
||||||
|
|
@ -293,7 +293,6 @@ export default class LocalAudioPlayer extends EventEmitter {
|
||||||
this.player.volume = volume
|
this.player.volume = volume
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
isValidDuration(duration) {
|
isValidDuration(duration) {
|
||||||
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
if (duration && !isNaN(duration) && duration !== Number.POSITIVE_INFINITY && duration !== Number.NEGATIVE_INFINITY) {
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,21 @@
|
||||||
export default (ctx) => {
|
export default (ctx) => {
|
||||||
var sendInit = async (castContext) => {
|
var sendInit = async (castContext) => {
|
||||||
// Fetch background covers for chromecast (temp)
|
// Fetch background covers for chromecast (temp)
|
||||||
var covers = await ctx.$axios.$get(`/api/libraries/${ctx.$store.state.libraries.currentLibraryId}/items?limit=40&minified=1`).then((data) => {
|
var covers = await ctx.$axios
|
||||||
return data.results.filter((b) => b.media.coverPath).map((libraryItem) => {
|
.$get(`/api/libraries/${ctx.$store.state.libraries.currentLibraryId}/items?limit=40&minified=1`)
|
||||||
var coverUrl = ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem)
|
.then((data) => {
|
||||||
if (process.env.NODE_ENV === 'development') return coverUrl
|
return data.results
|
||||||
return `${window.location.origin}${coverUrl}`
|
.filter((b) => b.media.coverPath)
|
||||||
|
.map((libraryItem) => {
|
||||||
|
var coverUrl = ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem)
|
||||||
|
if (process.env.NODE_ENV === 'development') return coverUrl
|
||||||
|
return `${window.location.origin}${coverUrl}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('failed to fetch books', error)
|
||||||
|
return null
|
||||||
})
|
})
|
||||||
}).catch((error) => {
|
|
||||||
console.error('failed to fetch books', error)
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
|
|
||||||
// Custom message to receiver
|
// Custom message to receiver
|
||||||
var castSession = castContext.getCurrentSession()
|
var castSession = castContext.getCurrentSession()
|
||||||
|
|
@ -24,40 +29,38 @@ export default (ctx) => {
|
||||||
castContext.setOptions({
|
castContext.setOptions({
|
||||||
receiverApplicationId: process.env.chromecastReceiver,
|
receiverApplicationId: process.env.chromecastReceiver,
|
||||||
autoJoinPolicy: chrome.cast ? chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED : null
|
autoJoinPolicy: chrome.cast ? chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED : null
|
||||||
});
|
})
|
||||||
|
|
||||||
castContext.addEventListener(
|
castContext.addEventListener(cast.framework.CastContextEventType.SESSION_STATE_CHANGED, (event) => {
|
||||||
cast.framework.CastContextEventType.SESSION_STATE_CHANGED,
|
console.log('Session state changed event', event)
|
||||||
(event) => {
|
|
||||||
console.log('Session state changed event', event)
|
|
||||||
|
|
||||||
switch (event.sessionState) {
|
switch (event.sessionState) {
|
||||||
case cast.framework.SessionState.SESSION_STARTED:
|
case cast.framework.SessionState.SESSION_STARTED:
|
||||||
console.log('[chromecast] CAST SESSION STARTED')
|
console.log('[chromecast] CAST SESSION STARTED')
|
||||||
|
|
||||||
ctx.$store.commit('globals/setCasting', true)
|
ctx.$store.commit('globals/setCasting', true)
|
||||||
sendInit(castContext)
|
sendInit(castContext)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ctx.$eventBus.$emit('cast-session-active', true)
|
ctx.$eventBus.$emit('cast-session-active', true)
|
||||||
}, 500)
|
}, 500)
|
||||||
|
|
||||||
break;
|
break
|
||||||
case cast.framework.SessionState.SESSION_RESUMED:
|
case cast.framework.SessionState.SESSION_RESUMED:
|
||||||
console.log('[chromecast] CAST SESSION RESUMED')
|
console.log('[chromecast] CAST SESSION RESUMED')
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ctx.$eventBus.$emit('cast-session-active', true)
|
ctx.$eventBus.$emit('cast-session-active', true)
|
||||||
}, 500)
|
}, 500)
|
||||||
break;
|
break
|
||||||
case cast.framework.SessionState.SESSION_ENDED:
|
case cast.framework.SessionState.SESSION_ENDED:
|
||||||
console.log('[chromecast] CAST SESSION DISCONNECTED')
|
console.log('[chromecast] CAST SESSION DISCONNECTED')
|
||||||
|
|
||||||
ctx.$store.commit('globals/setCasting', false)
|
ctx.$store.commit('globals/setCasting', false)
|
||||||
ctx.$eventBus.$emit('cast-session-active', false)
|
ctx.$eventBus.$emit('cast-session-active', false)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.$store.commit('globals/setChromecastInitialized', true)
|
ctx.$store.commit('globals/setChromecastInitialized', true)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,7 @@ const Hotkeys = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { Constants }
|
||||||
Constants
|
|
||||||
}
|
|
||||||
export default ({ app }, inject) => {
|
export default ({ app }, inject) => {
|
||||||
inject('constants', Constants)
|
inject('constants', Constants)
|
||||||
inject('keynames', KeyNames)
|
inject('keynames', KeyNames)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import Vue from "vue"
|
import Vue from 'vue'
|
||||||
import Toast from "vue-toastification"
|
import Toast from 'vue-toastification'
|
||||||
import "vue-toastification/dist/index.css"
|
import 'vue-toastification/dist/index.css'
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
hideProgressBar: true,
|
hideProgressBar: true,
|
||||||
|
|
|
||||||
|
|
@ -72,11 +72,11 @@ export const state = () => ({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
checkBookProviderExists: state => (providerValue) => {
|
checkBookProviderExists: (state) => (providerValue) => {
|
||||||
return state.providers.some(p => p.value === providerValue)
|
return state.providers.some((p) => p.value === providerValue)
|
||||||
},
|
},
|
||||||
checkPodcastProviderExists: state => (providerValue) => {
|
checkPodcastProviderExists: (state) => (providerValue) => {
|
||||||
return state.podcastProviders.some(p => p.value === providerValue)
|
return state.podcastProviders.some((p) => p.value === providerValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,13 +85,13 @@ export const actions = {}
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
addCustomMetadataProvider(state, provider) {
|
addCustomMetadataProvider(state, provider) {
|
||||||
if (provider.mediaType === 'book') {
|
if (provider.mediaType === 'book') {
|
||||||
if (state.providers.some(p => p.value === provider.slug)) return
|
if (state.providers.some((p) => p.value === provider.slug)) return
|
||||||
state.providers.push({
|
state.providers.push({
|
||||||
text: provider.name,
|
text: provider.name,
|
||||||
value: provider.slug
|
value: provider.slug
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (state.podcastProviders.some(p => p.value === provider.slug)) return
|
if (state.podcastProviders.some((p) => p.value === provider.slug)) return
|
||||||
state.podcastProviders.push({
|
state.podcastProviders.push({
|
||||||
text: provider.name,
|
text: provider.name,
|
||||||
value: provider.slug
|
value: provider.slug
|
||||||
|
|
@ -100,9 +100,9 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
removeCustomMetadataProvider(state, provider) {
|
removeCustomMetadataProvider(state, provider) {
|
||||||
if (provider.mediaType === 'book') {
|
if (provider.mediaType === 'book') {
|
||||||
state.providers = state.providers.filter(p => p.value !== provider.slug)
|
state.providers = state.providers.filter((p) => p.value !== provider.slug)
|
||||||
} else {
|
} else {
|
||||||
state.podcastProviders = state.podcastProviders.filter(p => p.value !== provider.slug)
|
state.podcastProviders = state.podcastProviders.filter((p) => p.value !== provider.slug)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setCustomMetadataProviders(state, providers) {
|
setCustomMetadataProviders(state, providers) {
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,21 @@
|
||||||
|
|
||||||
export const state = () => ({
|
export const state = () => ({
|
||||||
usersOnline: []
|
usersOnline: []
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
getIsUserOnline: state => id => {
|
getIsUserOnline: (state) => (id) => {
|
||||||
return state.usersOnline.find(u => u.id === id)
|
return state.usersOnline.find((u) => u.id === id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export const mutations = {
|
export const mutations = {
|
||||||
setUsersOnline(state, usersOnline) {
|
setUsersOnline(state, usersOnline) {
|
||||||
state.usersOnline = usersOnline
|
state.usersOnline = usersOnline
|
||||||
},
|
},
|
||||||
updateUserOnline(state, user) {
|
updateUserOnline(state, user) {
|
||||||
var index = state.usersOnline.findIndex(u => u.id === user.id)
|
var index = state.usersOnline.findIndex((u) => u.id === user.id)
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
state.usersOnline.splice(index, 1, user)
|
state.usersOnline.splice(index, 1, user)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -26,6 +23,6 @@ export const mutations = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeUserOnline(state, user) {
|
removeUserOnline(state, user) {
|
||||||
state.usersOnline = state.usersOnline.filter(u => u.id !== user.id)
|
state.usersOnline = state.usersOnline.filter((u) => u.id !== user.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue