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="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="label-6">Парам. в URL</div>
<q-checkbox size="xs" v-model="allowUrlParamBookPos">
@@ -68,18 +96,6 @@
</q-checkbox>
</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="label-6">Копирование</div>
<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"/>
</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"/>
</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="label-2">Изображения</div>
<div class="col row">

View File

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

View File

@@ -1,4 +1,16 @@
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',
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/fontawesome-v5/fontawesome-v5.css';
//import '@quasar/extras/material-icons-outlined/material-icons-outlined.css';
import '@quasar/extras/line-awesome/line-awesome.css';
//import fontawesomeV5 from 'quasar/icon-set/fontawesome-v5.js'

View File

@@ -160,6 +160,7 @@ const settingDefaults = {
statusBarTop: false,// top, bottom
statusBarHeight: 19,// px
statusBarColorAlpha: 0.4,
statusBarClickOpen: true,
scrollingDelay: 3000,// замедление, ms
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",
"version": "0.9.0",
"version": "0.9.1",
"author": "Book Pauk <bookpauk@gmail.com>",
"license": "CC0-1.0",
"repository": "bookpauk/liberama",
@@ -22,7 +22,7 @@
},
"devDependencies": {
"babel-core": "^6.22.1",
"babel-eslint": "^10.0.3",
"babel-eslint": "^10.1.0",
"babel-loader": "^7.1.1",
"babel-plugin-component": "^1.1.1",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
@@ -32,7 +32,6 @@
"clean-webpack-plugin": "^1.0.1",
"copy-webpack-plugin": "^5.1.1",
"css-loader": "^1.0.0",
"element-theme-chalk": "^2.12.0",
"eslint": "^5.16.0",
"eslint-plugin-html": "^5.0.5",
"eslint-plugin-node": "^8.0.0",
@@ -41,27 +40,26 @@
"html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.5.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"pkg": "^4.4.2",
"pkg": "^4.4.4",
"terser-webpack-plugin": "^1.4.1",
"url-loader": "^1.1.2",
"vue-class-component": "^6.3.2",
"vue-loader": "^15.7.1",
"vue-loader": "^15.9.0",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.7",
"webpack-dev-middleware": "^3.7.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-middleware": "^3.7.2",
"webpack-hot-middleware": "^2.25.0",
"webpack-merge": "^4.2.2"
},
"dependencies": {
"@quasar/extras": "^1.5.0",
"@quasar/extras": "^1.5.2",
"appcache-webpack-plugin": "^1.4.0",
"axios": "^0.18.1",
"base-x": "^3.0.6",
"base-x": "^3.0.8",
"chardet": "^0.7.0",
"compression": "^1.7.4",
"element-ui": "^2.12.0",
"express": "^4.17.1",
"fg-loadcss": "^2.1.0",
"fs-extra": "^7.0.1",
@@ -72,21 +70,21 @@
"lodash": "^4.17.15",
"minimist": "^1.2.0",
"multer": "^1.4.2",
"pako": "^1.0.10",
"pako": "^1.0.11",
"path-browserify": "^1.0.0",
"quasar": "^1.8.5",
"quasar": "^1.9.6",
"safe-buffer": "^5.2.0",
"sjcl": "^1.0.8",
"sql-template-strings": "^2.2.2",
"sqlite": "^3.0.3",
"tar-fs": "^2.0.0",
"unbzip2-stream": "^1.3.3",
"vue": "github:paulkamer/vue#fix_palemoon_clickhandlers_dist",
"vue-router": "^3.1.3",
"vuex": "^3.1.1",
"vuex-persistedstate": "^2.5.4",
"webdav": "^2.10.1",
"vue": "github:bookpauk/vue",
"vue-router": "^3.1.6",
"vuex": "^3.1.2",
"vuex-persistedstate": "^2.7.1",
"webdav": "^2.10.2",
"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 outFilename = `${outDir}/${hash}`;
if (!await fs.pathExists(outFilename)) {
await this.gzipFile(filename, outFilename, 1);
await this.gzipFile(filename, outFilename, (isMaxCompression ? 9 : 1));
// переупакуем через некоторое время на максималках
const filenameCopy = `${filename}.copy`;
await fs.copy(filename, filenameCopy);
// переупакуем через некоторое время на максималках, если упаковали плохо
if (!isMaxCompression) {
const filenameCopy = `${filename}.copy`;
await fs.copy(filename, filenameCopy);
(async() => {
await utils.sleep(5000);
const filenameGZ = `${filename}.gz`;
await this.gzipFile(filenameCopy, filenameGZ, 9);
(async() => {
await utils.sleep(5000);
const filenameGZ = `${filename}.gz`;
await this.gzipFile(filenameCopy, filenameGZ, 9);
await fs.move(filenameGZ, outFilename, {overwrite: true});
await fs.move(filenameGZ, outFilename, {overwrite: true});
await fs.remove(filenameCopy);
})().catch((e) => { if (appLogger.inited) appLogger.log(LM_ERR, `FileDecompressor.gzipFileIfNotExists: ${e.message}`) });
await fs.remove(filenameCopy);
})().catch((e) => { if (appLogger.inited) appLogger.log(LM_ERR, `FileDecompressor.gzipFileIfNotExists: ${e.message}`) });
}
} else {
await utils.touchFile(outFilename);
}

View File

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