Update users table info #94, Reorder libraries in config #95, Use dropdown for library menu #96, update mobi reader

This commit is contained in:
advplyr 2021-10-12 20:07:42 -05:00
parent 9715c53332
commit cd6e99b4c3
30 changed files with 1361 additions and 557 deletions

View file

@ -0,0 +1,506 @@
/*
Calibres stylesheet
*/
export default `
@charset "UTF-8";
/*
Calibre styles
*/
.arabic {
display: block;
list-style-type: decimal;
margin-bottom: 1em;
margin-right: 0;
margin-top: 1em;
text-align: justify
}
.attribution {
display: block;
font-size: 1em;
line-height: 1.2;
text-align: left;
margin: 0.3em 0
}
.big {
font-size: 1.375em;
line-height: 1.2
}
.big1 {
font-size: 1em
}
.block {
display: block;
text-align: justify;
margin: 1em 1em 2em
}
.block1 {
display: block;
text-align: justify;
margin: 1em 4em
}
.block2 {
display: block;
text-align: justify;
margin: 1em 1em 1em 2em
}
.bullet {
display: block;
list-style-type: disc;
margin-bottom: 1em;
margin-right: 0;
margin-top: 1em;
text-align: disc
}
.calibre {
background-color: #000007;
display: block;
font-family: Charis, "Times New Roman", Verdana, Arial;
font-size: 1.125em;
line-height: 1.2;
padding-left: 0;
padding-right: 0;
text-align: center;
margin: 0 5pt
}
.calibre1 {
display: block
}
.calibre2 {
height: auto;
width: auto
}
.calibre3:not(strong) {
display: block;
font-family: Charis, "Times New Roman", Verdana, Arial;
font-size: 1.125em;
line-height: 1.2;
padding-left: 0;
padding-right: 0;
margin: 0 5pt
}
.calibre4 {
font-weight: bold
}
.calibre5 {
font-style: italic
}
.calibre6 {
background-color: #FFF;
display: block;
font-family: Charis, "Times New Roman", Verdana, Arial;
font-size: 1.125em;
line-height: 1.2;
padding-left: 0;
padding-right: 0;
text-align: center;
margin: 0 5pt
}
.calibre7 {
display: list-item
}
.calibre8 {
font-size: 1em;
line-height: 1.2;
vertical-align: super
}
.calibre9 {
border-collapse: separate;
border-spacing: 2px;
display: table;
margin-bottom: 0;
margin-top: 0;
text-indent: 0
}
.calibre10 {
display: table-row;
vertical-align: middle
}
.calibre11 {
display: table-cell;
text-align: right;
vertical-align: inherit;
padding: 1px
}
.calibre12 {
display: table-cell;
text-align: left;
vertical-align: inherit;
padding: 1px
}
.calibre13 {
height: 1em;
width: auto
}
.calibre14 {
font-size: 0.88889em;
line-height: 1.2;
vertical-align: super
}
.calibre15 {
font-size: 1em;
line-height: 1.2;
vertical-align: sub
}
.calibre16 {
display: block;
list-style-type: decimal;
margin-bottom: 1em;
margin-right: 0;
margin-top: 1em
}
.calibre17 {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 1.2;
margin: 0.83em 0
}
.center {
display: block;
text-align: center;
margin: 1em 0
}
.center1 {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 1.2;
text-align: center;
margin: -2em 0 3em
}
.center2 {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 1.2;
text-align: center;
margin: 2em 0 1em
}
.center3 {
display: block;
text-align: center;
margin: -1em 0 1em
}
.center4 {
display: block;
text-align: center;
text-indent: 3%;
margin: 1em 0
}
.chapter {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 2em;
text-align: center;
margin: 2em 0 1em
}
.chapter1 {
display: block;
font-size: 0.88889em;
line-height: 1.2;
margin-left: 0.5em;
margin-right: 0.5em;
margin-top: 2em
}
.chapter2 {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 2em;
text-align: center;
margin: 2em 0 3em
}
.copyright {
display: block;
font-size: 0.88889em;
line-height: 1.2;
margin-top: 4em;
text-align: center
}
.dedication {
display: block;
font-size: 0.88889em;
line-height: 1.2;
margin-top: 4em
}
.dropcaps {
float: left;
font-size: 3.4375rem;
line-height: 50px;
margin-right: 0.09em;
margin-top: -0.05em;
padding-top: 1px
}
.dropcaps1 {
float: left;
font-size: 3.4375rem;
line-height: 50px;
margin-right: 0.09em;
margin-top: 0.15em;
padding-top: 1px
}
.extract {
display: block;
text-align: justify;
margin: 2em 0 0.3em
}
.extract1 {
display: block;
text-align: justify;
text-indent: 3%;
margin: 2em 0 0.3em
}
.extract2 {
display: block;
text-align: justify;
margin: 1em 0 0.3em
}
.footnote {
border-bottom-style: solid;
border-bottom-width: 0;
border-left-style: solid;
border-left-width: 0;
border-right-style: solid;
border-right-width: 0;
border-top-style: solid;
border-top-width: 1px;
display: block;
font-size: 1em;
line-height: 1.2;
margin-top: 2 em
}
.footnote1 {
display: block;
text-align: justify;
margin: 0.3em 0 0.3em 2
}
.footnote2 {
border-bottom-style: solid;
border-bottom-width: 0;
border-left-style: solid;
border-left-width: 0;
border-right-style: solid;
border-right-width: 0;
border-top-style: solid;
border-top-width: 1px;
display: block;
font-size: 0.88889em;
line-height: 1.2;
margin-top: 2 em
}
.hanging {
display: block;
font-size: 0.88889em;
line-height: 1.2;
text-align: left;
text-indent: -1em;
margin: 0.5em 0 0.3em 1em
}
.hanging1 {
display: block;
font-size: 0.88889em;
line-height: 1.2;
text-align: left;
text-indent: -1em;
margin: 0.5em 0 0.3em 1.5em
}
.hanging2 {
display: block;
font-size: 1em;
line-height: 1.2;
text-indent: -1em;
margin: 0.5em 0 0.3em 1em
}
.hanging3 {
display: block;
font-size: 1em;
line-height: 1.2;
text-align: left;
text-indent: 1em;
margin: 0.1em 0 0.3em 1em
}
.hanging4 {
display: block;
font-size: 1em;
line-height: 1.2;
text-align: left;
text-indent: 0.1em;
margin: 0.1em 0 0.3em 1em
}
a.hlink {
text-decoration: none
}
.indent {
display: block;
text-align: justify;
text-indent: 1em;
margin: 0.3em 0
}
.line {
border-top: currentColor solid 1px;
border-bottom: currentColor solid 1px
}
.loweralpha {
display: block;
list-style-type: lower-alpha;
margin-bottom: 1em;
margin-right: 0;
margin-top: 1em;
text-align: justify
}
.none {
display: block;
list-style-type: none;
margin-bottom: 1em;
margin-right: 0;
margin-top: 1em;
text-align: justify
}
.none1 {
display: block;
list-style-type: none;
margin-bottom: 0;
margin-right: 0;
margin-top: 0;
text-align: justify
}
.nonindent {
display: block;
text-align: justify;
margin: 0.3em 0
}
.nonindent1 {
display: block;
font-size: 1.125em;
line-height: 1.2;
text-indent: -1em;
margin: 0.5em 0 0.3em 0.1em
}
.nonindent2 {
display: block;
font-size: 1.125em;
line-height: 1.2;
text-indent: -1em;
margin: 0.5em 0 0.3em -0.5em
}
.nonindent3 {
display: block;
text-align: justify;
text-indent: 3%;
margin: 0.3em 0
}
.part {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 2em;
text-align: center;
margin: 4em 0 1em
}
.preface {
display: block;
font-size: 0.88889em;
line-height: 1.2;
margin-left: 2em;
margin-right: 2em;
text-align: justify
}
.pubhlink {
color: green;
text-decoration: none
}
.right {
display: block;
text-align: right;
margin: 0.3em 0
}
.section {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 1.2;
text-align: center;
margin: 2em 0 0.5em
}
.section1 {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 1.2;
text-align: left;
margin: 2em 0 0.3em
}
.section2 {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 1.2;
text-align: left;
margin: 2em 0 0.3em 1em
}
.small {
font-size: 0.66667em
}
.small1 {
font-size: 0.75em
}
.subchapter {
display: block;
font-size: 1.125em;
font-weight: bold;
line-height: 1.2;
margin: 1em 0
}
.textbox {
background-color: #E4E4E4;
display: block;
line-height: 1.5em;
margin-bottom: 2em;
margin-top: 2em;
text-align: justify;
border-top: currentColor double 2px;
border-bottom: currentColor double 2px
}
.textbox1 {
display: block;
text-align: justify;
margin: 0.3em 0.5em 0.3em 0.8em
}
.textbox2 {
display: block;
text-align: justify;
text-indent: 1em;
margin: 0.3em 0.5em
}
.textbox3 {
display: block;
text-align: justify;
text-indent: 3%;
margin: 0.3em 0.5em 0.3em 0.8em
}
.titlepage {
display: block;
margin-left: -0.4em;
margin-top: 1.2em
}
.toc {
display: block;
font-size: 1em;
line-height: 1.2;
text-align: center
}
.toc1 {
display: block;
font-size: 1em;
font-weight: bold;
line-height: 1.2;
text-align: center;
margin: 0.67em 0 3em
}
.underline {
text-decoration: underline
}
`

View file

@ -0,0 +1,248 @@
/*
This is borrowed from koodo-reader https://github.com/troyeguo/koodo-reader/tree/master/src
*/
export const isTitle = (
line,
isContainDI = false,
isContainChapter = false,
isContainCHAPTER = false
) => {
return (
line.length < 30 &&
line.indexOf("[") === -1 &&
line.indexOf("(") === -1 &&
(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("後序") ||
/(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$/.test(
line
) ||
(line.startsWith("第") && startWithDI(line)) ||
(line.startsWith("卷") && startWithJUAN(line)) ||
startWithRomanNum(line) ||
(!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("第")))) ||
(!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) => {
let keywords = [
"章",
"节",
"回",
"節",
"卷",
"部",
"輯",
"辑",
"話",
"集",
"话",
"篇",
];
let flag = false;
for (let i = 0; i < keywords.length; i++) {
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]
) {
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;
}
}
return flag;
};
const startWithJUAN = (line) => {
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, 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) => {
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.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) => {
if (
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
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;
return false;
};
const startWithNumAndColon = (line) => {
if (
/^[\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d\u5341\u767e\u5343\u4e07\u842c]+$/.test(
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;
return false;
};
const startWithNumAndPause = (line) => {
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;
return false;
};
class HtmlParser {
bookDoc;
contentList;
contentTitleList;
constructor(bookDoc) {
this.bookDoc = bookDoc;
this.contentList = [];
this.contentTitleList = [];
this.getContent(bookDoc);
}
getContent(bookDoc) {
this.contentList = Array.from(
bookDoc.querySelectorAll("h1,h2,h3,h4,h5,b,font")
).filter((item, index) => {
return isTitle(item.innerText.trim());
});
for (let i = 0; i < this.contentList.length; i++) {
let random = Math.floor(Math.random() * 900000) + 100000;
this.contentTitleList.push({
label: this.contentList[i].innerText,
id: "title" + random,
href: "#title" + random,
subitems: [],
});
}
for (let i = 0; i < this.contentList.length; i++) {
this.contentList[i].id = this.contentTitleList[i].id;
}
}
getAnchoredDoc() {
return this.bookDoc;
}
getContentList() {
return this.contentTitleList.filter((item, index) => {
if (index > 0) {
return item.label !== this.contentTitleList[index - 1].label;
} else {
return true;
}
});
}
}
export default HtmlParser;

View file

@ -0,0 +1,450 @@
/*
This is borrowed from koodo-reader https://github.com/troyeguo/koodo-reader/tree/master/src
*/
function ab2str(buf) {
if (buf instanceof ArrayBuffer) {
buf = new Uint8Array(buf);
}
return new TextDecoder("utf-8").decode(buf);
}
var domParser = new DOMParser();
class Buffer {
capacity;
fragment_list;
imageArray;
cur_fragment;
constructor(capacity) {
this.capacity = capacity;
this.fragment_list = [];
this.imageArray = [];
this.cur_fragment = new Fragment(capacity);
this.fragment_list.push(this.cur_fragment);
}
write(byte) {
var result = this.cur_fragment.write(byte);
if (!result) {
this.cur_fragment = new Fragment(this.capacity);
this.fragment_list.push(this.cur_fragment);
this.cur_fragment.write(byte);
}
}
get(idx) {
var fi = 0;
while (fi < this.fragment_list.length) {
var frag = this.fragment_list[fi];
if (idx < frag.size) {
return frag.get(idx);
}
idx -= frag.size;
fi += 1;
}
return null;
}
size() {
var s = 0;
for (var i = 0; i < this.fragment_list.length; i++) {
s += this.fragment_list[i].size;
}
return s;
}
shrink() {
var total_buffer = new Uint8Array(this.size());
var offset = 0;
for (var i = 0; i < this.fragment_list.length; i++) {
var frag = this.fragment_list[i];
if (frag.full()) {
total_buffer.set(frag.buffer, offset);
} else {
total_buffer.set(frag.buffer.slice(0, frag.size), offset);
}
offset += frag.size;
}
return total_buffer;
}
}
var copagesne_uint8array = function (buffers) {
var total_size = 0;
for (let i = 0; i < buffers.length; i++) {
var buffer = buffers[i];
total_size += buffer.length;
}
var total_buffer = new Uint8Array(total_size);
var offset = 0;
for (let i = 0; i < buffers.length; i++) {
buffer = buffers[i];
total_buffer.set(buffer, offset);
offset += buffer.length;
}
return total_buffer;
};
class Fragment {
buffer;
capacity;
size;
constructor(capacity) {
this.buffer = new Uint8Array(capacity);
this.capacity = capacity;
this.size = 0;
}
write(byte) {
if (this.size >= this.capacity) {
return false;
}
this.buffer[this.size] = byte;
this.size += 1;
return true;
}
full() {
return this.size === this.capacity;
}
get(idx) {
return this.buffer[idx];
}
}
var uncompression_lz77 = function (data) {
var length = data.length;
var offset = 0; // Current offset into data
var buffer = new Buffer(data.length);
while (offset < length) {
var char = data[offset];
offset += 1;
if (char === 0) {
buffer.write(char);
} else if (char <= 8) {
for (var i = offset; i < offset + char; i++) {
buffer.write(data[i]);
}
offset += char;
} else if (char <= 0x7f) {
buffer.write(char);
} else if (char <= 0xbf) {
var next = data[offset];
offset += 1;
var distance = (((char << 8) | next) >> 3) & 0x7ff;
var lz_length = (next & 0x7) + 3;
var buffer_size = buffer.size();
for (let i = 0; i < lz_length; i++) {
buffer.write(buffer.get(buffer_size - distance));
buffer_size += 1;
}
} else {
buffer.write(32);
buffer.write(char ^ 0x80);
}
}
return buffer;
};
class MobiFile {
view;
buffer;
offset;
header;
palm_header;
mobi_header;
reclist;
constructor(data) {
this.view = new DataView(data);
this.buffer = this.view.buffer;
this.offset = 0;
this.header = null;
}
parse() { }
getUint8() {
var v = this.view.getUint8(this.offset);
this.offset += 1;
return v;
}
getUint16() {
var v = this.view.getUint16(this.offset);
this.offset += 2;
return v;
}
getUint32() {
var v = this.view.getUint32(this.offset);
this.offset += 4;
return v;
}
getStr(size) {
var v = ab2str(this.buffer.slice(this.offset, this.offset + size));
this.offset += size;
return v;
}
skip(size) {
this.offset += size;
}
setoffset(_of) {
this.offset = _of;
}
get_record_extrasize(data, flags) {
var pos = data.length - 1;
var extra = 0;
for (var i = 15; i > 0; i--) {
if (flags & (1 << i)) {
var res = this.buffer_get_varlen(data, pos);
var size = res[0];
var l = res[1];
pos = res[2];
pos -= size - l;
extra += size;
}
}
if (flags & 1) {
var a = data[pos];
extra += (a & 0x3) + 1;
}
return extra;
}
// data should be uint8array
buffer_get_varlen(data, pos) {
var l = 0;
var size = 0;
var byte_count = 0;
var mask = 0x7f;
var stop_flag = 0x80;
var shift = 0;
for (var i = 0; ; i++) {
var byte = data[pos];
size |= (byte & mask) << shift;
shift += 7;
l += 1;
byte_count += 1;
pos -= 1;
var to_stop = byte & stop_flag;
if (byte_count >= 4 || to_stop > 0) {
break;
}
}
return [size, l, pos];
}
// 读出文本内容
read_text() {
var text_end = this.palm_header.record_count;
var buffers = [];
for (var i = 1; i <= text_end; i++) {
buffers.push(this.read_text_record(i));
}
var all = copagesne_uint8array(buffers);
return ab2str(all);
}
read_text_record(i) {
var flags = this.mobi_header.extra_flags;
var begin = this.reclist[i].offset;
var end = this.reclist[i + 1].offset;
var data = new Uint8Array(this.buffer.slice(begin, end));
var ex = this.get_record_extrasize(data, flags);
data = new Uint8Array(this.buffer.slice(begin, end - ex));
if (this.palm_header.compression === 2) {
var buffer = uncompression_lz77(data);
return buffer.shrink();
} else {
return data;
}
}
// 从buffer中读出image
read_image(idx) {
var first_image_idx = this.mobi_header.first_image_idx;
var begin = this.reclist[first_image_idx + idx].offset;
var end = this.reclist[first_image_idx + idx + 1].offset;
var data = new Uint8Array(this.buffer.slice(begin, end));
return new Blob([data.buffer]);
}
load() {
this.header = this.load_pdbheader();
this.reclist = this.load_reclist();
this.load_record0();
}
load_pdbheader() {
var header = {};
header.name = this.getStr(32);
header.attr = this.getUint16();
header.version = this.getUint16();
header.ctime = this.getUint32();
header.mtime = this.getUint32();
header.btime = this.getUint32();
header.mod_num = this.getUint32();
header.appinfo_offset = this.getUint32();
header.sortinfo_offset = this.getUint32();
header.type = this.getStr(4);
header.creator = this.getStr(4);
header.uid = this.getUint32();
header.next_rec = this.getUint32();
header.record_num = this.getUint16();
return header;
}
load_reclist() {
var reclist = [];
for (var i = 0; i < this.header.record_num; i++) {
var record = {};
record.offset = this.getUint32();
// TODO(zz) change
record.attr = this.getUint32();
reclist.push(record);
}
return reclist;
}
load_record0() {
this.palm_header = this.load_record0_header();
this.mobi_header = this.load_mobi_header();
}
load_record0_header() {
var p_header = {};
var first_record = this.reclist[0];
this.setoffset(first_record.offset);
p_header.compression = this.getUint16();
this.skip(2);
p_header.text_length = this.getUint32();
p_header.record_count = this.getUint16();
p_header.record_size = this.getUint16();
p_header.encryption_type = this.getUint16();
this.skip(2);
return p_header;
}
load_mobi_header() {
var mobi_header = {};
var start_offset = this.offset;
mobi_header.identifier = this.getUint32();
mobi_header.header_length = this.getUint32();
mobi_header.mobi_type = this.getUint32();
mobi_header.text_encoding = this.getUint32();
mobi_header.uid = this.getUint32();
mobi_header.generator_version = this.getUint32();
this.skip(40);
mobi_header.first_nonbook_index = this.getUint32();
mobi_header.full_name_offset = this.getUint32();
mobi_header.full_name_length = this.getUint32();
mobi_header.language = this.getUint32();
mobi_header.input_language = this.getUint32();
mobi_header.output_language = this.getUint32();
mobi_header.min_version = this.getUint32();
mobi_header.first_image_idx = this.getUint32();
mobi_header.huff_rec_index = this.getUint32();
mobi_header.huff_rec_count = this.getUint32();
mobi_header.datp_rec_index = this.getUint32();
mobi_header.datp_rec_count = this.getUint32();
mobi_header.exth_flags = this.getUint32();
this.skip(36);
mobi_header.drm_offset = this.getUint32();
mobi_header.drm_count = this.getUint32();
mobi_header.drm_size = this.getUint32();
mobi_header.drm_flags = this.getUint32();
this.skip(8);
// TODO (zz) fdst_index
this.skip(4);
this.skip(46);
mobi_header.extra_flags = this.getUint16();
this.setoffset(start_offset + mobi_header.header_length);
return mobi_header;
}
load_exth_header() {
// TODO
return {};
}
extractContent(s) {
var span = document.createElement("span");
span.innerHTML = s;
return span.textContent || span.innerText;
}
render(isElectron = false) {
return new Promise((resolve, reject) => {
this.load();
var content = this.read_text();
var bookDoc = domParser.parseFromString(content, "text/html")
.documentElement;
let lines = Array.from(
bookDoc.querySelectorAll("p,b,font,h3,h2,h1")
);
let parseContent = [];
for (let i = 0, len = lines.length; i < len - 1; i++) {
lines[i].innerText &&
lines[i].innerText !== parseContent[parseContent.length - 1] &&
parseContent.push(lines[i].innerText);
let imgDoms = lines[i].getElementsByTagName("img");
if (imgDoms.length > 0) {
for (let i = 0; i < imgDoms.length; i++) {
parseContent.push("#image");
}
}
}
const handleImage = async () => {
var imgDoms = bookDoc.getElementsByTagName("img");
parseContent.push("~image");
for (let i = 0; i < imgDoms.length; i++) {
const src = await this.render_image(imgDoms, i);
parseContent.push(
src + " " + imgDoms[i].width + " " + imgDoms[i].height
);
}
if (imgDoms.length > 200 || !isElectron) {
resolve(bookDoc);
} else {
resolve(parseContent.join("\n \n"));
}
};
handleImage();
});
}
render_image = (imgDoms, i) => {
return new Promise((resolve, reject) => {
var imgDom = imgDoms[i];
var idx = +imgDom.getAttribute("recindex");
var blob = this.read_image(idx - 1);
var imgReader = new FileReader();
imgReader.onload = (e) => {
imgDom.src = e.target?.result;
resolve(e.target?.result);
};
imgReader.onerror = function (err) {
reject(err);
};
imgReader.readAsDataURL(blob);
});
};
}
export default MobiFile;