Compare commits
1 Commits
master
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
34437310f2 |
@@ -115,10 +115,6 @@ Options:
|
|||||||
|
|
||||||
// Подключение себя, как клиента, к серверу обновлений
|
// Подключение себя, как клиента, к серверу обновлений
|
||||||
"bucServer": false
|
"bucServer": false
|
||||||
|
|
||||||
// Сcылка для открытия в новом окне брауpера по клику на кнопку "Сетевая библиотека"
|
|
||||||
// Если не задано, открывается внутренний менеджер библиотек с использванием фрейма
|
|
||||||
"networkLibraryLink": "http://samlib.ru/"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import wsc from './webSocketConnection';
|
import wsc from './webSocketConnection';
|
||||||
|
|
||||||
class Misc {
|
class Misc {
|
||||||
async loadConfig(_configHash) {
|
async loadConfig() {
|
||||||
|
|
||||||
const query = {
|
const query = {params: [
|
||||||
params: [
|
'name', 'version', 'mode', 'maxUploadFileSize', 'useExternalBookConverter', 'acceptFileExt', 'bucEnabled', 'branch',
|
||||||
'name', 'version', 'mode', 'maxUploadFileSize', 'useExternalBookConverter',
|
]};
|
||||||
'acceptFileExt', 'bucEnabled', 'branch', 'networkLibraryLink', 'restricted'
|
|
||||||
],
|
|
||||||
_configHash,
|
|
||||||
};
|
|
||||||
|
|
||||||
const config = await wsc.message(await wsc.send(Object.assign({action: 'get-config'}, query)));
|
const config = await wsc.message(await wsc.send(Object.assign({action: 'get-config'}, query)));
|
||||||
if (config.error)
|
if (config.error)
|
||||||
|
|||||||
@@ -154,11 +154,8 @@ class App {
|
|||||||
(async() => {
|
(async() => {
|
||||||
//загрузим конфиг сервера
|
//загрузим конфиг сервера
|
||||||
try {
|
try {
|
||||||
const config = await miscApi.loadConfig(this.config._configHash);
|
const config = await miscApi.loadConfig();
|
||||||
|
this.commit('config/setConfig', config);
|
||||||
if (!config._useCached)
|
|
||||||
this.commit('config/setConfig', config);
|
|
||||||
|
|
||||||
this.showPage = true;
|
this.showPage = true;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
//проверим, не получен ли конфиг ранее
|
//проверим, не получен ли конфиг ранее
|
||||||
|
|||||||
@@ -52,21 +52,18 @@ class CopyTextPage {
|
|||||||
from = (from < 0 ? 0 : from);
|
from = (from < 0 ? 0 : from);
|
||||||
to = paraIndex + 100;
|
to = paraIndex + 100;
|
||||||
to = (to > parsed.para.length ? parsed.para.length : to);
|
to = (to > parsed.para.length ? parsed.para.length : to);
|
||||||
cut = '<dd>..... Текст вырезан. Если хотите скопировать больше, поставьте в настройках галочку "Загружать весь текст"';
|
cut = '<p>..... Текст вырезан. Если хотите скопировать больше, поставьте в настройках галочку "Загружать весь текст"';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (from > 0)
|
if (from > 0)
|
||||||
text += cut;
|
text += cut;
|
||||||
for (let i = from; i < to; i++) {
|
for (let i = from; i < to; i++) {
|
||||||
const p = parsed.para[i];
|
const p = parsed.para[i];
|
||||||
if (p.addIndex > 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const parts = parsed.splitToStyle(p.text);
|
const parts = parsed.splitToStyle(p.text);
|
||||||
if (this.stopInit)
|
if (this.stopInit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
text += `<dd id="p${i}" class="copyPara"> `;
|
text += `<p id="p${i}" class="copyPara">`;
|
||||||
for (const part of parts)
|
for (const part of parts)
|
||||||
text += part.text;
|
text += part.text;
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const tabs = [
|
|||||||
['MouseHelpPage', 'Мышь/тачскрин'],
|
['MouseHelpPage', 'Мышь/тачскрин'],
|
||||||
['HotkeysHelpPage', 'Клавиатура'],
|
['HotkeysHelpPage', 'Клавиатура'],
|
||||||
['VersionHistoryPage', 'История версий'],
|
['VersionHistoryPage', 'История версий'],
|
||||||
//['DonateHelpPage', 'Помочь проекту'],
|
['DonateHelpPage', 'Помочь проекту'],
|
||||||
];
|
];
|
||||||
|
|
||||||
const componentOptions = {
|
const componentOptions = {
|
||||||
|
|||||||
@@ -770,10 +770,6 @@ class Reader {
|
|||||||
return this.$store.state.config.bucEnabled && this.bucEnabled;
|
return this.$store.state.config.bucEnabled && this.bucEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
get restricted() {
|
|
||||||
return this.$store.state.config.restricted;
|
|
||||||
}
|
|
||||||
|
|
||||||
get routeParamUrl() {
|
get routeParamUrl() {
|
||||||
let result = '';
|
let result = '';
|
||||||
const path = this.$route.fullPath;
|
const path = this.$route.fullPath;
|
||||||
@@ -1036,11 +1032,6 @@ class Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
libsToogle() {
|
libsToogle() {
|
||||||
if (this.config.networkLibraryLink) {
|
|
||||||
window.open(this.config.networkLibraryLink, '_blank');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.libsActive = !this.libsActive;
|
this.libsActive = !this.libsActive;
|
||||||
if (this.libsActive) {
|
if (this.libsActive) {
|
||||||
this.$refs.libsPage.init();//no await
|
this.$refs.libsPage.init();//no await
|
||||||
@@ -1267,19 +1258,6 @@ class Reader {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
isUrlAllowed(url) {
|
|
||||||
const restrictedSites = this.restricted?.sites;
|
|
||||||
if (restrictedSites) {
|
|
||||||
url = url.toLowerCase();
|
|
||||||
for (const site of restrictedSites) {
|
|
||||||
if (url.indexOf(site) === 0)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _loadBook(opts) {
|
async _loadBook(opts) {
|
||||||
if (!opts || !opts.url) {
|
if (!opts || !opts.url) {
|
||||||
this.mostRecentBook();
|
this.mostRecentBook();
|
||||||
@@ -1290,11 +1268,6 @@ class Reader {
|
|||||||
|
|
||||||
let url = encodeURI(decodeURI(opts.url));
|
let url = encodeURI(decodeURI(opts.url));
|
||||||
|
|
||||||
if (!this.isUrlAllowed(url)) {
|
|
||||||
this.$root.stdDialog.alert('Книга не загружена, причина: нарушение авторских прав.<br>Приносим извинения за неудобство.', '', {color: 'negative'});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((url.indexOf('http://') != 0) && (url.indexOf('https://') != 0) &&
|
if ((url.indexOf('http://') != 0) && (url.indexOf('https://') != 0) &&
|
||||||
(url.indexOf('disk://') != 0))
|
(url.indexOf('disk://') != 0))
|
||||||
url = 'http://' + url;
|
url = 'http://' + url;
|
||||||
@@ -1406,7 +1379,6 @@ class Reader {
|
|||||||
found = (found ? _.cloneDeep(found) : found);
|
found = (found ? _.cloneDeep(found) : found);
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
//если такой файл уже не загружен (path не совпадают)
|
|
||||||
if (wasOpened.sameBookKey != found.sameBookKey) {
|
if (wasOpened.sameBookKey != found.sameBookKey) {
|
||||||
//спрашиваем, надо ли объединить файлы
|
//спрашиваем, надо ли объединить файлы
|
||||||
const askResult = bookManager.keysEqual(found.path, addedBook.path) ||
|
const askResult = bookManager.keysEqual(found.path, addedBook.path) ||
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class ReaderDialogs {
|
|||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
await this.showWhatsNew();
|
await this.showWhatsNew();
|
||||||
//await this.showDonation();
|
await this.showDonation();
|
||||||
}
|
}
|
||||||
|
|
||||||
loadSettings() {
|
loadSettings() {
|
||||||
|
|||||||
@@ -201,7 +201,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
class="del-button self-end row justify-center items-center clickable"
|
class="del-button self-end row justify-center items-center clickable"
|
||||||
@click="handleDel(item)"
|
@click="handleDel(item.key)"
|
||||||
>
|
>
|
||||||
<q-icon class="la la-times" size="12px" />
|
<q-icon class="la la-times" size="12px" />
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
<div
|
<div
|
||||||
v-show="showArchive"
|
v-show="showArchive"
|
||||||
class="restore-button self-start row justify-center items-center clickable"
|
class="restore-button self-start row justify-center items-center clickable"
|
||||||
@click="handleRestore(item)"
|
@click="handleRestore(item.key)"
|
||||||
>
|
>
|
||||||
<q-icon class="la la-arrow-left" size="14px" />
|
<q-icon class="la la-arrow-left" size="14px" />
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
||||||
@@ -593,51 +593,26 @@ class RecentBooksPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleDel(item) {
|
async handleDel(key) {
|
||||||
if (item.group?.length) {
|
if (!this.showArchive) {
|
||||||
const keys = [{key: item.key}];
|
await bookManager.delRecentBook({key});
|
||||||
for (const book of item.group)
|
this.$root.notify.info('Перенесено в архив');
|
||||||
keys.push({key: book.key});
|
|
||||||
|
|
||||||
if (!this.showArchive) {
|
|
||||||
await bookManager.delRecentBooks(keys);
|
|
||||||
this.$root.notify.info(`Группа книг (всего ${keys.length}) перенесена в архив`);
|
|
||||||
} else {
|
|
||||||
if (await this.$root.stdDialog.confirm(`Подтвердите удаление группы книг (всего ${keys.length}) из архива:`, ' ')) {
|
|
||||||
await bookManager.delRecentBooks(keys, 2);
|
|
||||||
this.$root.notify.info('Группа книг удалена безвозвратно');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (!this.showArchive) {
|
if (await this.$root.stdDialog.confirm('Подтвердите удаление из архива:', ' ')) {
|
||||||
await bookManager.delRecentBooks([{key: item.key}]);
|
await bookManager.delRecentBook({key}, 2);
|
||||||
this.$root.notify.info('Книга перенесена в архив');
|
this.$root.notify.info('Удалено безвозвратно');
|
||||||
} else {
|
|
||||||
if (await this.$root.stdDialog.confirm('Подтвердите удаление книги из архива:', ' ')) {
|
|
||||||
await bookManager.delRecentBooks([{key: item.key}], 2);
|
|
||||||
this.$root.notify.info('Книга удалена безвозвратно');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleRestore(item) {
|
async handleRestore(key) {
|
||||||
if (item.group?.length) {
|
await bookManager.restoreRecentBook({key});
|
||||||
const keys = [{key: item.key}];
|
this.$root.notify.info('Восстановлено из архива');
|
||||||
for (const book of item.group)
|
|
||||||
keys.push({key: book.key});
|
|
||||||
|
|
||||||
await bookManager.restoreRecentBooks(keys);
|
|
||||||
this.$root.notify.info(`Группа книг (всего ${keys.length}) восстановлена из архива`);
|
|
||||||
} else {
|
|
||||||
await bookManager.restoreRecentBooks([{key: item.key}]);
|
|
||||||
this.$root.notify.info('Книга восстановлена из архива');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadBook(item, force = false) {
|
async loadBook(item, force = false) {
|
||||||
if (item.deleted)
|
if (item.deleted)
|
||||||
await this.handleRestore(item);
|
await this.handleRestore(item.key);
|
||||||
|
|
||||||
this.$emit('load-book', {url: item.url, path: item.path, force});
|
this.$emit('load-book', {url: item.url, path: item.path, force});
|
||||||
this.close();
|
this.close();
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--div class="sets-item row">
|
<div class="sets-item row">
|
||||||
<div class="sets-label label">
|
<div class="sets-label label">
|
||||||
Уведомление
|
Уведомление
|
||||||
</div>
|
</div>
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
Показывать диалог для сбора пожертвований
|
Показывать диалог для сбора пожертвований
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div-->
|
</div>
|
||||||
|
|
||||||
<!---------------------------------------------->
|
<!---------------------------------------------->
|
||||||
<div class="sets-part-header">
|
<div class="sets-part-header">
|
||||||
|
|||||||
@@ -14,11 +14,6 @@ export default class DrawHelper {
|
|||||||
return this.context.measureText(text).width;
|
return this.context.measureText(text).width;
|
||||||
}
|
}
|
||||||
|
|
||||||
measureTextMetrics(text, style) {// eslint-disable-line no-unused-vars
|
|
||||||
this.context.font = this.fontByStyle(style);
|
|
||||||
return this.context.measureText(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
measureTextFont(text, font) {// eslint-disable-line no-unused-vars
|
measureTextFont(text, font) {// eslint-disable-line no-unused-vars
|
||||||
this.context.font = font;
|
this.context.font = font;
|
||||||
return this.context.measureText(text).width;
|
return this.context.measureText(text).width;
|
||||||
@@ -51,22 +46,7 @@ export default class DrawHelper {
|
|||||||
tOpen += (part.style.italic ? '<i>' : '');
|
tOpen += (part.style.italic ? '<i>' : '');
|
||||||
tOpen += (part.style.sup ? '<span style="vertical-align: baseline; position: relative; line-height: 0; top: -0.3em">' : '');
|
tOpen += (part.style.sup ? '<span style="vertical-align: baseline; position: relative; line-height: 0; top: -0.3em">' : '');
|
||||||
tOpen += (part.style.sub ? '<span style="vertical-align: baseline; position: relative; line-height: 0; top: 0.3em">' : '');
|
tOpen += (part.style.sub ? '<span style="vertical-align: baseline; position: relative; line-height: 0; top: 0.3em">' : '');
|
||||||
if (part.style.note) {
|
|
||||||
const t = part.text;
|
|
||||||
const m = this.measureTextMetrics(t, part.style);
|
|
||||||
const d = this.fontSize - 1.1*m.fontBoundingBoxAscent;
|
|
||||||
const w = m.width;
|
|
||||||
const size = (this.fontSize > 18 ? this.fontSize : 18);
|
|
||||||
const pad = size/2;
|
|
||||||
const btnW = (w >= size ? w : size) + pad*2;
|
|
||||||
|
|
||||||
tOpen += `<span style="position: relative;">` +
|
|
||||||
`<span style="position: absolute; background-color: ${this.textColor}; opacity: 0.1; cursor: pointer; pointer-events: auto; ` +
|
|
||||||
`height: ${this.fontSize + pad*2}px; padding: ${pad}px; left: -${(btnW - w)/2 - pad*0.05}px; top: -${pad + d}px; width: ${btnW}px; border-radius: ${size}px;" ` +
|
|
||||||
`onclick="onNoteClickLiberama('${part.style.note.id}', ${part.style.note.orig ? 1 : 0})"><span style="visibility: hidden;" class="dborder">${t}</span></span>`;
|
|
||||||
}
|
|
||||||
let tClose = '';
|
let tClose = '';
|
||||||
tClose += (part.style.note ? '</span>' : '');
|
|
||||||
tClose += (part.style.sub ? '</span>' : '');
|
tClose += (part.style.sub ? '</span>' : '');
|
||||||
tClose += (part.style.sup ? '</span>' : '');
|
tClose += (part.style.sup ? '</span>' : '');
|
||||||
tClose += (part.style.italic ? '</i>' : '');
|
tClose += (part.style.italic ? '</i>' : '');
|
||||||
|
|||||||
@@ -4,30 +4,34 @@
|
|||||||
<div class="absolute" v-html="background"></div>
|
<div class="absolute" v-html="background"></div>
|
||||||
<div class="absolute" v-html="pageDivider"></div>
|
<div class="absolute" v-html="pageDivider"></div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="scrollBox1" class="scroll-box layout over-hidden" @wheel.prevent.stop="onMouseWheel">
|
<div ref="scrollBox1" class="layout over-hidden" @wheel.prevent.stop="onMouseWheel">
|
||||||
<div ref="scrollingPage1" class="layout over-hidden" @transitionend="onPage1TransitionEnd" @animationend="onPage1AnimationEnd">
|
<div ref="scrollingPage1" class="layout over-hidden" @transitionend="onPage1TransitionEnd" @animationend="onPage1AnimationEnd">
|
||||||
<div @copy.prevent="copyText" v-html="page1"></div>
|
<div @copy.prevent="copyText" v-html="page1"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div ref="scrollBox2" class="scroll-box layout over-hidden" @wheel.prevent.stop="onMouseWheel">
|
<div ref="scrollBox2" class="layout over-hidden" @wheel.prevent.stop="onMouseWheel">
|
||||||
<div ref="scrollingPage2" class="layout over-hidden" @transitionend="onPage2TransitionEnd" @animationend="onPage2AnimationEnd">
|
<div ref="scrollingPage2" class="layout over-hidden" @transitionend="onPage2TransitionEnd" @animationend="onPage2AnimationEnd">
|
||||||
<div @copy.prevent="copyText" v-html="page2"></div>
|
<div @copy.prevent="copyText" v-html="page2"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="showStatusBar" ref="statusBar" class="layout" :class="{'no-events': clickControl}">
|
<div v-show="showStatusBar" ref="statusBar" class="layout">
|
||||||
<div v-html="statusBar"></div>
|
<div v-html="statusBar"></div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="clickControl" ref="layoutEvents" class="layout events"
|
v-show="clickControl" ref="layoutEvents" class="layout events"
|
||||||
oncontextmenu="return false;"
|
oncontextmenu="return false;"
|
||||||
@mousedown.prevent.stop="onMouseDown" @mouseup.prevent.stop="onMouseUp"
|
@mousedown.prevent.stop="onMouseDown" @mouseup.prevent.stop="onMouseUp"
|
||||||
@mouseover.prevent.stop="onMouseEvent" @mouseout.prevent.stop="onMouseEvent" @mousemove.prevent.stop="onMouseEvent"
|
|
||||||
@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"
|
||||||
>
|
>
|
||||||
|
<div
|
||||||
|
v-show="showStatusBar && statusBarClickOpen" @mousedown.prevent.stop @touchstart.stop
|
||||||
|
@click.prevent.stop="onStatusBarClick"
|
||||||
|
v-html="statusBarClickable"
|
||||||
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-show="showStatusBar && statusBarClickOpen" class="layout"
|
v-show="!clickControl && showStatusBar && statusBarClickOpen" class="layout"
|
||||||
@mousedown.prevent.stop @touchstart.stop
|
@mousedown.prevent.stop @touchstart.stop
|
||||||
@click.prevent.stop="onStatusBarClick"
|
@click.prevent.stop="onStatusBarClick"
|
||||||
v-html="statusBarClickable"
|
v-html="statusBarClickable"
|
||||||
@@ -36,29 +40,6 @@
|
|||||||
<!-- невидимым делать нельзя (display: none), вовремя не подгружаютя шрифты -->
|
<!-- невидимым делать нельзя (display: none), вовремя не подгружаютя шрифты -->
|
||||||
<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>
|
||||||
|
|
||||||
<!-- Примечание -->
|
|
||||||
<Dialog ref="dialog1" v-model="noteDialogVisible">
|
|
||||||
<template #header>
|
|
||||||
{{ noteTitle }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="column col" style="line-height: 20px; max-width: 400px; max-height: 200px; overflow-x: hidden; overflow-y: auto">
|
|
||||||
<div v-html="noteHtml"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template #footer>
|
|
||||||
<div class="row col">
|
|
||||||
<q-btn class="q-px-md q-mr-md" color="btn2" text-color="app" dense no-caps @click="goToNotes">
|
|
||||||
В примечания
|
|
||||||
</q-btn>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<q-btn class="q-px-md" color="btn2" text-color="app" dense no-caps @click="noteDialogVisible = false">
|
|
||||||
OK
|
|
||||||
</q-btn>
|
|
||||||
</template>
|
|
||||||
</Dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -70,7 +51,6 @@ import {loadCSS} from 'fg-loadcss';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import he from 'he';
|
import he from 'he';
|
||||||
|
|
||||||
import Dialog from '../../share/Dialog.vue';
|
|
||||||
import './TextPage.css';
|
import './TextPage.css';
|
||||||
|
|
||||||
import * as utils from '../../../share/utils';
|
import * as utils from '../../../share/utils';
|
||||||
@@ -82,19 +62,7 @@ import {clickMap} from '../share/clickMap';
|
|||||||
|
|
||||||
const minLayoutWidth = 100;
|
const minLayoutWidth = 100;
|
||||||
|
|
||||||
//обработчик кликов по примечаниям, см. DrawHelper
|
|
||||||
//коряво, но иначе придется сильно усложнять рендеринг страниц (через Vue)
|
|
||||||
window.onNoteClickLiberama = (noteId, orig) => {
|
|
||||||
const textPage = window.textPageLiberama;
|
|
||||||
if (textPage) {
|
|
||||||
textPage.showNote(noteId, orig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentOptions = {
|
const componentOptions = {
|
||||||
components: {
|
|
||||||
Dialog
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
bookPos: function() {
|
bookPos: function() {
|
||||||
this.$emit('book-pos-changed', {bookPos: this.bookPos, bookPosSeen: this.bookPosSeen});
|
this.$emit('book-pos-changed', {bookPos: this.bookPos, bookPosSeen: this.bookPosSeen});
|
||||||
@@ -122,7 +90,6 @@ class TextPage {
|
|||||||
_options = componentOptions;
|
_options = componentOptions;
|
||||||
|
|
||||||
showStatusBar = false;
|
showStatusBar = false;
|
||||||
statusBarClickOpen = false;
|
|
||||||
clickControl = true;
|
clickControl = true;
|
||||||
|
|
||||||
background = null;
|
background = null;
|
||||||
@@ -147,11 +114,6 @@ class TextPage {
|
|||||||
|
|
||||||
meta = null;
|
meta = null;
|
||||||
|
|
||||||
noteDialogVisible = false;
|
|
||||||
noteId = '';
|
|
||||||
noteTitle = '';
|
|
||||||
noteHtml = '';
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.drawHelper = new DrawHelper();
|
this.drawHelper = new DrawHelper();
|
||||||
|
|
||||||
@@ -191,8 +153,6 @@ class TextPage {
|
|||||||
await utils.sleep(200);
|
await utils.sleep(200);
|
||||||
this.$nextTick(this.onResize);
|
this.$nextTick(this.onResize);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.textPageLiberama = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -337,8 +297,6 @@ class TextPage {
|
|||||||
top += this.statusBarHeight*(this.statusBarTop ? 1 : 0);
|
top += this.statusBarHeight*(this.statusBarTop ? 1 : 0);
|
||||||
let page1 = this.$refs.scrollBox1.style;
|
let page1 = this.$refs.scrollBox1.style;
|
||||||
let page2 = this.$refs.scrollBox2.style;
|
let page2 = this.$refs.scrollBox2.style;
|
||||||
|
|
||||||
page1.pointerEvents = page2.pointerEvents = (this.clickControl ? 'none' : 'auto');
|
|
||||||
|
|
||||||
page1.perspective = page2.perspective = '3072px';
|
page1.perspective = page2.perspective = '3072px';
|
||||||
|
|
||||||
@@ -955,22 +913,6 @@ class TextPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doPara(paraIndex) {
|
|
||||||
const para = this.parsed.para[paraIndex];
|
|
||||||
|
|
||||||
if (para && this.pageLineCount > 0) {
|
|
||||||
const lines = this.parsed.getLines(para.offset, this.pageLineCount);
|
|
||||||
|
|
||||||
if (lines.length >= this.pageLineCount) {
|
|
||||||
this.currentAnimation = this.pageChangeAnimation;
|
|
||||||
this.pageChangeDirectionDown = true;
|
|
||||||
this.userBookPosChange = true;
|
|
||||||
this.bookPos = lines[0].begin;
|
|
||||||
} else
|
|
||||||
this.doEnd();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
doToolBarToggle(event) {
|
doToolBarToggle(event) {
|
||||||
this.$emit('do-action', {action: 'switchToolbar', event});
|
this.$emit('do-action', {action: 'switchToolbar', event});
|
||||||
}
|
}
|
||||||
@@ -1074,7 +1016,6 @@ class TextPage {
|
|||||||
if (this.startTouch) {
|
if (this.startTouch) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
this.endClickRepeat();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onTouchEnd(event) {
|
onTouchEnd(event) {
|
||||||
@@ -1159,9 +1100,6 @@ class TextPage {
|
|||||||
onMouseWheel(event) {
|
onMouseWheel(event) {
|
||||||
if (this.$root.isMobileDevice)
|
if (this.$root.isMobileDevice)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.endClickRepeat();
|
|
||||||
|
|
||||||
if (event.deltaY > 0) {
|
if (event.deltaY > 0) {
|
||||||
this.doDown();
|
this.doDown();
|
||||||
} else if (event.deltaY < 0) {
|
} else if (event.deltaY < 0) {
|
||||||
@@ -1169,12 +1107,6 @@ class TextPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseEvent() {
|
|
||||||
if (this.$root.isMobileDevice)
|
|
||||||
return;
|
|
||||||
this.endClickRepeat();
|
|
||||||
}
|
|
||||||
|
|
||||||
onStatusBarClick() {
|
onStatusBarClick() {
|
||||||
const url = this.meta.url;
|
const url = this.meta.url;
|
||||||
if (url && url.indexOf('disk://') != 0) {
|
if (url && url.indexOf('disk://') != 0) {
|
||||||
@@ -1277,43 +1209,6 @@ class TextPage {
|
|||||||
|
|
||||||
event.clipboardData.setData('text/plain', filtered);
|
event.clipboardData.setData('text/plain', filtered);
|
||||||
}
|
}
|
||||||
|
|
||||||
showNote(noteId, orig) {
|
|
||||||
const note = this.parsed.notes[noteId];
|
|
||||||
if (note) {
|
|
||||||
if (orig) {//show dialog
|
|
||||||
this.noteId = noteId;
|
|
||||||
this.noteTitle = `[${note.title?.trim()}]`;
|
|
||||||
this.noteHtml = note.xml
|
|
||||||
.replace(/<p>/g, '<p class="note-para">')
|
|
||||||
.replace(/<stanza>/g, '<br>').replace(/<\/stanza>/g, '')
|
|
||||||
.replace(/<v>/g, '<p style="margin: 0">').replace(/<\/v>/g, '</p>')
|
|
||||||
.replace(/<emphasis>/g, '<em>').replace(/<\/emphasis>/g, '</em>')
|
|
||||||
.replace(/<text-author>/g, '<br>').replace(/<\/text-author>/g, '')
|
|
||||||
;
|
|
||||||
|
|
||||||
this.noteDialogVisible = true;
|
|
||||||
} else {//go to orig
|
|
||||||
this.goToOrigNote(noteId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goToNotes() {
|
|
||||||
const note = this.parsed.notes[this.noteId];
|
|
||||||
if (note && note.noteParaIndex >= 0) {
|
|
||||||
this.doPara(note.noteParaIndex);
|
|
||||||
this.noteDialogVisible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
goToOrigNote(noteId) {
|
|
||||||
const note = this.parsed.notes[noteId];
|
|
||||||
if (note && note.linkParaIndex >= 0) {
|
|
||||||
this.doPara(note.linkParaIndex);
|
|
||||||
this.noteDialogVisible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default vueComponent(TextPage);
|
export default vueComponent(TextPage);
|
||||||
@@ -1349,18 +1244,8 @@ export default vueComponent(TextPage);
|
|||||||
}
|
}
|
||||||
|
|
||||||
.events {
|
.events {
|
||||||
z-index: 9;
|
z-index: 20;
|
||||||
background-color: rgba(0,0,0,0);
|
background-color: rgba(0,0,0,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-events {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
<style>
|
|
||||||
.note-para {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -86,24 +86,17 @@ export default class BookParser {
|
|||||||
let binaryType = '';
|
let binaryType = '';
|
||||||
let dimPromises = [];
|
let dimPromises = [];
|
||||||
this.coverPageId = '';
|
this.coverPageId = '';
|
||||||
this.images = [];
|
|
||||||
let imageNum = 0;
|
|
||||||
|
|
||||||
//примечания
|
|
||||||
this.notes = {};
|
|
||||||
let inNote = false;
|
|
||||||
let noteId = '';
|
|
||||||
let inNotesBody = false;
|
|
||||||
const noteTags = new Set(['p', 'poem', 'stanza', 'v', 'text-author', 'emphasis']);
|
|
||||||
|
|
||||||
//оглавление
|
//оглавление
|
||||||
this.contents = [];
|
this.contents = [];
|
||||||
|
this.images = [];
|
||||||
let curTitle = {paraIndex: -1, title: '', subtitles: []};
|
let curTitle = {paraIndex: -1, title: '', subtitles: []};
|
||||||
let curSubtitle = {paraIndex: -1, title: ''};
|
let curSubtitle = {paraIndex: -1, title: ''};
|
||||||
let inTitle = false;
|
let inTitle = false;
|
||||||
let inSubtitle = false;
|
let inSubtitle = false;
|
||||||
let sectionLevel = 0;
|
let sectionLevel = 0;
|
||||||
let bodyIndex = 0;
|
let bodyIndex = 0;
|
||||||
|
let imageNum = 0;
|
||||||
|
|
||||||
let paraIndex = -1;
|
let paraIndex = -1;
|
||||||
let paraOffset = 0;
|
let paraOffset = 0;
|
||||||
@@ -296,7 +289,7 @@ export default class BookParser {
|
|||||||
if (attrs.href && attrs.href.value) {
|
if (attrs.href && attrs.href.value) {
|
||||||
const href = attrs.href.value;
|
const href = attrs.href.value;
|
||||||
const alt = (attrs.alt && attrs.alt.value ? attrs.alt.value : '');
|
const alt = (attrs.alt && attrs.alt.value ? attrs.alt.value : '');
|
||||||
const {id, local} = this.hrefToId(href);
|
const {id, local} = this.imageHrefToId(href);
|
||||||
if (local) {//local
|
if (local) {//local
|
||||||
imageNum++;
|
imageNum++;
|
||||||
|
|
||||||
@@ -329,23 +322,6 @@ export default class BookParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag == 'a') {
|
|
||||||
let attrs = sax.getAttrsSync(tail);
|
|
||||||
if (attrs.href && attrs.href.value && attrs.type && attrs.type.value === 'note') {//note
|
|
||||||
const href = attrs.href.value;
|
|
||||||
const {id, local} = this.hrefToId(href);
|
|
||||||
|
|
||||||
if (local) {
|
|
||||||
inNote = true;
|
|
||||||
growParagraph(`<note href="${id}" orig="1">`, 0);
|
|
||||||
|
|
||||||
if (!this.notes[id]) {
|
|
||||||
this.notes[id] = {id, linkParaIndex: paraIndex};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == '/fictionbook/description/title-info/author') {
|
if (path == '/fictionbook/description/title-info/author') {
|
||||||
if (!fb2.author)
|
if (!fb2.author)
|
||||||
fb2.author = [];
|
fb2.author = [];
|
||||||
@@ -374,11 +350,6 @@ export default class BookParser {
|
|||||||
|
|
||||||
if (path.indexOf('/fictionbook/body') == 0) {
|
if (path.indexOf('/fictionbook/body') == 0) {
|
||||||
if (tag == 'body') {
|
if (tag == 'body') {
|
||||||
let attrs = sax.getAttrsSync(tail);
|
|
||||||
if (attrs.name && attrs.name.value === 'notes') {//notes
|
|
||||||
inNotesBody = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isFirstBody && fb2.annotation) {
|
if (isFirstBody && fb2.annotation) {
|
||||||
const ann = fb2.annotation.split('<p>').filter(v => v).map(v => utils.removeHtmlTags(v));
|
const ann = fb2.annotation.split('<p>').filter(v => v).map(v => utils.removeHtmlTags(v));
|
||||||
ann.forEach(a => {
|
ann.forEach(a => {
|
||||||
@@ -402,31 +373,6 @@ export default class BookParser {
|
|||||||
bodyIndex++;
|
bodyIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag == 'section') {
|
|
||||||
if (!isFirstSection)
|
|
||||||
newParagraph();
|
|
||||||
isFirstSection = false;
|
|
||||||
sectionLevel++;
|
|
||||||
|
|
||||||
if (inNotesBody) {
|
|
||||||
let attrs = sax.getAttrsSync(tail);
|
|
||||||
if (attrs.id && attrs.id.value) {//notes
|
|
||||||
const id = attrs.id.value;
|
|
||||||
let note = this.notes[id];
|
|
||||||
if (!note) {
|
|
||||||
note = {id};
|
|
||||||
this.notes[id] = note;
|
|
||||||
}
|
|
||||||
|
|
||||||
note.noteParaIndex = paraIndex;
|
|
||||||
note.xml = '';
|
|
||||||
note.title = '';
|
|
||||||
noteId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == 'title') {
|
if (tag == 'title') {
|
||||||
newParagraph();
|
newParagraph();
|
||||||
isFirstTitlePara = true;
|
isFirstTitlePara = true;
|
||||||
@@ -438,6 +384,13 @@ export default class BookParser {
|
|||||||
this.contents.push(curTitle);
|
this.contents.push(curTitle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tag == 'section') {
|
||||||
|
if (!isFirstSection)
|
||||||
|
newParagraph();
|
||||||
|
isFirstSection = false;
|
||||||
|
sectionLevel++;
|
||||||
|
}
|
||||||
|
|
||||||
if (tag == 'emphasis' || tag == 'strong' || tag == 'sup' || tag == 'sub') {
|
if (tag == 'emphasis' || tag == 'strong' || tag == 'sup' || tag == 'sub') {
|
||||||
growParagraph(`<${tag}>`, 0);
|
growParagraph(`<${tag}>`, 0);
|
||||||
}
|
}
|
||||||
@@ -448,10 +401,6 @@ export default class BookParser {
|
|||||||
if (tag == 'p') {
|
if (tag == 'p') {
|
||||||
inPara = true;
|
inPara = true;
|
||||||
isFirstTitlePara = false;
|
isFirstTitlePara = false;
|
||||||
|
|
||||||
if (inTitle && inNotesBody && noteId) {
|
|
||||||
growParagraph(`<note href="${noteId}">`, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,30 +434,17 @@ export default class BookParser {
|
|||||||
bold = true;
|
bold = true;
|
||||||
space += 1;
|
space += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inTitle && inNotesBody && noteId && noteTags.has(tag)) {
|
|
||||||
this.notes[noteId].xml += `<${tag}>`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
|
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
|
||||||
tag = elemName;
|
tag = elemName;
|
||||||
|
|
||||||
if (tag == 'a' && inNote) {
|
|
||||||
growParagraph('</note>', 0);
|
|
||||||
inNote = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == 'binary') {
|
if (tag == 'binary') {
|
||||||
binaryId = '';
|
binaryId = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.indexOf('/fictionbook/body') == 0) {
|
if (path.indexOf('/fictionbook/body') == 0) {
|
||||||
if (tag == 'body') {
|
|
||||||
inNotesBody = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == 'title') {
|
if (tag == 'title') {
|
||||||
isFirstTitlePara = false;
|
isFirstTitlePara = false;
|
||||||
bold = false;
|
bold = false;
|
||||||
@@ -526,10 +462,6 @@ export default class BookParser {
|
|||||||
|
|
||||||
if (tag == 'p') {
|
if (tag == 'p') {
|
||||||
inPara = false;
|
inPara = false;
|
||||||
|
|
||||||
if (inTitle && inNotesBody && noteId) {
|
|
||||||
growParagraph('</note>', 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag == 'subtitle') {
|
if (tag == 'subtitle') {
|
||||||
@@ -553,10 +485,6 @@ export default class BookParser {
|
|||||||
bold = false;
|
bold = false;
|
||||||
space -= 1;
|
space -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inTitle && inNotesBody && noteId && noteTags.has(tag)) {
|
|
||||||
this.notes[noteId].xml += `</${tag}>`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let i = path.lastIndexOf(tag);
|
let i = path.lastIndexOf(tag);
|
||||||
@@ -642,14 +570,6 @@ export default class BookParser {
|
|||||||
growParagraph(`${tOpen}${text}${tClose}`, text.length, text);
|
growParagraph(`${tOpen}${text}${tClose}`, text.length, text);
|
||||||
else
|
else
|
||||||
growParagraph(' ', 1);
|
growParagraph(' ', 1);
|
||||||
|
|
||||||
if (inNotesBody && noteId) {
|
|
||||||
if (inTitle) {
|
|
||||||
this.notes[noteId].title += text;
|
|
||||||
} else {
|
|
||||||
this.notes[noteId].xml += text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -682,7 +602,7 @@ export default class BookParser {
|
|||||||
return {fb2};
|
return {fb2};
|
||||||
}
|
}
|
||||||
|
|
||||||
hrefToId(id) {
|
imageHrefToId(id) {
|
||||||
let local = false;
|
let local = false;
|
||||||
if (id[0] == '#') {
|
if (id[0] == '#') {
|
||||||
id = id.substr(1);
|
id = id.substr(1);
|
||||||
@@ -715,7 +635,7 @@ export default class BookParser {
|
|||||||
|
|
||||||
splitToStyle(s) {
|
splitToStyle(s) {
|
||||||
let result = [];/*array of {
|
let result = [];/*array of {
|
||||||
style: {bold: Boolean, italic: Boolean, sup: Boolean, sub: Boolean, center: Boolean, space: Number, note: Object},
|
style: {bold: Boolean, italic: Boolean, sup: Boolean, sub: Boolean, center: Boolean, space: Number},
|
||||||
image: {local: Boolean, inline: Boolean, id: String},
|
image: {local: Boolean, inline: Boolean, id: String},
|
||||||
text: String,
|
text: String,
|
||||||
}*/
|
}*/
|
||||||
@@ -766,7 +686,7 @@ export default class BookParser {
|
|||||||
case 'image': {
|
case 'image': {
|
||||||
let attrs = sax.getAttrsSync(tail);
|
let attrs = sax.getAttrsSync(tail);
|
||||||
if (attrs.href && attrs.href.value) {
|
if (attrs.href && attrs.href.value) {
|
||||||
image = this.hrefToId(attrs.href.value);
|
image = this.imageHrefToId(attrs.href.value);
|
||||||
image.inline = false;
|
image.inline = false;
|
||||||
image.num = (attrs.num && attrs.num.value ? attrs.num.value : 0);
|
image.num = (attrs.num && attrs.num.value ? attrs.num.value : 0);
|
||||||
}
|
}
|
||||||
@@ -775,7 +695,7 @@ export default class BookParser {
|
|||||||
case 'image-inline': {
|
case 'image-inline': {
|
||||||
let attrs = sax.getAttrsSync(tail);
|
let attrs = sax.getAttrsSync(tail);
|
||||||
if (attrs.href && attrs.href.value) {
|
if (attrs.href && attrs.href.value) {
|
||||||
const img = this.hrefToId(attrs.href.value);
|
const img = this.imageHrefToId(attrs.href.value);
|
||||||
img.inline = true;
|
img.inline = true;
|
||||||
img.num = (attrs.num && attrs.num.value ? attrs.num.value : 0);
|
img.num = (attrs.num && attrs.num.value ? attrs.num.value : 0);
|
||||||
result.push({
|
result.push({
|
||||||
@@ -786,13 +706,6 @@ export default class BookParser {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'note': {
|
|
||||||
let attrs = sax.getAttrsSync(tail);
|
|
||||||
if (attrs.href && attrs.href.value) {
|
|
||||||
style.note = {id: attrs.href.value, orig: attrs.orig?.value};
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -821,9 +734,6 @@ export default class BookParser {
|
|||||||
break;
|
break;
|
||||||
case 'image-inline':
|
case 'image-inline':
|
||||||
break;
|
break;
|
||||||
case 'note':
|
|
||||||
style.note = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -467,7 +467,7 @@ class BookManager {
|
|||||||
async getRecentBook(value) {
|
async getRecentBook(value) {
|
||||||
return this.recent[value.key];
|
return this.recent[value.key];
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
async delRecentBook(value, delFlag = 1) {
|
async delRecentBook(value, delFlag = 1) {
|
||||||
const item = this.recent[value.key];
|
const item = this.recent[value.key];
|
||||||
item.deleted = delFlag;
|
item.deleted = delFlag;
|
||||||
@@ -479,37 +479,13 @@ class BookManager {
|
|||||||
await this.recentSetItem(item);
|
await this.recentSetItem(item);
|
||||||
this.emit('recent-deleted', value.key);
|
this.emit('recent-deleted', value.key);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
async delRecentBooks(values, delFlag = 1) {
|
|
||||||
for (const value of values) {
|
|
||||||
const item = this.recent[value.key];
|
|
||||||
item.deleted = delFlag;
|
|
||||||
|
|
||||||
if (this.recentLastKey == value.key) {
|
|
||||||
await this.recentSetLastKey(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.recentSetItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emit('recent-deleted');
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
async restoreRecentBook(value) {
|
async restoreRecentBook(value) {
|
||||||
const item = this.recent[value.key];
|
const item = this.recent[value.key];
|
||||||
item.deleted = 0;
|
item.deleted = 0;
|
||||||
|
|
||||||
await this.recentSetItem(item);
|
await this.recentSetItem(item);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
async restoreRecentBooks(values) {
|
|
||||||
for (const value of values) {
|
|
||||||
const item = this.recent[value.key];
|
|
||||||
item.deleted = 0;
|
|
||||||
|
|
||||||
await this.recentSetItem(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async setCheckBuc(value, checkBuc) {
|
async setCheckBuc(value, checkBuc) {
|
||||||
const item = this.recent[value.key];
|
const item = this.recent[value.key];
|
||||||
|
|||||||
@@ -1,98 +1,4 @@
|
|||||||
export const versionHistory = [
|
export const versionHistory = [
|
||||||
{
|
|
||||||
version: '1.2.8',
|
|
||||||
releaseDate: '2025-06-04',
|
|
||||||
showUntil: '2025-06-03',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>исправление багов</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.7',
|
|
||||||
releaseDate: '2025-02-22',
|
|
||||||
showUntil: '2025-02-21',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>отключена форма для сбора донатов</li>
|
|
||||||
<li>мелкие оптимизации</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.6',
|
|
||||||
releaseDate: '2024-10-03',
|
|
||||||
showUntil: '2024-10-02',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>исправления из-за нарушения авторских прав</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.4',
|
|
||||||
releaseDate: '2024-08-27',
|
|
||||||
showUntil: '2024-08-26',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>исправление багов</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.3',
|
|
||||||
releaseDate: '2024-08-02',
|
|
||||||
showUntil: '2024-08-01',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>исправление багов</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.2',
|
|
||||||
releaseDate: '2024-07-28',
|
|
||||||
showUntil: '2024-07-27',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>добавлено отображение примечаний на месте, по клику на сноске (#50)</li>
|
|
||||||
<li>исправление багов</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
version: '1.2.0',
|
|
||||||
releaseDate: '2024-03-25',
|
|
||||||
showUntil: '2024-03-24',
|
|
||||||
content:
|
|
||||||
`
|
|
||||||
<ul>
|
|
||||||
<li>в списке загруженных, книга в архив (из архива) переносится теперь со всей группой своих версий</li>
|
|
||||||
<li>добавлена возможность задавать в конфиге любую ссылку для кнопки "Сетевая библиотека", параметр networkLibraryLink (#47)</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
`
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
version: '1.1.3',
|
version: '1.1.3',
|
||||||
releaseDate: '2023-02-06',
|
releaseDate: '2023-02-06',
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import miscApi from '../../api/misc';
|
||||||
// initial state
|
// initial state
|
||||||
const state = {
|
const state = {
|
||||||
name: null,
|
name: null,
|
||||||
|
|||||||
8715
package-lock.json
generated
8715
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
66
package.json
66
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "liberama",
|
"name": "liberama",
|
||||||
"version": "1.2.8",
|
"version": "1.1.3",
|
||||||
"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",
|
||||||
@@ -25,41 +25,41 @@
|
|||||||
"scripts": "server/config/*.js"
|
"scripts": "server/config/*.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.23.5",
|
"@babel/core": "^7.20.5",
|
||||||
"@babel/eslint-parser": "^7.23.3",
|
"@babel/eslint-parser": "^7.19.1",
|
||||||
"@babel/eslint-plugin": "^7.23.5",
|
"@babel/eslint-plugin": "^7.19.1",
|
||||||
"@babel/plugin-proposal-decorators": "^7.23.5",
|
"@babel/plugin-proposal-decorators": "^7.20.5",
|
||||||
"@babel/preset-env": "^7.23.5",
|
"@babel/preset-env": "^7.20.2",
|
||||||
"@vue/compiler-sfc": "^3.2.22",
|
"@vue/compiler-sfc": "^3.2.22",
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.0",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.8.1",
|
"css-loader": "^6.7.3",
|
||||||
"css-minimizer-webpack-plugin": "^4.2.2",
|
"css-minimizer-webpack-plugin": "^4.2.2",
|
||||||
"eslint": "^8.55.0",
|
"eslint": "^8.29.0",
|
||||||
"eslint-plugin-vue": "^9.19.2",
|
"eslint-plugin-vue": "^9.8.0",
|
||||||
"html-webpack-plugin": "^5.5.4",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"mini-css-extract-plugin": "^2.7.6",
|
"mini-css-extract-plugin": "^2.7.2",
|
||||||
"pkg": "^5.8.1",
|
"pkg": "^5.8.0",
|
||||||
"showdown": "^2.1.0",
|
"showdown": "^2.1.0",
|
||||||
"terser-webpack-plugin": "^5.3.9",
|
"terser-webpack-plugin": "^5.3.6",
|
||||||
"vue-eslint-parser": "^9.3.2",
|
"vue-eslint-parser": "^9.1.0",
|
||||||
"vue-loader": "^17.3.1",
|
"vue-loader": "^17.0.1",
|
||||||
"vue-style-loader": "^4.1.3",
|
"vue-style-loader": "^4.1.3",
|
||||||
"webpack": "^5.89.0",
|
"webpack": "^5.76.0",
|
||||||
"webpack-cli": "^5.1.4",
|
"webpack-cli": "^5.0.1",
|
||||||
"webpack-dev-middleware": "^6.1.1",
|
"webpack-dev-middleware": "^6.0.1",
|
||||||
"webpack-hot-middleware": "^2.25.4",
|
"webpack-hot-middleware": "^2.25.3",
|
||||||
"webpack-merge": "^5.10.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"workbox-webpack-plugin": "^6.6.0"
|
"workbox-webpack-plugin": "^6.5.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.16.9",
|
"@quasar/extras": "^1.15.8",
|
||||||
"@vue/compat": "^3.3.10",
|
"@vue/compat": "^3.2.45",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"base-x": "^4.0.0",
|
"base-x": "^4.0.0",
|
||||||
"chardet": "^1.6.0",
|
"chardet": "^1.5.0",
|
||||||
"compression": "^1.7.4",
|
"compression": "^1.7.4",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.7",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"fg-loadcss": "^3.1.0",
|
"fg-loadcss": "^3.1.0",
|
||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
@@ -68,23 +68,23 @@
|
|||||||
"jembadb": "^5.1.7",
|
"jembadb": "^5.1.7",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.7",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"pako": "^2.1.0",
|
"pako": "^2.1.0",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"pidusage": "^3.0.2",
|
"pidusage": "^3.0.2",
|
||||||
"quasar": "^2.14.1",
|
"quasar": "^2.10.2",
|
||||||
"safe-buffer": "^5.2.1",
|
"safe-buffer": "^5.2.1",
|
||||||
"sanitize-html": "^2.11.0",
|
"sanitize-html": "^2.8.0",
|
||||||
"sjcl": "^1.0.8",
|
"sjcl": "^1.0.8",
|
||||||
"tar-fs": "^2.1.1",
|
"tar-fs": "^2.1.1",
|
||||||
"unbzip2-stream": "^1.4.3",
|
"unbzip2-stream": "^1.4.3",
|
||||||
"vue": "^3.2.37",
|
"vue": "^3.2.37",
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.1.6",
|
||||||
"vuex": "^4.1.0",
|
"vuex": "^4.1.0",
|
||||||
"vuex-persist": "^3.1.3",
|
"vuex-persist": "^3.1.3",
|
||||||
"webdav": "^4.11.3",
|
"webdav": "^4.11.2",
|
||||||
"ws": "^8.14.2",
|
"ws": "^8.11.0",
|
||||||
"zip-stream": "^4.1.1"
|
"zip-stream": "^4.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ module.exports = {
|
|||||||
|
|
||||||
useExternalBookConverter: false,
|
useExternalBookConverter: false,
|
||||||
acceptFileExt: '.fb2, .fb3, .html, .txt, .zip, .bz2, .gz, .rar, .epub, .mobi, .rtf, .doc, .docx, .pdf, .djvu, .jpg, .jpeg, .png',
|
acceptFileExt: '.fb2, .fb3, .html, .txt, .zip, .bz2, .gz, .rar, .epub, .mobi, .rtf, .doc, .docx, .pdf, .djvu, .jpg, .jpeg, .png',
|
||||||
restricted: {},
|
webConfigParams: ['name', 'version', 'mode', 'maxUploadFileSize', 'useExternalBookConverter', 'acceptFileExt', 'bucEnabled', 'branch'],
|
||||||
webConfigParams: ['name', 'version', 'mode', 'maxUploadFileSize', 'useExternalBookConverter', 'acceptFileExt', 'bucEnabled', 'branch', 'networkLibraryLink', 'restricted'],
|
|
||||||
|
|
||||||
jembaDb: [
|
jembaDb: [
|
||||||
{
|
{
|
||||||
@@ -57,9 +56,6 @@ module.exports = {
|
|||||||
ip: '0.0.0.0',
|
ip: '0.0.0.0',
|
||||||
port: '33443',
|
port: '33443',
|
||||||
accessToken: '',
|
accessToken: '',
|
||||||
shciForHost: {
|
|
||||||
'samlib.ru': 300000
|
|
||||||
},
|
|
||||||
}*/
|
}*/
|
||||||
],
|
],
|
||||||
|
|
||||||
@@ -78,6 +74,5 @@ module.exports = {
|
|||||||
accessToken: '',
|
accessToken: '',
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
networkLibraryLink: '',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ const propsToSave = [
|
|||||||
'remoteStorage',
|
'remoteStorage',
|
||||||
'bucEnabled',
|
'bucEnabled',
|
||||||
'bucServer',
|
'bucServer',
|
||||||
'networkLibraryLink',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
@@ -56,7 +55,6 @@ class ConfigManager {
|
|||||||
|
|
||||||
await fs.ensureDir(config.dataDir);
|
await fs.ensureDir(config.dataDir);
|
||||||
this._userConfigFile = `${config.dataDir}/config.json`;
|
this._userConfigFile = `${config.dataDir}/config.json`;
|
||||||
this._restrictedFile = `${config.dataDir}/restricted.json`;
|
|
||||||
this._config = config;
|
this._config = config;
|
||||||
|
|
||||||
this.inited = true;
|
this.inited = true;
|
||||||
@@ -76,10 +74,6 @@ class ConfigManager {
|
|||||||
return this._userConfigFile;
|
return this._userConfigFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
get restrictedFile() {
|
|
||||||
return this._restrictedFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
set userConfigFile(value) {
|
set userConfigFile(value) {
|
||||||
if (value)
|
if (value)
|
||||||
this._userConfigFile = value;
|
this._userConfigFile = value;
|
||||||
@@ -105,12 +99,6 @@ class ConfigManager {
|
|||||||
} else {
|
} else {
|
||||||
await this.save();
|
await this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await fs.pathExists(this.restrictedFile)) {
|
|
||||||
const data = JSON.parse(await fs.readFile(this.restrictedFile, 'utf8'));
|
|
||||||
|
|
||||||
this.config = {restricted: data};
|
|
||||||
}
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
throw new Error(`Error while loading "${this.userConfigFile}": ${e.message}`);
|
throw new Error(`Error while loading "${this.userConfigFile}": ${e.message}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ class WebSocketController {
|
|||||||
this.readerWorker = new ReaderWorker(config);
|
this.readerWorker = new ReaderWorker(config);
|
||||||
this.workerState = new WorkerState();
|
this.workerState = new WorkerState();
|
||||||
|
|
||||||
this.configHash = '';
|
|
||||||
|
|
||||||
if (config.bucEnabled) {
|
if (config.bucEnabled) {
|
||||||
this.bucClient = new BUCClient(config);
|
this.bucClient = new BUCClient(config);
|
||||||
}
|
}
|
||||||
@@ -121,22 +119,8 @@ class WebSocketController {
|
|||||||
async getConfig(req, ws) {
|
async getConfig(req, ws) {
|
||||||
if (Array.isArray(req.params)) {
|
if (Array.isArray(req.params)) {
|
||||||
const paramsSet = new Set(req.params);
|
const paramsSet = new Set(req.params);
|
||||||
const _configHash = req._configHash;
|
|
||||||
|
|
||||||
let response = {_useCached: true};
|
this.send(_.pick(this.config, this.config.webConfigParams.filter(x => paramsSet.has(x))), req, ws);
|
||||||
|
|
||||||
//оптимизация, чтобы не отдавал большой конфиг каждый раз при обновлении страницы
|
|
||||||
if (!_configHash || _configHash !== this.configHash) {
|
|
||||||
if (!this.configHash) {
|
|
||||||
const webConfig = _.pick(this.config, this.config.webConfigParams);
|
|
||||||
this.configHash = await utils.getBufHash(Buffer.from(JSON.stringify(webConfig)), 'sha256', 'hex');
|
|
||||||
}
|
|
||||||
|
|
||||||
response = _.pick(this.config, this.config.webConfigParams.filter(x => paramsSet.has(x)));
|
|
||||||
response._configHash = this.configHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.send(response, req, ws);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error('params is not an array');
|
throw new Error('params is not an array');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class BUCServer {
|
|||||||
|
|
||||||
this.cleanQueryInterval = 300*dayMs;//интервал очистки устаревших
|
this.cleanQueryInterval = 300*dayMs;//интервал очистки устаревших
|
||||||
this.oldQueryInterval = 14*dayMs;//интервал устаревания запроса на обновление
|
this.oldQueryInterval = 14*dayMs;//интервал устаревания запроса на обновление
|
||||||
this.checkingInterval = 1*dayMs;//интервал проверки обновления одного и того же файла
|
this.checkingInterval = 5*hourMs;//интервал проверки обновления одного и того же файла
|
||||||
this.sameHostCheckInterval = 10*1000;//интервал проверки файла на том же сайте, не менее
|
this.sameHostCheckInterval = 1000;//интервал проверки файла на том же сайте, не менее
|
||||||
} else {
|
} else {
|
||||||
this.maxCheckQueueLength = 10;//максимальная длина checkQueue
|
this.maxCheckQueueLength = 10;//максимальная длина checkQueue
|
||||||
this.fillCheckQueuePeriod = 10*1000;//период пополнения очереди
|
this.fillCheckQueuePeriod = 10*1000;//период пополнения очереди
|
||||||
@@ -51,7 +51,6 @@ class BUCServer {
|
|||||||
|
|
||||||
this.checkQueue = [];
|
this.checkQueue = [];
|
||||||
this.hostChecking = {};
|
this.hostChecking = {};
|
||||||
this.shciForHost = this.config.shciForHost || {};//sameHostCheckInterval for host
|
|
||||||
|
|
||||||
this.main(); //no await
|
this.main(); //no await
|
||||||
|
|
||||||
@@ -263,7 +262,7 @@ class BUCServer {
|
|||||||
let unchanged = true;
|
let unchanged = true;
|
||||||
let hash = '';
|
let hash = '';
|
||||||
|
|
||||||
const headers = await this.down.head(row.id, {timeout: 10*1000});
|
const headers = await this.down.head(row.id);
|
||||||
|
|
||||||
const etag = headers['etag'] || '';
|
const etag = headers['etag'] || '';
|
||||||
const modTime = headers['last-modified'] || '';
|
const modTime = headers['last-modified'] || '';
|
||||||
@@ -277,7 +276,7 @@ class BUCServer {
|
|||||||
&& (!size || !row.size || (size !== row.size))
|
&& (!size || !row.size || (size !== row.size))
|
||||||
) {
|
) {
|
||||||
|
|
||||||
const downdata = await this.down.load(row.id, {timeout: 10*1000});
|
const downdata = await this.down.load(row.id);
|
||||||
|
|
||||||
size = downdata.length;
|
size = downdata.length;
|
||||||
hash = await utils.getBufHash(downdata, 'sha256', 'hex');
|
hash = await utils.getBufHash(downdata, 'sha256', 'hex');
|
||||||
@@ -317,12 +316,7 @@ class BUCServer {
|
|||||||
log(LM_ERR, `error ${row.id} > ${e.stack ? e.stack : e.message}`);
|
log(LM_ERR, `error ${row.id} > ${e.stack ? e.stack : e.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
(async() => {
|
(async() => {
|
||||||
let sameHostCheckInterval = this.shciForHost[url.hostname] || this.sameHostCheckInterval;
|
await utils.sleep(this.sameHostCheckInterval);
|
||||||
sameHostCheckInterval = Math.round((Math.random() - 0.5)*(sameHostCheckInterval*0.2) + sameHostCheckInterval);
|
|
||||||
|
|
||||||
log(`delay ${sameHostCheckInterval}ms for host '${url.hostname}'`);
|
|
||||||
await utils.sleep(sameHostCheckInterval);
|
|
||||||
|
|
||||||
this.hostChecking[url.hostname] = false;
|
this.hostChecking[url.hostname] = false;
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
@@ -333,7 +327,7 @@ class BUCServer {
|
|||||||
log(LM_ERR, e.stack);
|
log(LM_ERR, e.stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
await utils.sleep(100);
|
await utils.sleep(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const https = require('https');
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
|
|
||||||
const userAgent = 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0';
|
const userAgent = 'Mozilla/5.0 (X11; HasCodingOs 1.0; Linux x64) AppleWebKit/637.36 (KHTML, like Gecko) Chrome/70.0.3112.101 Safari/637.36 HasBrowser/5.0';
|
||||||
|
|
||||||
class FileDownloader {
|
class FileDownloader {
|
||||||
constructor(limitDownloadSize = 0) {
|
constructor(limitDownloadSize = 0) {
|
||||||
@@ -16,6 +16,7 @@ class FileDownloader {
|
|||||||
headers: {
|
headers: {
|
||||||
'accept-encoding': 'gzip, compress, deflate',
|
'accept-encoding': 'gzip, compress, deflate',
|
||||||
'user-agent': userAgent,
|
'user-agent': userAgent,
|
||||||
|
timeout: 300*1000,
|
||||||
},
|
},
|
||||||
httpsAgent: new https.Agent({
|
httpsAgent: new https.Agent({
|
||||||
rejectUnauthorized: false // решение проблемы 'unable to verify the first certificate' для некоторых сайтов с валидным сертификатом
|
rejectUnauthorized: false // решение проблемы 'unable to verify the first certificate' для некоторых сайтов с валидным сертификатом
|
||||||
@@ -25,9 +26,6 @@ class FileDownloader {
|
|||||||
if (opts)
|
if (opts)
|
||||||
options = Object.assign({}, opts, options);
|
options = Object.assign({}, opts, options);
|
||||||
|
|
||||||
if (!options.timeout)
|
|
||||||
options.timeout = 300*1000;//5 min
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.get(url, options);
|
const res = await axios.get(url, options);
|
||||||
|
|
||||||
@@ -79,8 +77,8 @@ class FileDownloader {
|
|||||||
const options = {
|
const options = {
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': userAgent,
|
'user-agent': userAgent,
|
||||||
|
timeout: 10*1000,
|
||||||
},
|
},
|
||||||
timeout: 10*1000,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await axios.head(url, options);
|
const res = await axios.head(url, options);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
require('tls').DEFAULT_MIN_VERSION = 'TLSv1';
|
require('tls').DEFAULT_MIN_VERSION = 'TLSv1';
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
||||||
|
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|||||||
Reference in New Issue
Block a user