prettier: client

This commit is contained in:
wommy 2024-10-15 22:24:27 -04:00
parent f2102a0a23
commit 3beb8905c4
74 changed files with 520 additions and 652 deletions

View file

@ -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';
} }

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -21,8 +21,7 @@
} }
.material-symbols.fill { .material-symbols.fill {
font-variation-settings: font-variation-settings: 'FILL' 1;
'FILL' 1
} }
/* cyrillic-ext */ /* cyrillic-ext */

View file

@ -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;
} }

View file

@ -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: ' · ';
} }

View file

@ -643,7 +643,6 @@ export default {
} }
</script> </script>
<style> <style>
#toolbar { #toolbar {
box-shadow: 0px 8px 6px #111111aa; box-shadow: 0px 8px 6px #111111aa;

View file

@ -175,4 +175,3 @@ export default {
mounted() {} mounted() {}
} }
</script> </script>

View file

@ -132,4 +132,3 @@ export default {
mounted() {} mounted() {}
} }
</script> </script>

View file

@ -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);

View file

@ -133,4 +133,3 @@ export default {
mounted() {} mounted() {}
} }
</script> </script>

View file

@ -121,4 +121,3 @@ export default {
background-color: #2f2f2f; background-color: #2f2f2f;
} }
</style> </style>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 {

View file

@ -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
.filter((ab) => {
if (!ab.itemFiles.length) { if (!ab.itemFiles.length) {
if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles) if (ab.otherFiles.length) ignoredFiles = ignoredFiles.concat(ab.otherFiles)
if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles) if (ab.ignoredFiles.length) ignoredFiles = ignoredFiles.concat(ab.ignoredFiles)
} }
return ab.itemFiles.length return ab.itemFiles.length
}).map(ab => this.cleanItem(ab, mediaType, index++)) })
.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
} }
}, }
} }
} }

View file

@ -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() {

View file

@ -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) {

View file

@ -1,13 +1,18 @@
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`)
.then((data) => {
return data.results
.filter((b) => b.media.coverPath)
.map((libraryItem) => {
var coverUrl = ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem) var coverUrl = ctx.$store.getters['globals/getLibraryItemCoverSrc'](libraryItem)
if (process.env.NODE_ENV === 'development') return coverUrl if (process.env.NODE_ENV === 'development') return coverUrl
return `${window.location.origin}${coverUrl}` return `${window.location.origin}${coverUrl}`
}) })
}).catch((error) => { })
.catch((error) => {
console.error('failed to fetch books', error) console.error('failed to fetch books', error)
return null return null
}) })
@ -24,11 +29,9 @@ 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,
(event) => {
console.log('Session state changed event', event) console.log('Session state changed event', event)
switch (event.sessionState) { switch (event.sessionState) {
@ -42,20 +45,20 @@ export default (ctx) => {
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
} }
}) })

View file

@ -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)

View file

@ -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,

View file

@ -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) {

View file

@ -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)
} }
} }