@@ -439,11 +439,12 @@ class SettingsPage extends Vue {
'#000000',
'#202020',
'#ebe2c9',
+ '#cfdc99',
+ '#478355',
+ '#a6caf0',
'#909080',
'#808080',
'#c8c8c8',
- '#478355',
- '#a6caf0',
];
}
diff --git a/client/components/Reader/TextPage/DrawHelper.js b/client/components/Reader/TextPage/DrawHelper.js
index 458927b1..de702ae4 100644
--- a/client/components/Reader/TextPage/DrawHelper.js
+++ b/client/components/Reader/TextPage/DrawHelper.js
@@ -28,7 +28,7 @@ export default class DrawHelper {
let out = ``;
+ ` line-height: ${this.lineHeight}px; white-space: nowrap;">`;
let imageDrawn = new Set();
let len = lines.length;
@@ -91,13 +91,13 @@ export default class DrawHelper {
} else
text = part.text;
- if (text.trim() == '')
+ if (text && text.trim() == '')
text = `${text}`;
lineText += `${tOpen}${text}${tClose}`;
center = center || part.style.center;
- space = (part.style.space > 0 ? part.style.space : space);
+ space = (part.style.space > space ? part.style.space : space);
//избражения
//image: {local: Boolean, inline: Boolean, id: String, imageLine: Number, lineCount: Number, paraIndex: Number},
diff --git a/client/components/Reader/share/BookParser.js b/client/components/Reader/share/BookParser.js
index b4c24a9a..b5a990ee 100644
--- a/client/components/Reader/share/BookParser.js
+++ b/client/components/Reader/share/BookParser.js
@@ -45,6 +45,9 @@ export default class BookParser {
let italic = false;
let space = 0;
let inPara = false;
+ let isFirstBody = true;
+ let isFirstSection = true;
+ let isFirstTitlePara = false;
this.binary = {};
let binaryId = '';
@@ -185,7 +188,7 @@ export default class BookParser {
if (attrs.href && attrs.href.value) {
const href = attrs.href.value;
if (href[0] == '#') {//local
- if (inPara && !this.showInlineImagesInCenter)
+ if (inPara && !this.showInlineImagesInCenter && !center)
growParagraph(``, 0);
else
newParagraph(`${' '.repeat(maxImageLineCount)}`, maxImageLineCount);
@@ -199,14 +202,23 @@ export default class BookParser {
}
if (path.indexOf('/fictionbook/body') == 0) {
+ if (tag == 'body') {
+ if (!isFirstBody)
+ newParagraph(' ', 1);
+ isFirstBody = false;
+ }
+
if (tag == 'title') {
newParagraph(' ', 1);
+ isFirstTitlePara = true;
bold = true;
center = true;
}
if (tag == 'section') {
- newParagraph(' ', 1);
+ if (!isFirstSection)
+ newParagraph(' ', 1);
+ isFirstSection = false;
}
if (tag == 'emphasis' || tag == 'strong') {
@@ -214,13 +226,17 @@ export default class BookParser {
}
if ((tag == 'p' || tag == 'empty-line' || tag == 'v')) {
- newParagraph(' ', 1);
- if (tag == 'p')
+ if (!(tag == 'p' && isFirstTitlePara))
+ newParagraph(' ', 1);
+ if (tag == 'p') {
inPara = true;
+ isFirstTitlePara = false;
+ }
}
if (tag == 'subtitle') {
newParagraph(' ', 1);
+ isFirstTitlePara = true;
bold = true;
}
@@ -248,6 +264,7 @@ export default class BookParser {
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
+ isFirstTitlePara = false;
bold = false;
center = false;
}
@@ -261,6 +278,7 @@ export default class BookParser {
}
if (tag == 'subtitle') {
+ isFirstTitlePara = false;
bold = false;
}
@@ -293,10 +311,10 @@ export default class BookParser {
text = text.replace(/>/g, '>');
text = text.replace(/= 0 ? ' ' : '');
- if (text == '')
+ if (!text)
return;
text = text.replace(/[\t\n\r]/g, ' ');
@@ -348,13 +366,7 @@ export default class BookParser {
}
if (path.indexOf('/fictionbook/body/section') == 0) {
- switch (tag) {
- case 'p':
- growParagraph(`${tOpen}${text}${tClose}`, text.length);
- break;
- default:
- growParagraph(`${tOpen}${text}${tClose}`, text.length);
- }
+ growParagraph(`${tOpen}${text}${tClose}`, text.length);
}
if (binaryId) {
diff --git a/package.json b/package.json
index 894c7552..912df4b5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "Liberama",
- "version": "0.4.3",
+ "version": "0.4.4",
"engines": {
"node": ">=10.0.0"
},
diff --git a/server/core/BookConverter/index.js b/server/core/BookConverter/index.js
index 93865f30..657ed90b 100644
--- a/server/core/BookConverter/index.js
+++ b/server/core/BookConverter/index.js
@@ -10,6 +10,7 @@ const FileDetector = require('../FileDetector');
const repSpaces = (text) => text.replace(/ |[\t\n\r]/g, ' ');
const repSpaces2 = (text) => text.replace(/[\n\r]/g, '');
+const repSpaces3 = (text) => text.replace(/ /g, ' ');
class BookConverter {
constructor() {
@@ -66,7 +67,10 @@ class BookConverter {
}
}
- return iconv.decode(data, selected);
+ if (selected.toLowerCase() != 'utf-8')
+ return iconv.decode(data, selected);
+ else
+ return data;
}
checkEncoding(data) {
@@ -108,19 +112,21 @@ class BookConverter {
};
const growParagraph = (text) => {
+ if (!pars.length)
+ newParagraph();
+
const l = pars.length;
- if (l) {
- if (pars[l - 1]._t == '')
- text = text.trimLeft();
- pars[l - 1]._t += text;
- }
+ if (pars[l - 1]._t == '')
+ text = text.trimLeft();
+ pars[l - 1]._t += text;
//посчитаем отступы у текста, чтобы выделить потом параграфы
const lines = text.split('\n');
- for (const line of lines) {
- const sp = line.split(' ');
+ for (let line of lines) {
+ line = repSpaces2(line).replace(/\t/g, ' ');
+
let l = 0;
- while (l < sp.length && sp[l].trim() == '') {
+ while (l < line.length && line[l] == ' ') {
l++;
}
if (!spaceCounter[l])
@@ -129,7 +135,6 @@ class BookConverter {
}
};
- newParagraph();
const newPara = new Set(['tr', 'br', 'br/', 'dd', 'p', 'title', '/title', 'h1', 'h2', 'h3', '/h1', '/h2', '/h3']);
const onTextNode = (text, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
@@ -183,22 +188,28 @@ class BookConverter {
};
const growPar = (text) => {
+ if (!newPars.length)
+ newPar();
+
const l = newPars.length;
- if (l) {
- newPars[l - 1]._t += text;
- }
+ newPars[l - 1]._t += text;
}
+ i = 0;
for (const par of pars) {
- newPar();
+ if (i > 0)
+ newPar();
+ i++;
const lines = par._t.split('\n');
- for (const line of lines) {
- const sp = line.split(' ');
+ for (let line of lines) {
+ line = repSpaces2(line).replace(/\t/g, ' ');
+
let l = 0;
- while (l < sp.length && sp[l].trim() == '') {
+ while (l < line.length && line[l] == ' ') {
l++;
}
+
if (l >= parIndent)
newPar();
growPar(line.trim() + ' ');
@@ -227,6 +238,7 @@ class BookConverter {
let inSubtitle = false;
let inJustify = true;
let inImage = false;
+ let isFirstPara = false;
let path = '';
let tag = '';// eslint-disable-line no-unused-vars
@@ -258,13 +270,17 @@ class BookConverter {
};
const growParagraph = (text) => {
+ if (!node._p) {
+ if (text.trim() != '')
+ openTag('p');
+ else
+ return;
+ }
if (node._n == 'p' && node._a.length == 0)
text = text.trimLeft();
node._a.push({_t: text});
};
- openTag('p');
-
const onStartNode = (elemName, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
if (elemName == '')
return;
@@ -272,18 +288,25 @@ class BookConverter {
path += '/' + elemName;
tag = elemName;
} else {
- if (inPara && elemName != 'i' && elemName != 'b' && elemName != 'em' && elemName != 'strong' && elemName != 'img')
- closeTag('p');
-
switch (elemName) {
case 'li':
case 'p':
case 'dd':
+ case 'br':
+ if (!(inSubtitle && isFirstPara)) {
+ if (inPara)
+ closeTag('p');
+ openTag('p');
+ }
+ isFirstPara = false;
+ break;
case 'h1':
case 'h2':
case 'h3':
- case 'br':
+ if (inPara)
+ closeTag('p');
openTag('p');
+ bold = true;
break;
case 'i':
case 'em':
@@ -294,9 +317,12 @@ class BookConverter {
bold = true;
break;
case 'div':
+ if (inPara)
+ closeTag('p');
if (tail.indexOf('align="center"') >= 0) {
openTag('subtitle');
inSubtitle = true;
+ isFirstPara = true;
}
if (tail.indexOf('align="justify"') >= 0) {
@@ -306,6 +332,8 @@ class BookConverter {
break;
case 'img': {
+ if (inPara)
+ closeTag('p');
const attrs = sax.getAttrsSync(tail);
if (attrs.src && attrs.src.value) {
let href = attrs.src.value;
@@ -341,10 +369,13 @@ class BookConverter {
case 'li':
case 'p':
case 'dd':
+ closeTag('p');
+ break;
case 'h1':
case 'h2':
case 'h3':
closeTag('p');
+ bold = false;
break;
case 'i':
case 'em':
@@ -358,6 +389,7 @@ class BookConverter {
if (inSubtitle) {
closeTag('subtitle');
inSubtitle = false;
+ isFirstPara = false;
}
if (inJustify) {
@@ -384,10 +416,10 @@ class BookConverter {
};
const onTextNode = (text) => {// eslint-disable-line no-unused-vars
- if (text != ' ' && text.trim() == '')
- text = text.trim();
+ if (text && text.trim() == '')
+ text = (text.indexOf(' ') >= 0 ? ' ' : '');
- if (text == '')
+ if (!text)
return;
switch (path) {
@@ -416,7 +448,7 @@ class BookConverter {
growParagraph(`${tOpen}${text}${tClose}`);
};
- sax.parseSync(repSpaces(repSpaces2(this.decode(data).toString())), {
+ sax.parseSync(repSpaces3(this.decode(data).toString()), {
onStartNode, onEndNode, onTextNode, onComment,
innerCut: new Set(['head', 'script', 'style'])
});
@@ -474,21 +506,29 @@ class BookConverter {
}
}
+ let tOpen = '';
+ let tBody = '';
+ let tClose = '';
if (name)
- out += `<${name}${attrs}>`;
+ tOpen += `<${name}${attrs}>`;
if (node.hasOwnProperty('_t'))
- out += repSpaces(node._t);
+ tBody += repSpaces(node._t);
for (let nodeName in node) {
if (nodeName && nodeName[0] == '_' && nodeName != '_a')
continue;
const n = node[nodeName];
- out += this.formatFb2Node(n, nodeName);
+ tBody += this.formatFb2Node(n, nodeName);
}
if (name)
- out += `${name}>`;
+ tClose += `${name}>`;
+
+ if (attrs == '' && name == 'p' && tBody.trim() == '')
+ out += ''
+ else
+ out += `${tOpen}${tBody}${tClose}`;
}
return out;
}
diff --git a/server/core/BookConverter/textUtils.js b/server/core/BookConverter/textUtils.js
index 475ef572..6ee5169d 100644
--- a/server/core/BookConverter/textUtils.js
+++ b/server/core/BookConverter/textUtils.js
@@ -1,4 +1,4 @@
-function getEncoding(buf) {
+function getEncoding(buf, returnAll) {
const lowerCase = 3;
const upperCase = 1;
@@ -8,6 +8,7 @@ function getEncoding(buf) {
'd': 'cp866',
'i': 'ISO-8859-5',
'm': 'maccyrillic',
+ 'u': 'utf-8',
};
let charsets = {
@@ -15,38 +16,47 @@ function getEncoding(buf) {
'w': 0,
'd': 0,
'i': 0,
- 'm': 0
+ 'm': 0,
+ 'u': 0,
};
const len = buf.length;
const blockSize = (len > 5*3000 ? 3000 : len);
let counter = 0;
let i = 0;
+ let totalChecked = 0;
while (i < len) {
const char = buf[i];
+ const nextChar = (i < len - 1 ? buf[i + 1] : 0);
+ totalChecked++;
i++;
//non-russian characters
if (char < 128 || char > 256)
continue;
- //CP866
- if ((char > 159 && char < 176) || (char > 223 && char < 242)) charsets['d'] += lowerCase;
- if ((char > 127 && char < 160)) charsets['d'] += upperCase;
+ //UTF-8
+ if ((char == 208 || char == 209) && nextChar >= 128 && nextChar <= 190)
+ charsets['u'] += lowerCase;
+ else {
+ //CP866
+ if ((char > 159 && char < 176) || (char > 223 && char < 242)) charsets['d'] += lowerCase;
+ if ((char > 127 && char < 160)) charsets['d'] += upperCase;
- //KOI8-R
- if ((char > 191 && char < 223)) charsets['k'] += lowerCase;
- if ((char > 222 && char < 256)) charsets['k'] += upperCase;
+ //KOI8-R
+ if ((char > 191 && char < 223)) charsets['k'] += lowerCase;
+ if ((char > 222 && char < 256)) charsets['k'] += upperCase;
- //WIN-1251
- if (char > 223 && char < 256) charsets['w'] += lowerCase;
- if (char > 191 && char < 224) charsets['w'] += upperCase;
+ //WIN-1251
+ if (char > 223 && char < 256) charsets['w'] += lowerCase;
+ if (char > 191 && char < 224) charsets['w'] += upperCase;
- //MAC
- if (char > 221 && char < 255) charsets['m'] += lowerCase;
- if (char > 127 && char < 160) charsets['m'] += upperCase;
+ //MAC
+ if (char > 221 && char < 255) charsets['m'] += lowerCase;
+ if (char > 127 && char < 160) charsets['m'] += upperCase;
- //ISO-8859-5
- if (char > 207 && char < 240) charsets['i'] += lowerCase;
- if (char > 175 && char < 208) charsets['i'] += upperCase;
+ //ISO-8859-5
+ if (char > 207 && char < 240) charsets['i'] += lowerCase;
+ if (char > 175 && char < 208) charsets['i'] += upperCase;
+ }
counter++;
@@ -57,18 +67,24 @@ function getEncoding(buf) {
}
let sorted = Object.keys(charsets).map(function(key) {
- return { codePage: codePage[key], c: charsets[key] };
+ return { codePage: codePage[key], c: charsets[key], totalChecked };
});
sorted.sort((a, b) => b.c - a.c);
- if (sorted[0].c > 0)
+ if (returnAll)
+ return sorted;
+ else if (sorted[0].c > 0)
return sorted[0].codePage;
else
return 'ISO-8859-5';
}
function checkIfText(buf) {
+ const enc = getEncoding(buf, true);
+ if (enc[0].c > enc[0].totalChecked*0.9)
+ return true;
+
let spaceCount = 0;
let crCount = 0;
let lfCount = 0;
diff --git a/server/index.js b/server/index.js
index 1d8e79e9..47b6620a 100644
--- a/server/index.js
+++ b/server/index.js
@@ -31,6 +31,7 @@ async function init() {
}
async function main() {
+ log(`${config.name} v${config.version}`);
log('Initializing');
await init();