Compare commits

...

15 Commits
0.3.1 ... 0.3.4

Author SHA1 Message Date
Book Pauk
d98251e34a Merge branch 'release/0.3.4' 2019-02-19 11:25:26 +07:00
Book Pauk
1eea4e8fc1 0.3.4 2019-02-19 11:25:10 +07:00
Book Pauk
da330bc615 Вместо omnireader.ru:11080 будет old.omnireader.ru 2019-02-19 11:23:37 +07:00
Book Pauk
1134250954 Merge tag '0.3.3' into develop
0.3.3
2019-02-19 02:37:43 +07:00
Book Pauk
d8fddd4128 Merge branch 'release/0.3.3' 2019-02-19 02:37:29 +07:00
Book Pauk
42656cd690 0.3.3 2019-02-19 02:37:06 +07:00
Book Pauk
746f9517d9 Поправил определение кодировки 2019-02-19 02:31:03 +07:00
Book Pauk
2a373de5f5 Мелкая поправка 2019-02-19 02:16:45 +07:00
Book Pauk
b507f00929 Merge tag '0.3.2' into develop
0.3.2
2019-02-19 01:41:03 +07:00
Book Pauk
aea8a254bf Merge branch 'hotfix/0.3.2' 2019-02-19 01:40:50 +07:00
Book Pauk
4247665ba4 Добавил поддержку форматов .gz .bz2 2019-02-19 01:39:52 +07:00
Book Pauk
d59d0a6a42 Промежуточный коммит, парсинг изображений 2019-02-18 23:55:32 +07:00
Book Pauk
8d40ed0bda Добавлено распарсивание тега binary 2019-02-18 21:28:48 +07:00
Book Pauk
67bc893e22 Добавил горячую клавишу 2019-02-18 17:23:12 +07:00
Book Pauk
0f5d3b34a5 Merge tag '0.3.1' into develop
0.3.1
2019-02-18 16:10:56 +07:00
11 changed files with 231 additions and 23 deletions

View File

@@ -4,7 +4,7 @@
<ul>
<li><b>F1, H</b> - открыть справку</li>
<li><b>Escape</b> - показать/скрыть страницу загрузки</li>
<li><b>Tab</b> - показать/скрыть панель управления</li>
<li><b>Tab, Q</b> - показать/скрыть панель управления</li>
<li><b>PageUp, Left, Shift+Space, Backspace</b> - страницу назад</li>
<li><b>PageDown, Right, Space</b> - страницу вперед</li>
<li><b>Home</b> - в начало книги</li>

View File

@@ -103,6 +103,13 @@ class LoaderPage extends Vue {
event.stopPropagation();
return true;
}
if (event.type == 'keydown' && (document.activeElement !== input && event.code == 'KeyQ')) {
this.$emit('tool-bar-toggle');
event.preventDefault();
event.stopPropagation();
return true;
}
}
}
//-----------------------------------------------------------------------------

View File

@@ -930,6 +930,7 @@ class TextPage extends Vue {
this.$emit('full-screen-toogle');
break;
case 'Tab':
case 'KeyQ':
this.doToolBarToggle();
event.preventDefault();
event.stopPropagation();

View File

@@ -2,6 +2,8 @@ import he from 'he';
import sax from '../../../../server/core/BookConverter/sax';
import {sleep} from '../../../share/utils';
const maxImageLineCount = 100;
export default class BookParser {
constructor() {
// defaults
@@ -37,6 +39,10 @@ export default class BookParser {
let center = false;
let bold = false;
let italic = false;
this.binary = {};
let binaryId = '';
let binaryType = '';
let dimPromises = [];
let paraIndex = -1;
let paraOffset = 0;
@@ -50,6 +56,28 @@ export default class BookParser {
addIndex: Number, //индекс добавляемого пустого параграфа (addEmptyParagraphs)
}
*/
const getImageDimensions = (binaryId, binaryType, data) => {
return new Promise (async(resolve, reject) => {
const i = new Image();
let resolved = false;
i.onload = () => {
resolved = true;
this.binary[binaryId] = {
w: i.width,
h: i.height,
type: binaryType,
data
};
resolve();
};
i.src = `data:${binaryType};base64,${data}`;
await sleep(30*1000);
if (!resolved)
reject('Не удалось получить размер изображения');
});
};
const newParagraph = (text, len, addIndex) => {
paraIndex++;
let p = {
@@ -103,13 +131,26 @@ export default class BookParser {
paraOffset += p.length;
};
const onStartNode = (elemName) => {// eslint-disable-line no-unused-vars
const onStartNode = (elemName, tail) => {// eslint-disable-line no-unused-vars
if (elemName == '?xml')
return;
tag = elemName;
path += '/' + elemName;
if (tag == 'binary') {
let attrs = sax.getAttrsSync(tail);
binaryType = (attrs['content-type'].value ? attrs['content-type'].value : '');
if (binaryType == 'image/jpeg' || binaryType == 'image/png')
binaryId = (attrs.id.value ? attrs.id.value : '');
}
if (tag == 'image') {
let attrs = sax.getAttrsSync(tail);
if (attrs.href.value)
newParagraph(`<image href="${attrs.href.value}">${' '.repeat(maxImageLineCount)}</image>`, maxImageLineCount);
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
newParagraph(' ', 1);
@@ -146,6 +187,10 @@ export default class BookParser {
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
if (tag == elemName) {
if (tag == 'binary') {
binaryId = '';
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
bold = false;
@@ -245,6 +290,10 @@ export default class BookParser {
growParagraph(`${tOpen}${text}${tClose}`, text.length);
}
}
if (binaryId) {
dimPromises.push(getImageDimensions(binaryId, binaryType, text));
}
};
const onProgress = async(prog) => {
@@ -256,6 +305,14 @@ export default class BookParser {
onStartNode, onEndNode, onTextNode, onProgress
});
if (dimPromises.length) {
try {
await Promise.all(dimPromises);
} catch (e) {
//
}
}
this.fb2 = fb2;
this.para = para;
@@ -292,18 +349,26 @@ export default class BookParser {
splitToStyle(s) {
let result = [];/*array of {
style: {bold: Boolean, italic: Boolean, center: Boolean},
image: Boolean,
imageId: String,
text: String,
}*/
let style = {};
let image = {};
/*let attrs = sax.getAttrsSync(tail);
if (attrs.href.value)
newParagraph(' '.repeat(maxImageLineCount) + `<image href="${attrs.href.value}" />`, maxImageLineCount);
*/
const onTextNode = async(text) => {// eslint-disable-line no-unused-vars
result.push({
style: Object.assign({}, style),
text: text
image,
text
});
};
const onStartNode = async(elemName) => {// eslint-disable-line no-unused-vars
const onStartNode = async(elemName, tail) => {// eslint-disable-line no-unused-vars
switch (elemName) {
case 'strong':
style.bold = true;
@@ -314,6 +379,9 @@ export default class BookParser {
case 'center':
style.center = true;
break;
case 'image':
image = {};
break;
}
};
@@ -328,6 +396,9 @@ export default class BookParser {
case 'center':
style.center = false;
break;
case 'image':
image = {};
break;
}
};
@@ -335,7 +406,6 @@ export default class BookParser {
onStartNode, onEndNode, onTextNode
});
//длинные слова (или белиберду без пробелов) тоже разобьем
const maxWordLength = this.maxWordLength;
const parts = result;
@@ -350,7 +420,7 @@ export default class BookParser {
if (i - spaceIndex >= maxWordLength && i < p.text.length - 1 &&
this.measureText(p.text.substr(spaceIndex + 1, i - spaceIndex), p.style) >= this.w - this.p) {
result.push({style: p.style, text: p.text.substr(0, i + 1)});
result.push({style: p.style, image: p.image, text: p.text.substr(0, i + 1)});
p = {style: p.style, text: p.text.substr(i + 1)};
spaceIndex = -1;
i = -1;

View File

@@ -25,8 +25,8 @@ server {
}
server {
listen 11080;
server_name omnireader.ru;
listen 80;
server_name old.omnireader.ru;
client_max_body_size 50m;

26
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "Liberama",
"version": "0.2.0",
"version": "0.3.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -3095,6 +3095,30 @@
"strip-dirs": "^2.0.0"
}
},
"decompress-bzip2": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/decompress-bzip2/-/decompress-bzip2-4.0.0.tgz",
"integrity": "sha1-0SVMlJ4F6vYol1QoawY/3Hz/AT8=",
"requires": {
"file-type": "^4.3.0",
"seek-bzip": "^1.0.5"
},
"dependencies": {
"file-type": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz",
"integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU="
}
}
},
"decompress-gz": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/decompress-gz/-/decompress-gz-0.0.1.tgz",
"integrity": "sha512-YMdCWdxHvPplsTbV1tvr2oFJOtAFNxqVMFnKWEmePBXl+LKG5z5bFrowzc12Jzd7O29nnzI/D1M95Asx0Qa1fg==",
"requires": {
"file-type": "^5.2.0"
}
},
"decompress-response": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "Liberama",
"version": "0.3.1",
"version": "0.3.4",
"engines": {
"node": ">=10.0.0"
},
@@ -60,6 +60,8 @@
"chardet": "^0.7.0",
"compression": "^1.7.3",
"decompress": "^4.2.0",
"decompress-bzip2": "^4.0.0",
"decompress-gz": "0.0.1",
"detect-file-type": "^0.2.0",
"element-ui": "^2.4.11",
"express": "^4.16.4",

View File

@@ -53,18 +53,16 @@ class BookConverter {
}
decode(data) {
const charsetAll = chardet.detectAll(data.slice(0, 20000));
let selected = textUtils.getEncoding(data);
let selected = 'ISO-8859-5';
if (selected == 'ISO-8859-5') {
const charsetAll = chardet.detectAll(data.slice(0, 20000));
for (const charset of charsetAll) {
if (charset.name.indexOf('ISO-8859') < 0) {
selected = charset.name;
break;
}
}
if (selected == 'ISO-8859-5') {
selected = textUtils.getEncoding(data);
}
return iconv.decode(data, selected);

View File

@@ -276,7 +276,84 @@ async function parse(xstr, options) {
await _onProgress(100);
}
function getAttrsSync(tail) {
let result = {};
let name = '';
let value = '';
let vOpen = '';
let inName = false;
let inValue = false;
let waitValue = false;
let waitEq = false;
const pushResult = () => {
if (name != '') {
let ns = '';
if (name.indexOf(':') >= 0) {
[ns, name] = name.split(':');
}
result[name] = {value, ns};
}
name = '';
value = '';
vOpen = '';
inName = false;
inValue = false;
waitValue = false;
waitEq = false;
};
tail = tail.replace(/[\t\n\r]/g, ' ');
for (let i = 0; i < tail.length; i++) {
const c = tail.charAt(i);
if (c == ' ') {
if (inValue) {
if (vOpen == '"')
value += c;
else
pushResult();
} else if (inName) {
waitEq = true;
inName = false;
}
} else if (!inValue && c == '=') {
waitEq = false;
waitValue = true;
inName = false;
} else if (c == '"') {
if (inValue) {
pushResult();
} else if (waitValue) {
inValue = true;
vOpen = '"';
}
} else if (inValue) {
value += c;
} else if (inName) {
name += c;
} else if (waitEq) {
pushResult();
inName = true;
name = c;
} else if (waitValue) {
waitValue = false;
inValue = true;
vOpen = ' ';
value = c;
} else {
inName = true;
name = c;
}
}
if (name != '')
pushResult();
return result;
}
module.exports = {
parseSync,
getAttrsSync,
parse
}

View File

@@ -85,7 +85,7 @@ function checkIfText(buf) {
const crFreq = crCount/(buf.length + 1);
const lfFreq = lfCount/(buf.length + 1);
return (spaceFreq > 0.1 || crFreq > 0.03 || lfFreq > 0.03);
return (buf.length < 1000 || spaceFreq > 0.1 || crFreq > 0.03 || lfFreq > 0.03);
}
module.exports = {

View File

@@ -1,8 +1,12 @@
const fs = require('fs-extra');
const zlib = require('zlib');
const crypto = require('crypto');
const path = require('path');
const utils = require('./utils');
const decompress = require('decompress');
const decompressGz = require('decompress-gz');
const decompressBzip2 = require('decompress-bzip2');
const FileDetector = require('./FileDetector');
class FileDecompressor {
@@ -13,10 +17,32 @@ class FileDecompressor {
async decompressFile(filename, outputDir) {
const fileType = await this.detector.detectFile(filename);
if (!fileType || !(fileType.ext == 'zip' || fileType.ext == 'bz2'))
if (!fileType || !(fileType.ext == 'zip' || fileType.ext == 'bz2' || fileType.ext == 'gz'))
return filename;
const files = await decompress(filename, outputDir);
//дурной decompress, поэтому в 2 этапа
//этап 1
let files = [];
try {
files = await decompress(filename, outputDir);
} catch (e) {
//
}
//этап 2
if (files.length == 0) {
try {
files = await decompress(filename, outputDir, {
inputFile: filename,
plugins: [
decompressGz(),
decompressBzip2({path: path.basename(filename)}),
]
});
} catch (e) {
//
}
}
let result = filename;
let max = 0;
@@ -29,6 +55,9 @@ class FileDecompressor {
}
}
}
//дурной decompress
if (result != filename)
await fs.chmod(result, 0o664);
return result;
}