Compare commits

...

19 Commits

Author SHA1 Message Date
Book Pauk
c3f1707343 Merge branch 'release/0.7.9-1' 2019-12-23 21:02:02 +07:00
Book Pauk
1ed058a553 Мелкие поправки 2019-12-23 20:57:44 +07:00
Book Pauk
0500a8178d Merge tag '0.7.9' into develop
0.7.9
2019-11-27 18:16:52 +07:00
Book Pauk
7d0059f573 Merge branch 'release/0.7.9' 2019-11-27 18:16:43 +07:00
Book Pauk
4e3b882362 Версия 0.7.9 2019-11-27 18:15:28 +07:00
Book Pauk
13cf47873e Добавлен неубираемый баннер о переходе на httpS 2019-11-27 18:11:34 +07:00
Book Pauk
7ee23ec38f Удален устаревший код 2019-11-27 17:33:30 +07:00
Book Pauk
eebf17c42c Добавлена проверка наличия файла на сервере перед скачиванием fb2 2019-11-27 17:12:07 +07:00
Book Pauk
f84536788b Merge tag '0.7.8b' into develop
0.7.8b
2019-11-25 16:00:10 +07:00
Book Pauk
4bbfdc2cb2 Merge branch 'release/0.7.8b' 2019-11-25 16:00:00 +07:00
Book Pauk
211fec35e3 Исправлен баг 2019-11-25 15:56:29 +07:00
Book Pauk
b8214a46ae Merge tag '0.7.8' into develop
0.7.8
2019-11-25 15:39:35 +07:00
Book Pauk
549ef91c81 Merge branch 'release/0.7.8' 2019-11-25 15:39:23 +07:00
Book Pauk
cede65313b Версия 0.7.8 2019-11-25 15:38:52 +07:00
Book Pauk
d897a7400f Улучшение парсера fb2 2019-11-25 15:36:34 +07:00
Book Pauk
47f059213f Добавлен конвертер для flibusta 2019-11-25 15:21:33 +07:00
Book Pauk
8af51bbf08 Улучшение фильтра html 2019-11-25 15:15:06 +07:00
Book Pauk
53d9f5ddc6 Улучшение конвертирования html->fb2 2019-11-24 15:36:11 +07:00
Book Pauk
06fffdccc8 Merge tag '0.7.7d' into develop
0.7.7d
2019-11-18 20:04:03 +07:00
13 changed files with 158 additions and 38 deletions

View File

@@ -56,7 +56,11 @@ class Reader {
}
}
async loadCachedBook(url, callback){
async checkUrl(url) {
return await axios.head(url, {headers: {'Cache-Control': 'no-cache'}});
}
async loadCachedBook(url, callback) {
const response = await axios.head(url);
let estSize = 1000000;

View File

@@ -1,5 +1,8 @@
<template>
<el-container>
<div v-show="isShowMigrationWarning" style="height: 30px; overflow: hidden; white-space:nowrap;">
<span style="margin-left: 10px; font-size: 20px; position: relative; top: 2px" class="clickable" @click="showMigrationHttp">HTTP-версия читалки скоро станет недоступна. Подробнее...</span>
</div>
<el-header v-show="toolBarActive" height='50px'>
<div ref="header" class="header">
<el-tooltip content="Загрузить книгу" :open-delay="1000" effect="light">
@@ -320,15 +323,6 @@ class Reader extends Vue {
});
this.loadSettings();
//TODO: убрать в будущем
if (this.showToolButton['history']) {
const newShowToolButton = Object.assign({}, this.showToolButton);
newShowToolButton['recentBooks'] = true;
delete newShowToolButton['history'];
const newSettings = Object.assign({}, this.settings, { showToolButton: newShowToolButton });
this.commit('reader/setSettings', newSettings);
}
}
mounted() {
@@ -444,6 +438,14 @@ class Reader extends Vue {
}
}
get isShowMigrationWarning() {
return window.location.protocol == 'http:';
}
showMigrationHttp() {
this.migrationVisible1 = true;
}
migrationDialogDisable() {
this.migrationVisible1 = false;
this.migrationVisible2 = false;

View File

@@ -5,6 +5,7 @@
<span v-show="loading"><i class="el-icon-loading" style="font-size: 25px"></i> <span style="position: relative; top: -4px">Список загружается</span></span>
</template>
<a ref="download" style='display: none;'></a>
<el-table
:data="tableData"
style="width: 570px"
@@ -72,7 +73,7 @@
>
<template slot-scope="scope">
<a v-show="isUrl(scope.row.url)" :href="scope.row.url" target="_blank">Оригинал</a><br>
<a :href="scope.row.path" :download="getFileNameFromPath(scope.row.path)">Скачать FB2</a>
<a :href="scope.row.path" @click.prevent="downloadBook(scope.row.path)">Скачать FB2</a>
</template>
</el-table-column>
@@ -104,6 +105,7 @@ import _ from 'lodash';
import * as utils from '../../../share/utils';
import Window from '../../share/Window.vue';
import bookManager from '../share/bookManager';
import readerApi from '../../../api/reader';
export default @Component({
components: {
@@ -209,7 +211,7 @@ class RecentBooksPage extends Vue {
a.middleName
]).join(' '));
author = authorNames.join(', ');
} else {
} else {//TODO: убрать в будущем
author = _.compact([
fb2.lastName,
fb2.firstName,
@@ -268,8 +270,20 @@ class RecentBooksPage extends Vue {
return result;
}
getFileNameFromPath(fb2Path) {
return path.basename(fb2Path).substr(0, 10) + '.fb2';
async downloadBook(fb2path) {
try {
await readerApi.checkUrl(fb2path);
const d = this.$refs.download;
d.href = fb2path;
d.download = path.basename(fb2path).substr(0, 10) + '.fb2';
d.click();
} catch (e) {
let errMes = e.message;
if (errMes.indexOf('404') >= 0)
errMes = 'Файл не найден на сервере (возможно был удален как устаревший)';
this.$alert(errMes, 'Ошибка', {type: 'error'});
}
}
openOriginal(url) {

View File

@@ -32,9 +32,6 @@ export default class BookParser {
//defaults
let fb2 = {
firstName: '',
middleName: '',
lastName: '',
bookTitle: '',
};
@@ -240,6 +237,7 @@ export default class BookParser {
newParagraph(' ', 1);
isFirstTitlePara = true;
bold = true;
center = true;
}
if (tag == 'epigraph') {
@@ -282,6 +280,7 @@ export default class BookParser {
if (tag == 'subtitle') {
isFirstTitlePara = false;
bold = false;
center = false;
}
if (tag == 'epigraph') {
@@ -367,11 +366,10 @@ export default class BookParser {
tClose += (bold ? '</strong>' : '');
tClose += (center ? '</center>' : '');
if (path.indexOf('/fictionbook/body/title') == 0) {
growParagraph(`${tOpen}${text}${tClose}`, text.length);
}
if (path.indexOf('/fictionbook/body/section') == 0) {
if (path.indexOf('/fictionbook/body/title') == 0 ||
path.indexOf('/fictionbook/body/section') == 0 ||
path.indexOf('/fictionbook/body/epigraph') == 0
) {
growParagraph(`${tOpen}${text}${tClose}`, text.length);
}

View File

@@ -319,7 +319,6 @@ class BookManager {
metaOnly(book) {
let result = Object.assign({}, book);
delete result.data;//можно будет убрать эту строку со временем
delete result.parsed;
return result;
}

View File

@@ -1,4 +1,28 @@
export const versionHistory = [
{
showUntil: '2019-11-26',
header: '0.7.9 (2019-11-27)',
content:
`
<ul>
<li>добавлен неубираемый баннер для http-версии о переходе на httpS</li>
<li>исправления багов</li>
</ul>
`
},
{
showUntil: '2019-11-24',
header: '0.7.8 (2019-11-25)',
content:
`
<ul>
<li>улучшение html-фильтров для сайтов</li>
<li>исправления багов</li>
</ul>
`
},
{
showUntil: '2019-11-10',
header: '0.7.7 (2019-11-06)',

View File

@@ -1,6 +1,6 @@
{
"name": "Liberama",
"version": "0.7.7",
"version": "0.7.9",
"engines": {
"node": ">=10.0.0"
},

View File

@@ -41,9 +41,9 @@ class ConfigManager {
process.env.NODE_ENV = this.branch;
this.branchConfigFile = __dirname + `/${this.branch}.js`;
await fs.access(this.branchConfigFile);
this._config = require(this.branchConfigFile);
await fs.ensureDir(this._config.dataDir);
this._userConfigFile = `${this._config.dataDir}/config.json`;
this.inited = true;
@@ -83,6 +83,7 @@ class ConfigManager {
async save() {
if (!this.inited)
throw new Error('not inited');
const dataToSave = _.pick(this._config, propsToSave);
await fs.writeFile(this.userConfigFile, JSON.stringify(dataToSave, null, 4));
}

View File

@@ -23,7 +23,7 @@ class ConvertFb2 extends ConvertBase {
const right = data.indexOf('?>', left);
if (right >= 0) {
const head = data.slice(left, right + 2).toString();
const m = head.match(/encoding="(.*)"/);
const m = head.match(/encoding="(.*?)"/);
if (m) {
let encoding = m[1].toLowerCase();
if (encoding != 'utf-8') {

View File

@@ -39,16 +39,19 @@ class ConvertHtml extends ConvertBase {
let title = '';
let inTitle = false;
let inSubTitle = false;
let inImage = false;
let image = {};
let bold = false;
let italic = false;
let begining = true;
let spaceCounter = [];
const repCrLfTab = (text) => text.replace(/[\n\r]/g, '').replace(/\t/g, ' ');
const newParagraph = () => {
begining = false;
pars.push({_n: 'p', _t: ''});
};
@@ -58,6 +61,8 @@ class ConvertHtml extends ConvertBase {
const l = pars.length;
pars[l - 1]._t += text;
if (inSubTitle)
pars[l - 1]._n = '';
//посчитаем отступы у текста, чтобы выделить потом параграфы
const lines = text.split('\n');
@@ -77,16 +82,21 @@ class ConvertHtml extends ConvertBase {
}
};
const newPara = new Set(['tr', '/table', 'hr', 'br', 'br/', 'li', 'dt', 'dd', 'p', 'title', '/title', 'h1', 'h2', 'h3', '/h1', '/h2', '/h3']);
const newPara = new Set(['tr', '/table', 'hr', 'br', 'br/', 'li', 'dt', 'dd', 'p', 'title', '/title', 'ul', '/ul', 'h1', 'h2', 'h3', 'h4', 'h5', '/h1', '/h2', '/h3', '/h4', '/h5']);
const newPara2 = new Set(['h1', 'h2', 'h3', 'h4', 'h5']);
const onTextNode = (text, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
text = this.escapeEntities(text);
if (!cutCounter && !(cutTitle && inTitle)) {
let tOpen = (bold ? '<strong>' : '');
let tOpen = '';
tOpen += (inSubTitle ? '<subtitle>' : '');
tOpen += (bold ? '<strong>' : '');
tOpen += (italic ? '<emphasis>' : '');
let tClose = (italic ? '</emphasis>' : '');
let tClose = ''
tClose += (italic ? '</emphasis>' : '');
tClose += (bold ? '</strong>' : '');
tClose += (inSubTitle ? '</subtitle>' : '');
growParagraph(`${tOpen}${text}${tClose}`);
}
@@ -106,6 +116,8 @@ class ConvertHtml extends ConvertBase {
const onStartNode = (tag, tail, singleTag, cutCounter, cutTag) => {// eslint-disable-line no-unused-vars
if (!cutCounter) {
if (newPara2.has(tag) && !begining)
newParagraph();
if (newPara.has(tag))
newParagraph();
@@ -130,6 +142,10 @@ class ConvertHtml extends ConvertBase {
cutTitle = true;
}
if (tag == 'subtitle') {
inSubTitle = true;
}
if (tag == 'fb2-image') {
inImage = true;
const attrs = sax.getAttrsSync(tail);
@@ -141,6 +157,8 @@ class ConvertHtml extends ConvertBase {
if (!cutCounter) {
if (newPara.has('/' + tag))
newParagraph();
if (newPara2.has('/' + tag))
newParagraph();
switch (tag) {
case 'i':
@@ -160,6 +178,9 @@ class ConvertHtml extends ConvertBase {
if (tag == 'title' || tag == 'cut-title')
inTitle = false;
if (tag == 'subtitle')
inSubTitle = false;
if (tag == 'fb2-image')
inImage = false;
};
@@ -197,7 +218,8 @@ class ConvertHtml extends ConvertBase {
while (i > 0 && (!spaceCounter[i] || spaceCounter[i] < total)) i--;
}
const parIndent = (i > 0 ? i : 0);
let parIndent = (i > 0 ? i : 0);
if (parIndent > 2) parIndent--;
let newPars = [];
const newPar = () => {
@@ -233,7 +255,7 @@ class ConvertHtml extends ConvertBase {
l++;
}
if (l >= parIndent) {
if (l >= parIndent || line == '') {
if (j > 0)
newPar();
j++;
@@ -250,6 +272,7 @@ class ConvertHtml extends ConvertBase {
//убираем лишнее, делаем валидный fb2, т.к. в рез-те разбиения на параграфы бьются теги
bold = false;
italic = false;
inSubTitle = false;
pars = body.section._a[0];
for (let i = 0; i < pars.length; i++) {
if (pars[i]._n != 'p')
@@ -259,16 +282,24 @@ class ConvertHtml extends ConvertBase {
if (pars[i]._t.indexOf('<') >= 0 || bold || italic) {
const t = pars[i]._t;
let first = true;
let a = [];
const onTextNode = (text) => {
let tOpen = (bold ? '<strong>' : '');
let tOpen = '';
tOpen += (inSubTitle ? '<subtitle>' : '');
tOpen += (bold ? '<strong>' : '');
tOpen += (italic ? '<emphasis>' : '');
let tClose = (italic ? '</emphasis>' : '');
let tClose = ''
tClose += (italic ? '</emphasis>' : '');
tClose += (bold ? '</strong>' : '');
tClose += (inSubTitle ? '</subtitle>' : '');
if (first)
text = text.replace(/^\s+/, ''); //trimLeft
a.push(`${tOpen}${text}${tClose}`);
first = false;
}
const onStartNode = (tag) => {
@@ -276,6 +307,8 @@ class ConvertHtml extends ConvertBase {
bold = true;
if (tag == 'emphasis')
italic = true;
if (tag == 'subtitle')
inSubTitle = true;
}
const onEndNode = (tag) => {
@@ -283,6 +316,8 @@ class ConvertHtml extends ConvertBase {
bold = false;
if (tag == 'emphasis')
italic = false;
if (tag == 'subtitle')
inSubTitle = false;
}
sax.parseSync(t, { onStartNode, onEndNode, onTextNode });

View File

@@ -102,6 +102,8 @@ class ConvertSamlib extends ConvertBase {
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
if (inPara)
closeTag('p');
openTag('p');
@@ -173,6 +175,8 @@ class ConvertSamlib extends ConvertBase {
case 'h1':
case 'h2':
case 'h3':
case 'h4':
case 'h5':
closeTag('p');
bold = false;
break;

View File

@@ -12,7 +12,10 @@ const sitesFilter = {
converter: 'cutter',
begin: `<!-- BEGIN section where work skin applies -->`,
end: `<!-- END work skin -->`,
}
},
'flibusta.is': {
converter: 'flibusta'
},
};
class ConvertSites extends ConvertHtml {
@@ -54,11 +57,11 @@ class ConvertSites extends ConvertHtml {
if (m)
title = m[1];
return `<title>${title.trim()}</title>`;
return title.trim();
}
cutter(text, opts) {
const title = this.getTitle(text);
const title = `<title>${this.getTitle(text)}</title>`;
const l = text.indexOf(opts.begin) + opts.begin.length;
const r = text.indexOf(opts.end);
if (l < 0 || r < 0 || r <= l)
@@ -66,6 +69,42 @@ class ConvertSites extends ConvertHtml {
return text.substring(l, r) + title;
}
flibusta(text) {
let author = '';
let m = text.match(/- <a href=".+">([\s\S]*?)<\/a><br\/?>/);
if (m)
author = m[1];
let book = this.getTitle(text);
book = book.replace(' (fb2) | Флибуста', '');
const title = `<title>${author}${(author ? ' - ' : '')}${book}</title>`;
let begin = '<h3 class="book">';
if (text.indexOf(begin) <= 0)
begin = '<h3 class=book>';
const end = '<div id="footer">';
const l = text.indexOf(begin);
const r = text.indexOf(end);
if (l < 0 || r < 0 || r <= l)
return false;
return text.substring(l, r)
.replace(/blockquote class="?book"?/g, 'p')
.replace(/<br\/?>\s*<\/h3>/g, '</h3>')
.replace(/<h3 class="?book"?>/g, '<br><br><subtitle>')
.replace(/<h5 class="?book"?>/g, '<br><br><subtitle>')
.replace(/<h3>/g, '<br><br><subtitle>')
.replace(/<h5>/g, '<br><br><subtitle>')
.replace(/<\/h3>/g, '</subtitle><br>')
.replace(/<\/h5>/g, '</subtitle><br>')
.replace(/<div class="?stanza"?>/g, '<br>')
.replace(/<div>/g, '<br>')
+ title;
}
}
module.exports = ConvertSites;

View File

@@ -18,7 +18,7 @@ async function init() {
const log = appLogger.log;
//dirs
log(`${config.name} v${config.version}`);
log(`${config.name} v${config.version}, Node.js ${process.version}`);
log('Initializing');
await fs.ensureDir(config.dataDir);
@@ -40,7 +40,7 @@ async function init() {
await connManager.init(config);
}
async function main() {
async function main() {
const log = new (require('./core/AppLogger'))().log;//singleton
const config = new (require('./config'))().config;//singleton