Merge branch 'release/0.9.1'

This commit is contained in:
Book Pauk
2020-03-03 21:48:01 +07:00
11 changed files with 1177 additions and 592 deletions

View File

@@ -54,6 +54,34 @@
<!----------------------------------------------> <!---------------------------------------------->
<div class="part-header">Другое</div> <div class="part-header">Другое</div>
<div class="item row">
<div class="label-6">Обработка</div>
<div class="col row">
<q-checkbox v-model="enableSitesFilter" @input="needTextReload" size="xs" label="Включить html-фильтр для сайтов">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Html-фильтр вырезает лишние элементы со<br>
страницы для определенных сайтов, таких как:<br>
samlib.ru<br>
www.fanfiction.net<br>
archiveofourown.org<br>
и других
</q-tooltip>
</q-checkbox>
</div>
</div>
<div class="item row">
<div class="label-6">Обработка</div>
<q-checkbox size="xs" v-model="lazyParseEnabled" label="Предварительная подготовка текста">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Включение этой опции позволяет делать предварительную<br>
подготовку всего текста в ленивом режиме сразу после<br>
загрузки книги. Это может повысить отзывчивость читалки,<br>
но нагружает процессор каждый раз при открытии книги.
</q-tooltip>
</q-checkbox>
</div>
<div class="item row"> <div class="item row">
<div class="label-6">Парам. в URL</div> <div class="label-6">Парам. в URL</div>
<q-checkbox size="xs" v-model="allowUrlParamBookPos"> <q-checkbox size="xs" v-model="allowUrlParamBookPos">
@@ -68,18 +96,6 @@
</q-checkbox> </q-checkbox>
</div> </div>
<div class="item row">
<div class="label-6">Парсинг</div>
<q-checkbox size="xs" v-model="lazyParseEnabled" label="Предварительная обработка текста">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Включение этой опции позволяет делать предварительную<br>
обработку текста в ленивом режиме сразу после загрузки<br>
книги. Это может повысить отзывчивость читалки, но<br>
нагружает процессор каждый раз при открытии книги.
</q-tooltip>
</q-checkbox>
</div>
<div class="item row"> <div class="item row">
<div class="label-6">Копирование</div> <div class="label-6">Копирование</div>
<q-checkbox size="xs" v-model="copyFullText" label="Загружать весь текст"> <q-checkbox size="xs" v-model="copyFullText" label="Загружать весь текст">

View File

@@ -22,3 +22,15 @@
<NumInput class="col-left" v-model="statusBarColorAlpha" :min="0" :max="1" :digits="2" :step="0.1" :disable="!showStatusBar"/> <NumInput class="col-left" v-model="statusBarColorAlpha" :min="0" :max="1" :digits="2" :step="0.1" :disable="!showStatusBar"/>
</div> </div>
</div> </div>
<div class="item row">
<div class="label-2"></div>
<div class="col row">
<q-checkbox v-model="statusBarClickOpen" size="xs" label="Открывать оригинал по клику">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
По клику на автора-название в строке статуса<br>
открывать оригинал произведения в новой вкладке
</q-tooltip>
</q-checkbox>
</div>
</div>

View File

@@ -108,22 +108,6 @@
<NumInput class="col" v-model="addEmptyParagraphs" :min="0" :max="2"/> <NumInput class="col" v-model="addEmptyParagraphs" :min="0" :max="2"/>
</div> </div>
<div class="item row">
<div class="label-2"></div>
<div class="col row">
<q-checkbox v-model="enableSitesFilter" @input="needTextReload" size="xs" label="Включить html-фильтр для сайтов">
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
Html-фильтр вырезает лишние элементы со<br>
страницы для определенных сайтов, таких как:<br>
samlib.ru<br>
www.fanfiction.net<br>
archiveofourown.org<br>
и других
</q-tooltip>
</q-checkbox>
</div>
</div>
<div class="item row"> <div class="item row">
<div class="label-2">Изображения</div> <div class="label-2">Изображения</div>
<div class="col row"> <div class="col row">

View File

@@ -21,11 +21,12 @@
@wheel.prevent.stop="onMouseWheel" @wheel.prevent.stop="onMouseWheel"
@touchstart.stop="onTouchStart" @touchend.stop="onTouchEnd" @touchmove.stop="onTouchMove" @touchcancel.prevent.stop="onTouchCancel" @touchstart.stop="onTouchStart" @touchend.stop="onTouchEnd" @touchmove.stop="onTouchMove" @touchcancel.prevent.stop="onTouchCancel"
oncontextmenu="return false;"> oncontextmenu="return false;">
<div v-show="showStatusBar" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop <div v-show="showStatusBar && statusBarClickOpen" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop
@click.prevent.stop="onStatusBarClick"></div> @click.prevent.stop="onStatusBarClick"></div>
</div> </div>
<div v-show="!clickControl && showStatusBar" class="layout" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop <div v-show="!clickControl && showStatusBar && statusBarClickOpen" class="layout" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop
@click.prevent.stop="onStatusBarClick"></div> @click.prevent.stop="onStatusBarClick">
</div>
<!-- невидимым делать нельзя, вовремя не подгружаютя шрифты --> <!-- невидимым делать нельзя, вовремя не подгружаютя шрифты -->
<canvas ref="offscreenCanvas" class="layout" style="visibility: hidden"></canvas> <canvas ref="offscreenCanvas" class="layout" style="visibility: hidden"></canvas>
<div ref="measureWidth" style="position: absolute; visibility: hidden"></div> <div ref="measureWidth" style="position: absolute; visibility: hidden"></div>

View File

@@ -1,4 +1,16 @@
export const versionHistory = [ export const versionHistory = [
{
showUntil: '2020-03-02',
header: '0.9.1 (2020-03-03)',
content:
`
<ul>
<li>улучшение работы серверной части</li>
<li>незначительные изменения интерфейса</li>
</ul>
`
},
{ {
showUntil: '2020-02-25', showUntil: '2020-02-25',
header: '0.9.0 (2020-02-26)', header: '0.9.0 (2020-02-26)',

View File

@@ -80,7 +80,6 @@ Vue.use(Quasar, { config, components, directives, plugins });
//import '@quasar/extras/material-icons-outlined/material-icons-outlined.css'; //import '@quasar/extras/material-icons-outlined/material-icons-outlined.css';
//import '@quasar/extras/fontawesome-v5/fontawesome-v5.css'; //import '@quasar/extras/fontawesome-v5/fontawesome-v5.css';
//import '@quasar/extras/material-icons-outlined/material-icons-outlined.css';
import '@quasar/extras/line-awesome/line-awesome.css'; import '@quasar/extras/line-awesome/line-awesome.css';
//import fontawesomeV5 from 'quasar/icon-set/fontawesome-v5.js' //import fontawesomeV5 from 'quasar/icon-set/fontawesome-v5.js'

View File

@@ -160,6 +160,7 @@ const settingDefaults = {
statusBarTop: false,// top, bottom statusBarTop: false,// top, bottom
statusBarHeight: 19,// px statusBarHeight: 19,// px
statusBarColorAlpha: 0.4, statusBarColorAlpha: 0.4,
statusBarClickOpen: true,
scrollingDelay: 3000,// замедление, ms scrollingDelay: 3000,// замедление, ms
scrollingType: 'ease-in-out', //linear, ease, ease-in, ease-out, ease-in-out scrollingType: 'ease-in-out', //linear, ease, ease-in, ease-out, ease-in-out

1552
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "Liberama", "name": "Liberama",
"version": "0.9.0", "version": "0.9.1",
"author": "Book Pauk <bookpauk@gmail.com>", "author": "Book Pauk <bookpauk@gmail.com>",
"license": "CC0-1.0", "license": "CC0-1.0",
"repository": "bookpauk/liberama", "repository": "bookpauk/liberama",
@@ -22,7 +22,7 @@
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^6.22.1", "babel-core": "^6.22.1",
"babel-eslint": "^10.0.3", "babel-eslint": "^10.1.0",
"babel-loader": "^7.1.1", "babel-loader": "^7.1.1",
"babel-plugin-component": "^1.1.1", "babel-plugin-component": "^1.1.1",
"babel-plugin-syntax-dynamic-import": "^6.18.0", "babel-plugin-syntax-dynamic-import": "^6.18.0",
@@ -32,7 +32,6 @@
"clean-webpack-plugin": "^1.0.1", "clean-webpack-plugin": "^1.0.1",
"copy-webpack-plugin": "^5.1.1", "copy-webpack-plugin": "^5.1.1",
"css-loader": "^1.0.0", "css-loader": "^1.0.0",
"element-theme-chalk": "^2.12.0",
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-plugin-html": "^5.0.5", "eslint-plugin-html": "^5.0.5",
"eslint-plugin-node": "^8.0.0", "eslint-plugin-node": "^8.0.0",
@@ -41,27 +40,26 @@
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.5.0", "mini-css-extract-plugin": "^0.5.0",
"optimize-css-assets-webpack-plugin": "^5.0.3", "optimize-css-assets-webpack-plugin": "^5.0.3",
"pkg": "^4.4.2", "pkg": "^4.4.4",
"terser-webpack-plugin": "^1.4.1", "terser-webpack-plugin": "^1.4.1",
"url-loader": "^1.1.2", "url-loader": "^1.1.2",
"vue-class-component": "^6.3.2", "vue-class-component": "^6.3.2",
"vue-loader": "^15.7.1", "vue-loader": "^15.9.0",
"vue-style-loader": "^4.1.2", "vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10", "vue-template-compiler": "^2.6.11",
"webpack": "^4.39.3", "webpack": "^4.42.0",
"webpack-cli": "^3.3.7", "webpack-cli": "^3.3.11",
"webpack-dev-middleware": "^3.7.1", "webpack-dev-middleware": "^3.7.2",
"webpack-hot-middleware": "^2.25.0", "webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^4.2.2" "webpack-merge": "^4.2.2"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "^1.5.0", "@quasar/extras": "^1.5.2",
"appcache-webpack-plugin": "^1.4.0", "appcache-webpack-plugin": "^1.4.0",
"axios": "^0.18.1", "axios": "^0.18.1",
"base-x": "^3.0.6", "base-x": "^3.0.8",
"chardet": "^0.7.0", "chardet": "^0.7.0",
"compression": "^1.7.4", "compression": "^1.7.4",
"element-ui": "^2.12.0",
"express": "^4.17.1", "express": "^4.17.1",
"fg-loadcss": "^2.1.0", "fg-loadcss": "^2.1.0",
"fs-extra": "^7.0.1", "fs-extra": "^7.0.1",
@@ -72,21 +70,21 @@
"lodash": "^4.17.15", "lodash": "^4.17.15",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"multer": "^1.4.2", "multer": "^1.4.2",
"pako": "^1.0.10", "pako": "^1.0.11",
"path-browserify": "^1.0.0", "path-browserify": "^1.0.0",
"quasar": "^1.8.5", "quasar": "^1.9.6",
"safe-buffer": "^5.2.0", "safe-buffer": "^5.2.0",
"sjcl": "^1.0.8", "sjcl": "^1.0.8",
"sql-template-strings": "^2.2.2", "sql-template-strings": "^2.2.2",
"sqlite": "^3.0.3", "sqlite": "^3.0.3",
"tar-fs": "^2.0.0", "tar-fs": "^2.0.0",
"unbzip2-stream": "^1.3.3", "unbzip2-stream": "^1.3.3",
"vue": "github:paulkamer/vue#fix_palemoon_clickhandlers_dist", "vue": "github:bookpauk/vue",
"vue-router": "^3.1.3", "vue-router": "^3.1.6",
"vuex": "^3.1.1", "vuex": "^3.1.2",
"vuex-persistedstate": "^2.5.4", "vuex-persistedstate": "^2.7.1",
"webdav": "^2.10.1", "webdav": "^2.10.2",
"ws": "^7.2.1", "ws": "^7.2.1",
"zip-stream": "^2.1.2" "zip-stream": "^2.1.3"
} }
} }

View File

@@ -241,27 +241,29 @@ class FileDecompressor {
}); });
} }
async gzipFileIfNotExists(filename, outDir) { async gzipFileIfNotExists(filename, outDir, isMaxCompression) {
const hash = await utils.getFileHash(filename, 'sha256', 'hex'); const hash = await utils.getFileHash(filename, 'sha256', 'hex');
const outFilename = `${outDir}/${hash}`; const outFilename = `${outDir}/${hash}`;
if (!await fs.pathExists(outFilename)) { if (!await fs.pathExists(outFilename)) {
await this.gzipFile(filename, outFilename, 1); await this.gzipFile(filename, outFilename, (isMaxCompression ? 9 : 1));
// переупакуем через некоторое время на максималках // переупакуем через некоторое время на максималках, если упаковали плохо
const filenameCopy = `${filename}.copy`; if (!isMaxCompression) {
await fs.copy(filename, filenameCopy); const filenameCopy = `${filename}.copy`;
await fs.copy(filename, filenameCopy);
(async() => { (async() => {
await utils.sleep(5000); await utils.sleep(5000);
const filenameGZ = `${filename}.gz`; const filenameGZ = `${filename}.gz`;
await this.gzipFile(filenameCopy, filenameGZ, 9); await this.gzipFile(filenameCopy, filenameGZ, 9);
await fs.move(filenameGZ, outFilename, {overwrite: true}); await fs.move(filenameGZ, outFilename, {overwrite: true});
await fs.remove(filenameCopy); await fs.remove(filenameCopy);
})().catch((e) => { if (appLogger.inited) appLogger.log(LM_ERR, `FileDecompressor.gzipFileIfNotExists: ${e.message}`) }); })().catch((e) => { if (appLogger.inited) appLogger.log(LM_ERR, `FileDecompressor.gzipFileIfNotExists: ${e.message}`) });
}
} else { } else {
await utils.touchFile(outFilename); await utils.touchFile(outFilename);
} }

View File

@@ -54,6 +54,7 @@ class ReaderWorker {
let decompDir = ''; let decompDir = '';
let downloadedFilename = ''; let downloadedFilename = '';
let isUploaded = false; let isUploaded = false;
let isRestored = false;
let convertFilename = ''; let convertFilename = '';
const overLoadMes = 'Слишком большая очередь загрузки. Пожалуйста, попробуйте позже.'; const overLoadMes = 'Слишком большая очередь загрузки. Пожалуйста, попробуйте позже.';
@@ -88,9 +89,17 @@ class ReaderWorker {
downloadedFilename = `${this.config.tempDownloadDir}/${tempFilename}`; downloadedFilename = `${this.config.tempDownloadDir}/${tempFilename}`;
await fs.writeFile(downloadedFilename, downdata); await fs.writeFile(downloadedFilename, downdata);
} else {//uploaded file } else {//uploaded file
downloadedFilename = `${this.config.uploadDir}/${url.substr(7)}`; const fileHash = url.substr(7);
if (!await fs.pathExists(downloadedFilename)) downloadedFilename = `${this.config.uploadDir}/${fileHash}`;
throw new Error('Файл не найден на сервере (возможно был удален как устаревший). Пожалуйста, загрузите файл с диска на сервер заново.'); if (!await fs.pathExists(downloadedFilename)) {
//если удалено из upload, попробуем восстановить из удаленного хранилища
try {
downloadedFilename = await this.restoreRemoteFile(fileHash);
isRestored = true;
} catch(e) {
throw new Error('Файл не найден на сервере (возможно был удален как устаревший). Пожалуйста, загрузите файл с диска на сервер заново.');
}
}
await utils.touchFile(downloadedFilename); await utils.touchFile(downloadedFilename);
isUploaded = true; isUploaded = true;
} }
@@ -146,6 +155,20 @@ class ReaderWorker {
})(); })();
} }
//лениво сохраним downloadedFilename в tmp и в удаленном хранилище в случае isUploaded
if (this.remoteWebDavStorage && isUploaded && !isRestored) {
(async() => {
await utils.sleep(30*1000);
try {
//сжимаем файл в tmp, если там уже нет с тем же именем-sha256
const compDownloadedFilename = await this.decomp.gzipFileIfNotExists(downloadedFilename, this.config.tempPublicDir, true);
await this.remoteWebDavStorage.putFile(compDownloadedFilename);
} catch (e) {
log(LM_ERR, e.stack);
}
})();
}
} catch (e) { } catch (e) {
log(LM_ERR, e.stack); log(LM_ERR, e.stack);
if (e.message == 'abort') if (e.message == 'abort')
@@ -188,6 +211,24 @@ class ReaderWorker {
return `file://${hash}`; return `file://${hash}`;
} }
async restoreRemoteFile(filename) {
const basename = path.basename(filename);
const targetName = `${this.config.tempPublicDir}/${basename}`;
if (!await fs.pathExists(targetName)) {
let found = false;
if (this.remoteWebDavStorage) {
found = await this.remoteWebDavStorage.getFileSuccess(targetName);
}
if (!found) {
throw new Error('404 Файл не найден');
}
}
return targetName;
}
restoreCachedFile(filename) { restoreCachedFile(filename) {
const workerId = this.workerState.generateWorkerId(); const workerId = this.workerState.generateWorkerId();
const wState = this.workerState.getControl(workerId); const wState = this.workerState.getControl(workerId);
@@ -197,21 +238,10 @@ class ReaderWorker {
try { try {
wState.set({state: 'download', step: 1, totalSteps: 1, path: filename, progress: 0}); wState.set({state: 'download', step: 1, totalSteps: 1, path: filename, progress: 0});
const basename = path.basename(filename); const targetName = await this.restoreRemoteFile(filename);
const targetName = `${this.config.tempPublicDir}/${basename}`;
if (!await fs.pathExists(targetName)) {
let found = false;
if (this.remoteWebDavStorage) {
found = await this.remoteWebDavStorage.getFileSuccess(targetName);
}
if (!found) {
throw new Error('404 Файл не найден');
}
}
const stat = await fs.stat(targetName); const stat = await fs.stat(targetName);
const basename = path.basename(filename);
wState.finish({path: `/tmp/${basename}`, size: stat.size, progress: 100}); wState.finish({path: `/tmp/${basename}`, size: stat.size, progress: 100});
} catch (e) { } catch (e) {
if (e.message.indexOf('404') < 0) if (e.message.indexOf('404') < 0)