Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
428b507257 | ||
|
|
043dab0731 | ||
|
|
a7b4d9c0d8 | ||
|
|
6f9c95e351 | ||
|
|
7a53063ea8 | ||
|
|
ec4d5cac4f | ||
|
|
f8557cba88 | ||
|
|
5dead039f5 | ||
|
|
ea38392df4 | ||
|
|
0cc9d90a94 | ||
|
|
8c7b86c458 | ||
|
|
0e29546fc5 | ||
|
|
c9fa90d07c | ||
|
|
7d8e0525b1 | ||
|
|
ddf69876a6 | ||
|
|
1d78e75e38 | ||
|
|
7ed58fe3c6 | ||
|
|
058c79570b | ||
|
|
ec8fbcdf38 | ||
|
|
76673295bf | ||
|
|
084401b9c3 | ||
|
|
49038b10f7 | ||
|
|
45ea26810a | ||
|
|
18c8b2d803 | ||
|
|
f4a7482b3b | ||
|
|
32dff128f4 | ||
|
|
a00b2d6574 | ||
|
|
10c6e7d522 | ||
|
|
df6a256d51 | ||
|
|
fbdb74ee68 | ||
|
|
9ad7250da0 |
@@ -38,6 +38,6 @@ $ npm run dev
|
|||||||
|
|
||||||
## Помочь проекту
|
## Помочь проекту
|
||||||
|
|
||||||
* bitcoin: 3EbgZ7MK1UVaN38Gty5DCBtS4PknM4Ut85
|
* bitcoin: bc1q3tyumaj648pp2e69jalsez2lnt462ttc33nup9
|
||||||
* litecoin: MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ
|
* litecoin: MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ
|
||||||
* monero: 8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz
|
* monero: 8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ class App {
|
|||||||
const url = s[1] || '';
|
const url = s[1] || '';
|
||||||
const q = utils.parseQuery(s[0] || '');
|
const q = utils.parseQuery(s[0] || '');
|
||||||
if (url) {
|
if (url) {
|
||||||
q.url = decodeURIComponent(url);
|
q.url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.history.replaceState({}, '', '/');
|
window.history.replaceState({}, '', '/');
|
||||||
|
|||||||
@@ -1,70 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="box">
|
<div class="column items-center" style="width: 500px">
|
||||||
<p class="p">
|
<p class="p">
|
||||||
Вы можете пожертвовать на развитие проекта любую сумму:
|
Здесь вы можете пожертвовать на развитие проекта:
|
||||||
</p>
|
</p>
|
||||||
<div class="address">
|
|
||||||
<img class="logo" src="./assets/yoomoney.png">
|
|
||||||
<q-btn class="q-ml-sm q-px-sm" dense no-caps @click="donateYooMoney">
|
|
||||||
Пожертвовать
|
|
||||||
</q-btn><br>
|
|
||||||
<div class="para">
|
|
||||||
{{ yooAddress }}
|
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyAddress(yooAddress, 'Кошелёк ЮMoney')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--div class="address">
|
<q-btn no-caps class="q-my-lg" color="green-8" size="14px" style="width: 200px" @click="makeDonation">
|
||||||
<img class="logo" src="./assets/paypal.png">
|
<q-icon class="q-mr-xs" name="la la-donate" size="24px" />
|
||||||
<div class="para">
|
Поддержать проект
|
||||||
{{ paypalAddress }}
|
</q-btn>
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyAddress(paypalAddress, 'Paypal-адрес')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
</div>
|
|
||||||
</div-->
|
|
||||||
|
|
||||||
<div class="address">
|
<div style="font-size: 60%">
|
||||||
<img class="logo" src="./assets/bitcoin.png">
|
* Ваш донат является подарком автору проекта
|
||||||
<div class="para">
|
|
||||||
{{ bitcoinAddress }}
|
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyAddress(bitcoinAddress, 'Bitcoin-адрес')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="address">
|
|
||||||
<img class="logo" src="./assets/litecoin.png">
|
|
||||||
<div class="para">
|
|
||||||
{{ litecoinAddress }}
|
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyAddress(litecoinAddress, 'Litecoin-адрес')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="address">
|
|
||||||
<img class="logo" src="./assets/monero.png">
|
|
||||||
<div class="para">
|
|
||||||
{{ moneroAddress }}
|
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyAddress(moneroAddress, 'Monero-адрес')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -74,28 +21,14 @@
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
import vueComponent from '../../../vueComponent.js';
|
import vueComponent from '../../../vueComponent.js';
|
||||||
|
|
||||||
import {copyTextToClipboard} from '../../../../share/utils';
|
import * as utils from '../../../../share/utils';
|
||||||
|
|
||||||
class DonateHelpPage {
|
class DonateHelpPage {
|
||||||
yooAddress = '410018702323056';
|
|
||||||
paypalAddress = 'bookpauk@gmail.com';
|
|
||||||
bitcoinAddress = '3EbgZ7MK1UVaN38Gty5DCBtS4PknM4Ut85';
|
|
||||||
litecoinAddress = 'MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ';
|
|
||||||
moneroAddress = '8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz';
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
}
|
}
|
||||||
|
|
||||||
donateYooMoney() {
|
makeDonation() {
|
||||||
window.open(`https://yoomoney.ru/to/${this.yooAddress}`, '_blank');
|
utils.makeDonation();
|
||||||
}
|
|
||||||
|
|
||||||
async copyAddress(address, prefix) {
|
|
||||||
const result = await copyTextToClipboard(address);
|
|
||||||
if (result)
|
|
||||||
this.$root.notify.success(`${prefix} ${address} успешно скопирован в буфер обмена`);
|
|
||||||
else
|
|
||||||
this.$root.notify.error('Копирование не удалось');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,31 +49,4 @@ export default vueComponent(DonateHelpPage);
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
text-indent: 20px;
|
text-indent: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.box {
|
|
||||||
max-width: 550px;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.address {
|
|
||||||
padding-top: 10px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.para {
|
|
||||||
margin: 10px 10px 10px 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
width: 130px;
|
|
||||||
position: relative;
|
|
||||||
top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.copy-icon {
|
|
||||||
margin-left: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 120%;
|
|
||||||
color: blue;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.8 KiB |
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Window @close="close">
|
<Window @close="close" style="z-index: 200">
|
||||||
<template #header>
|
<template #header>
|
||||||
Справка
|
Справка
|
||||||
</template>
|
</template>
|
||||||
@@ -36,14 +36,14 @@ import CommonHelpPage from './CommonHelpPage/CommonHelpPage.vue';
|
|||||||
import HotkeysHelpPage from './HotkeysHelpPage/HotkeysHelpPage.vue';
|
import HotkeysHelpPage from './HotkeysHelpPage/HotkeysHelpPage.vue';
|
||||||
import MouseHelpPage from './MouseHelpPage/MouseHelpPage.vue';
|
import MouseHelpPage from './MouseHelpPage/MouseHelpPage.vue';
|
||||||
import VersionHistoryPage from './VersionHistoryPage/VersionHistoryPage.vue';
|
import VersionHistoryPage from './VersionHistoryPage/VersionHistoryPage.vue';
|
||||||
//import DonateHelpPage from './DonateHelpPage/DonateHelpPage.vue';
|
import DonateHelpPage from './DonateHelpPage/DonateHelpPage.vue';
|
||||||
|
|
||||||
const pages = {
|
const pages = {
|
||||||
'CommonHelpPage': CommonHelpPage,
|
'CommonHelpPage': CommonHelpPage,
|
||||||
'HotkeysHelpPage': HotkeysHelpPage,
|
'HotkeysHelpPage': HotkeysHelpPage,
|
||||||
'MouseHelpPage': MouseHelpPage,
|
'MouseHelpPage': MouseHelpPage,
|
||||||
'VersionHistoryPage': VersionHistoryPage,
|
'VersionHistoryPage': VersionHistoryPage,
|
||||||
//'DonateHelpPage': DonateHelpPage,
|
'DonateHelpPage': DonateHelpPage,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
@@ -51,7 +51,7 @@ const tabs = [
|
|||||||
['MouseHelpPage', 'Мышь/тачскрин'],
|
['MouseHelpPage', 'Мышь/тачскрин'],
|
||||||
['HotkeysHelpPage', 'Клавиатура'],
|
['HotkeysHelpPage', 'Клавиатура'],
|
||||||
['VersionHistoryPage', 'История версий'],
|
['VersionHistoryPage', 'История версий'],
|
||||||
//['DonateHelpPage', 'Помочь проекту'],
|
['DonateHelpPage', 'Помочь проекту'],
|
||||||
];
|
];
|
||||||
|
|
||||||
const componentOptions = {
|
const componentOptions = {
|
||||||
@@ -80,7 +80,7 @@ class HelpPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
activateDonateHelpPage() {
|
activateDonateHelpPage() {
|
||||||
//this.selectedTab = 'DonateHelpPage';
|
this.selectedTab = 'DonateHelpPage';
|
||||||
}
|
}
|
||||||
|
|
||||||
activateVersionHistoryHelpPage() {
|
activateVersionHistoryHelpPage() {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
<div class="col column justify-end items-center no-wrap overflow-hidden">
|
<div class="col column justify-end items-center no-wrap overflow-hidden">
|
||||||
<span v-if="mode == 'omnireader'" class="bottom-span clickable" @click="findBook">Найти книгу</span>
|
<span v-if="mode == 'omnireader'" class="bottom-span clickable" @click="findBook">Найти книгу</span>
|
||||||
<span class="bottom-span clickable" @click="openHelp">Справка</span>
|
<span class="bottom-span clickable" @click="openHelp">Справка</span>
|
||||||
<!--span class="bottom-span clickable" @click="openDonate">Помочь проекту</span-->
|
<span class="bottom-span clickable" @click="openDonate">Помочь проекту</span>
|
||||||
|
|
||||||
<span v-if="version == clientVersion" class="bottom-span">v{{ version }}</span>
|
<span v-if="version == clientVersion" class="bottom-span">v{{ version }}</span>
|
||||||
<span v-else class="bottom-span">Версия сервера {{ version }}, версия клиента {{ clientVersion }}, необходимо обновить страницу</span>
|
<span v-else class="bottom-span">Версия сервера {{ version }}, версия клиента {{ clientVersion }}, необходимо обновить страницу</span>
|
||||||
|
|||||||
@@ -476,7 +476,10 @@ class Reader {
|
|||||||
this.dualPageMode = settings.dualPageMode;
|
this.dualPageMode = settings.dualPageMode;
|
||||||
this.userWallpapers = settings.userWallpapers;
|
this.userWallpapers = settings.userWallpapers;
|
||||||
this.bucEnabled = settings.bucEnabled;
|
this.bucEnabled = settings.bucEnabled;
|
||||||
|
this.bucSizeDiff = settings.bucSizeDiff;
|
||||||
this.bucSetOnNew = settings.bucSetOnNew;
|
this.bucSetOnNew = settings.bucSetOnNew;
|
||||||
|
this.bucCancelEnabled = settings.bucCancelEnabled;
|
||||||
|
this.bucCancelDays = settings.bucCancelDays;
|
||||||
|
|
||||||
this.readerActionByKeyCode = utils.userHotKeysObjectSwap(settings.userHotKeys);
|
this.readerActionByKeyCode = utils.userHotKeysObjectSwap(settings.userHotKeys);
|
||||||
this.$root.readerActionByKeyEvent = (event) => {
|
this.$root.readerActionByKeyEvent = (event) => {
|
||||||
@@ -604,13 +607,50 @@ class Reader {
|
|||||||
await utils.sleep(1000);//чтобы не ддосить сервер
|
await utils.sleep(1000);//чтобы не ддосить сервер
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const checkSetTime = {};
|
||||||
//проставим новые размеры у книг
|
//проставим новые размеры у книг
|
||||||
for (const book of sorted) {
|
for (const book of sorted) {
|
||||||
|
if (book.deleted)
|
||||||
|
continue;
|
||||||
|
|
||||||
//размер 0 считаем отсутствующим
|
//размер 0 считаем отсутствующим
|
||||||
if (book.url && bucSize[book.url] && bucSize[book.url] !== book.bucSize) {
|
if (book.url && bucSize[book.url] && bucSize[book.url] !== book.bucSize) {
|
||||||
book.bucSize = bucSize[book.url];
|
book.bucSize = bucSize[book.url];
|
||||||
await bookManager.recentSetItem(book);
|
await bookManager.recentSetItem(book);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//подготовка к следующему шагу, ищем книгу по url с максимальной датой установки checkBucTime/loadTime
|
||||||
|
//от этой даты будем потом отсчитывать bucCancelDays
|
||||||
|
if (updateUrls.has(book.url)) {
|
||||||
|
let rec = checkSetTime[book.url] || {time: 0, loadTime: 0};
|
||||||
|
|
||||||
|
const time = (book.checkBucTime ? book.checkBucTime : (rec.loadTime || 0));
|
||||||
|
if (time > rec.time || (time == rec.time && (book.loadTime > rec.loadTime)))
|
||||||
|
rec = {time, loadTime: book.loadTime, key: book.key};
|
||||||
|
|
||||||
|
checkSetTime[book.url] = rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//bucCancelEnabled и bucCancelDays
|
||||||
|
//снимем флаг checkBuc у необновлявшихся bucCancelDays
|
||||||
|
if (this.bucCancelEnabled) {
|
||||||
|
for (const rec of Object.values(checkSetTime)) {
|
||||||
|
if (rec.time && Date.now() - rec.time > this.bucCancelDays*24*3600*1000) {
|
||||||
|
const book = await bookManager.getRecentBook({key: rec.key});
|
||||||
|
const needBookUpdate =
|
||||||
|
book.checkBuc
|
||||||
|
&& book.bucSize
|
||||||
|
&& utils.hasProp(book, 'downloadSize')
|
||||||
|
&& book.bucSize !== book.downloadSize
|
||||||
|
&& (book.bucSize - book.downloadSize >= this.bucSizeDiff)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (book && !needBookUpdate) {
|
||||||
|
await bookManager.setCheckBuc(book, undefined);//!!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$refs.recentBooksPage.updateTableData();
|
await this.$refs.recentBooksPage.updateTableData();
|
||||||
@@ -681,7 +721,7 @@ class Reader {
|
|||||||
return;
|
return;
|
||||||
const recent = this.mostRecentBook();
|
const recent = this.mostRecentBook();
|
||||||
const pos = (recent && recent.bookPos && this.allowUrlParamBookPos ? `__p=${recent.bookPos}&` : '');
|
const pos = (recent && recent.bookPos && this.allowUrlParamBookPos ? `__p=${recent.bookPos}&` : '');
|
||||||
const url = (recent ? `url=${recent.url}` : '');
|
const url = (recent ? `url=${encodeURIComponent(recent.url)}` : '');
|
||||||
if (isNewRoute)
|
if (isNewRoute)
|
||||||
this.$router.push(`/reader?${pos}${url}`).catch(() => {});
|
this.$router.push(`/reader?${pos}${url}`).catch(() => {});
|
||||||
else
|
else
|
||||||
@@ -1251,6 +1291,7 @@ class Reader {
|
|||||||
|
|
||||||
this.checkBookPosPercent();
|
this.checkBookPosPercent();
|
||||||
this.activateClickMapPage();//no await
|
this.activateClickMapPage();//no await
|
||||||
|
this.$refs.recentBooksPage.updateTableData();//no await
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,56 +18,51 @@
|
|||||||
</template>
|
</template>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|
||||||
<Dialog ref="dialog2" v-model="donationVisible">
|
<q-dialog ref="dialog2" v-model="donationVisible" style="z-index: 100" no-route-dismiss no-esc-dismiss no-backdrop-dismiss>
|
||||||
<template #header>
|
<div class="column bg-white no-wrap q-pa-md">
|
||||||
Здравствуйте, уважаемые читатели!
|
<div class="row justify-center q-mb-md" style="font-size: 110%">
|
||||||
</template>
|
Здравствуйте, дорогие читатели!
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="word-break: normal">
|
<div class="q-mx-md column" style="word-break: normal">
|
||||||
Стартовала ежегодная акция "Оплатим хостинг вместе".<br><br>
|
<div>
|
||||||
|
Вот уже много лет мы все вместе пользуемся нашей любимой читалкой.<br><br>
|
||||||
|
|
||||||
Для оплаты годового хостинга читалки, необходимо собрать около 2000 рублей.
|
Напоминаем вам, что проект является некоммерческим и обладает такими
|
||||||
В настоящий момент у автора эта сумма есть в наличии. Однако будет справедливо, если каждый
|
достоинствами, как:
|
||||||
сможет проголосовать рублем за то, чтобы читалка так и оставалась:
|
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>непрерывно улучшаемой</li>
|
<li>все функции читалки открыты и доступны совершенно бесплатно</li>
|
||||||
<li>без рекламы</li>
|
<li>в проекте отсутствует какая-либо реклама или баннеры</li>
|
||||||
<li>без регистрации</li>
|
<li>нет никакой регистрации и монетизации</li>
|
||||||
<li>Open Source</li>
|
<li>нет сбора персональных данных</li>
|
||||||
|
<li>открытый исходный код</li>
|
||||||
|
<li>проект постепенно улучшается, по мере возможности</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Автор также обращается с просьбой о помощи в распространении
|
Однако на оплату хостинга читалки и сервера обновлений автор тратит свои
|
||||||
<a href="https://omnireader.ru" target="_blank">ссылки</a>
|
собственные средства, а также тратит свое время и силы на улучшение проекта.
|
||||||
<q-icon class="copy-icon" name="la la-copy" @click="copyLink('https://omnireader.ru')">
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="center middle" content-style="font-size: 80%">
|
|
||||||
Скопировать
|
|
||||||
</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
на читалку через тематические форумы, соцсети, мессенджеры и пр.
|
|
||||||
Чем нас больше, тем легче оставаться на плаву и тем больше мотивации у разработчика, чтобы продолжать работать над проектом.
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
Если соберется бóльшая сумма, то разработка децентрализованной библиотеки для свободного обмена книгами будет по возможности ускорена.
|
Поддержим же материально наш ресурс, чтобы и дальше спокойно существовать и развиваться:
|
||||||
<br><br>
|
|
||||||
P.S. При необходимости можно воспользоваться подходящим обменником на <a href="https://www.bestchange.ru" target="_blank">bestchange.ru</a>
|
|
||||||
|
|
||||||
<br><br>
|
|
||||||
<div class="row justify-center">
|
|
||||||
<!--q-btn class="q-px-sm" color="primary" dense no-caps @click="openDonate">
|
|
||||||
Помочь проекту
|
|
||||||
</q-btn-->
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<q-btn style="margin: 10px 50px 10px 50px" color="green-8" size="14px" no-caps @click="makeDonation">
|
||||||
<span class="clickable row justify-end" style="font-size: 60%; color: grey" @click="donationDialogDisable">Больше не показывать</span>
|
<q-icon class="q-mr-xs" name="la la-donate" size="24px" />
|
||||||
<br>
|
Поддержать проект
|
||||||
<q-btn class="q-px-sm" dense no-caps @click="donationDialogRemind">
|
|
||||||
Напомнить позже
|
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</template>
|
|
||||||
</Dialog>
|
<q-btn style="margin: 0 50px 20px 50px" size="14px" no-caps @click="donationDialogRemind">
|
||||||
|
Напомнить в следующем месяце
|
||||||
|
</q-btn>
|
||||||
|
|
||||||
|
<div class="row justify-center">
|
||||||
|
<div class="q-px-sm clickable" style="font-size: 80%" @click="openDonate">
|
||||||
|
Помочь проекту можно в любое время
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</q-dialog>
|
||||||
|
|
||||||
<Dialog ref="dialog3" v-model="urlHelpVisible">
|
<Dialog ref="dialog3" v-model="urlHelpVisible">
|
||||||
<template #header>
|
<template #header>
|
||||||
@@ -134,7 +129,7 @@ class ReaderDialogs {
|
|||||||
loadSettings() {
|
loadSettings() {
|
||||||
const settings = this.settings;
|
const settings = this.settings;
|
||||||
this.showWhatsNewDialog = settings.showWhatsNewDialog;
|
this.showWhatsNewDialog = settings.showWhatsNewDialog;
|
||||||
this.showDonationDialog2020 = settings.showDonationDialog2020;
|
this.showDonationDialog = settings.showDonationDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
async showWhatsNew() {
|
async showWhatsNew() {
|
||||||
@@ -149,9 +144,9 @@ class ReaderDialogs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async showDonation() {
|
async showDonation() {
|
||||||
const today = utils.formatDate(new Date(), 'coDate');
|
const today = utils.formatDate(new Date(), 'coMonth');
|
||||||
|
|
||||||
if ((this.mode == 'omnireader' || this.mode == 'liberama.top') && today < '2020-03-01' && this.showDonationDialog2020 && this.donationRemindDate != today) {
|
if ((this.mode == 'omnireader' || this.mode == 'liberama.top') && this.showDonationDialog && this.donationRemindDate != today) {
|
||||||
await utils.sleep(3000);
|
await utils.sleep(3000);
|
||||||
this.donationVisible = true;
|
this.donationVisible = true;
|
||||||
}
|
}
|
||||||
@@ -166,20 +161,17 @@ class ReaderDialogs {
|
|||||||
this.urlHelpVisible = false;
|
this.urlHelpVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
donationDialogDisable() {
|
|
||||||
this.donationVisible = false;
|
|
||||||
if (this.showDonationDialog2020) {
|
|
||||||
this.commit('reader/setSettings', { showDonationDialog2020: false });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
donationDialogRemind() {
|
donationDialogRemind() {
|
||||||
this.donationVisible = false;
|
this.donationVisible = false;
|
||||||
this.commit('reader/setDonationRemindDate', utils.formatDate(new Date(), 'coDate'));
|
this.commit('reader/setDonationRemindDate', utils.formatDate(new Date(), 'coMonth'));
|
||||||
|
}
|
||||||
|
|
||||||
|
makeDonation() {
|
||||||
|
utils.makeDonation();
|
||||||
|
this.donationDialogRemind();
|
||||||
}
|
}
|
||||||
|
|
||||||
openDonate() {
|
openDonate() {
|
||||||
this.donationVisible = false;
|
|
||||||
this.$emit('donate-toggle');
|
this.$emit('donate-toggle');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,8 +147,8 @@
|
|||||||
{{ item.desc.title }}
|
{{ item.desc.title }}
|
||||||
</div>
|
</div>
|
||||||
<div v-show="bothBucEnabled && item.needBookUpdate" style="font-size: 75%; color: blue;">
|
<div v-show="bothBucEnabled && item.needBookUpdate" style="font-size: 75%; color: blue;">
|
||||||
Размер: {{ item.downloadSize }} → {{ item.bucSize }},
|
Размер: {{ item.bucSize - item.downloadSize > 0 ? '+' : '' }}{{ item.bucSize - item.downloadSize }}
|
||||||
{{ item.bucSize - item.downloadSize > 0 ? '+' : '' }}{{ item.bucSize - item.downloadSize }}
|
({{ item.downloadSize }} → {{ item.bucSize }})
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -231,7 +231,12 @@
|
|||||||
@update:model-value="checkBucChange(item)"
|
@update:model-value="checkBucChange(item)"
|
||||||
>
|
>
|
||||||
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
<q-tooltip :delay="1500" anchor="bottom middle" content-style="font-size: 80%">
|
||||||
Проверять обновления
|
<div v-if="item.checkBuc === undefined">
|
||||||
|
Проверка обновлений отключена автоматически<br>т.к. книга не обновлялась {{ bucCancelDays }} дней
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
{{ (item.checkBuc ? 'Проверка обновлений книги включена' : 'Проверка обновлений книги отключена') }}
|
||||||
|
</div>
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div>
|
</div>
|
||||||
@@ -289,6 +294,7 @@ class RecentBooksPage {
|
|||||||
bucEnabled = false;
|
bucEnabled = false;
|
||||||
bucSizeDiff = 0;
|
bucSizeDiff = 0;
|
||||||
bucSetOnNew = false;
|
bucSetOnNew = false;
|
||||||
|
bucCancelDays = 0;
|
||||||
needBookUpdateCount = 0;
|
needBookUpdateCount = 0;
|
||||||
|
|
||||||
showArchive = false;
|
showArchive = false;
|
||||||
@@ -332,6 +338,7 @@ class RecentBooksPage {
|
|||||||
this.bucEnabled = settings.bucEnabled;
|
this.bucEnabled = settings.bucEnabled;
|
||||||
this.bucSizeDiff = settings.bucSizeDiff;
|
this.bucSizeDiff = settings.bucSizeDiff;
|
||||||
this.bucSetOnNew = settings.bucSetOnNew;
|
this.bucSetOnNew = settings.bucSetOnNew;
|
||||||
|
this.bucCancelDays = settings.bucCancelDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
get settings() {
|
get settings() {
|
||||||
@@ -403,8 +410,8 @@ class RecentBooksPage {
|
|||||||
inGroup: false,
|
inGroup: false,
|
||||||
coverPageUrl: book.coverPageUrl,
|
coverPageUrl: book.coverPageUrl,
|
||||||
|
|
||||||
showCheckBuc: !this.showArchive && utils.hasProp(book, 'downloadSize'),
|
showCheckBuc: !this.showArchive && utils.hasProp(book, 'downloadSize') && book.url.indexOf('disk://') !== 0,
|
||||||
checkBuc: !!book.checkBuc,
|
checkBuc: book.checkBuc,
|
||||||
needBookUpdate: (
|
needBookUpdate: (
|
||||||
!this.showArchive
|
!this.showArchive
|
||||||
&& book.checkBuc
|
&& book.checkBuc
|
||||||
@@ -806,6 +813,12 @@ class RecentBooksPage {
|
|||||||
const book = await bookManager.getRecentBook(item);
|
const book = await bookManager.getRecentBook(item);
|
||||||
if (book) {
|
if (book) {
|
||||||
await bookManager.setCheckBuc(book, item.checkBuc);
|
await bookManager.setCheckBuc(book, item.checkBuc);
|
||||||
|
|
||||||
|
this.$root.notify.info(item.checkBuc
|
||||||
|
? 'Проверка обновлений книги включена'
|
||||||
|
: 'Проверка обновлений книги отключена'
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,15 +41,15 @@
|
|||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div>
|
</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="showDonationDialog2020">
|
<q-checkbox size="xs" v-model="showDonationDialog">
|
||||||
Показывать "Оплатим хостинг вместе"
|
Показывать форму доната
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
Показывать уведомление "Оплатим хостинг вместе"
|
Показывать диалог для сбора пожертвований
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div-->
|
</div>
|
||||||
|
|
||||||
<!---------------------------------------------->
|
<!---------------------------------------------->
|
||||||
<div class="part-header">Другое</div>
|
<div class="part-header">Другое</div>
|
||||||
|
|||||||
@@ -27,17 +27,7 @@
|
|||||||
|
|
||||||
<div v-show="configBucEnabled && bucEnabled" class="item row">
|
<div v-show="configBucEnabled && bucEnabled" class="item row">
|
||||||
<div class="label-6"></div>
|
<div class="label-6"></div>
|
||||||
<q-checkbox size="xs" v-model="bucSetOnNew">
|
<div class="col-5 column justify-center items-end q-pr-xs">Разница размеров</div>
|
||||||
Автопроверка для вновь загружаемых
|
|
||||||
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
|
||||||
Автоматически устанавливать флаг проверки<br>
|
|
||||||
обновлений для всех вновь загружаемых книг
|
|
||||||
</q-tooltip>
|
|
||||||
</q-checkbox>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-show="configBucEnabled && bucEnabled" class="item row">
|
|
||||||
<div class="label-6">Разница размеров</div>
|
|
||||||
<div class="col row">
|
<div class="col row">
|
||||||
<NumInput class="col-left" v-model="bucSizeDiff" />
|
<NumInput class="col-left" v-model="bucSizeDiff" />
|
||||||
|
|
||||||
@@ -48,3 +38,39 @@
|
|||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-show="configBucEnabled && bucEnabled" class="item row">
|
||||||
|
<div class="label-6"></div>
|
||||||
|
<q-checkbox size="xs" v-model="bucSetOnNew">
|
||||||
|
Автопроверка для вновь загружаемых
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
Автоматически устанавливать флаг проверки<br>
|
||||||
|
обновлений для всех вновь загружаемых книг
|
||||||
|
</q-tooltip>
|
||||||
|
</q-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="configBucEnabled && bucEnabled" class="item row">
|
||||||
|
<div class="label-6"></div>
|
||||||
|
<q-checkbox size="xs" v-model="bucCancelEnabled">
|
||||||
|
Отменять проверку через {{ bucCancelDays }} дней{{ (bucCancelEnabled ? ':' : '') }}
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
Снимать флаг проверки с книги, если не было<br>
|
||||||
|
обновлений в течение {{ bucCancelDays }} дней
|
||||||
|
</q-tooltip>
|
||||||
|
</q-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="configBucEnabled && bucEnabled && bucCancelEnabled" class="item row">
|
||||||
|
<div class="label-6"></div>
|
||||||
|
<div class="col-5"></div>
|
||||||
|
<div class="col row">
|
||||||
|
<NumInput class="col-left" v-model="bucCancelDays" :min="1" :max="10000"/>
|
||||||
|
|
||||||
|
<q-tooltip :delay="1000" anchor="top middle" self="bottom middle" content-style="font-size: 80%">
|
||||||
|
Снимать флаг проверки с книги, если не было<br>
|
||||||
|
обновлений в течение {{ bucCancelDays }} дней
|
||||||
|
</q-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -487,7 +487,7 @@ class BookManager {
|
|||||||
await this.recentSetItem(item);
|
await this.recentSetItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setCheckBuc(value, checkBuc = true) {
|
async setCheckBuc(value, checkBuc) {
|
||||||
const item = this.recent[value.key];
|
const item = this.recent[value.key];
|
||||||
|
|
||||||
const updateItems = [];
|
const updateItems = [];
|
||||||
@@ -495,7 +495,7 @@ class BookManager {
|
|||||||
if (item.sameBookKey !== undefined) {
|
if (item.sameBookKey !== undefined) {
|
||||||
const sorted = this.getSortedRecent();
|
const sorted = this.getSortedRecent();
|
||||||
for (const book of sorted) {
|
for (const book of sorted) {
|
||||||
if (book.sameBookKey === item.sameBookKey)
|
if (!book.deleted && book.sameBookKey === item.sameBookKey)
|
||||||
updateItems.push(book);
|
updateItems.push(book);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -503,8 +503,11 @@ class BookManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
for (const book of updateItems) {
|
for (const book of updateItems) {
|
||||||
book.checkBuc = checkBuc;
|
book.checkBuc = checkBuc;
|
||||||
|
if (checkBuc)
|
||||||
|
book.checkBucTime = now;
|
||||||
await this.recentSetItem(book);
|
await this.recentSetItem(book);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
export const versionHistory = [
|
export const versionHistory = [
|
||||||
|
{
|
||||||
|
version: '0.12.1',
|
||||||
|
releaseDate: '2022-09-01',
|
||||||
|
showUntil: '2022-08-30',
|
||||||
|
content:
|
||||||
|
`
|
||||||
|
<ul>
|
||||||
|
<li>добавлена форма для доната</li>
|
||||||
|
<li>исправления багов</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
`
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
version: '0.12.0',
|
version: '0.12.0',
|
||||||
releaseDate: '2022-07-27',
|
releaseDate: '2022-07-27',
|
||||||
@@ -9,7 +23,8 @@ export const versionHistory = [
|
|||||||
<li>запущен сервер проверки обновлений книг:</li>
|
<li>запущен сервер проверки обновлений книг:</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>проверка обновления той или иной книги настраивается в списке загруженных (чекбокс)</li>
|
<li>проверка обновления той или иной книги настраивается в списке загруженных (чекбокс)</li>
|
||||||
<li>в настройках можно указать разницу размеров, при которой необходимо делать уведомление</li>
|
<li>для того, чтобы чекбокс появился у ранее загруженной, необходимо принудительно обновить книгу</li>
|
||||||
|
<li>в настройках можно указать разницу размеров, при которой требуется делать уведомление</li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ export function formatDate(d, format) {
|
|||||||
`${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
|
`${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
|
||||||
case 'coDate':
|
case 'coDate':
|
||||||
return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
|
return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
|
||||||
|
case 'coMonth':
|
||||||
|
return `${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
|
||||||
case 'noDate':
|
case 'noDate':
|
||||||
return `${d.getDate().toString().padStart(2, '0')}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getFullYear()}`;
|
return `${d.getDate().toString().padStart(2, '0')}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getFullYear()}`;
|
||||||
}
|
}
|
||||||
@@ -410,3 +412,7 @@ export function resizeImage(dataUrl, toWidth, toHeight, quality = 0.9) {
|
|||||||
reject('Не удалось изменить размер');
|
reject('Не удалось изменить размер');
|
||||||
})().catch(reject); });
|
})().catch(reject); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function makeDonation() {
|
||||||
|
window.open('https://donatty.com/liberama', '_blank');
|
||||||
|
}
|
||||||
|
|||||||
@@ -180,12 +180,12 @@ const settingDefaults = {
|
|||||||
|
|
||||||
showServerStorageMessages: true,
|
showServerStorageMessages: true,
|
||||||
showWhatsNewDialog: true,
|
showWhatsNewDialog: true,
|
||||||
showDonationDialog2020: true,
|
showDonationDialog: true,
|
||||||
showNeedUpdateNotify: true,
|
showNeedUpdateNotify: true,
|
||||||
|
|
||||||
fontShifts: {},
|
fontShifts: {},
|
||||||
showToolButton: {},
|
showToolButton: {},
|
||||||
toolBarHideOnScroll: true,
|
toolBarHideOnScroll: false,
|
||||||
userHotKeys: {},
|
userHotKeys: {},
|
||||||
userWallpapers: [],
|
userWallpapers: [],
|
||||||
|
|
||||||
@@ -196,6 +196,8 @@ const settingDefaults = {
|
|||||||
bucEnabled: true, // общее включение/выключение проверки обновлений
|
bucEnabled: true, // общее включение/выключение проверки обновлений
|
||||||
bucSizeDiff: 1, // разница в размерах файла, при которой показывать наличие обновления
|
bucSizeDiff: 1, // разница в размерах файла, при которой показывать наличие обновления
|
||||||
bucSetOnNew: true, // автоматически включать проверку обновлений для вновь загружаемых файлов
|
bucSetOnNew: true, // автоматически включать проверку обновлений для вновь загружаемых файлов
|
||||||
|
bucCancelEnabled: true, // вкл/выкл отмену проверки книг через bucCancelDays
|
||||||
|
bucCancelDays: 90, // количество дней, через которое отменяется проверка книги, при условии отсутствия обновлений за это время
|
||||||
|
|
||||||
//для SettingsPage
|
//для SettingsPage
|
||||||
needUpdateSettingsView: 0,
|
needUpdateSettingsView: 0,
|
||||||
|
|||||||
1697
package-lock.json
generated
1697
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@@ -1,17 +1,17 @@
|
|||||||
{
|
{
|
||||||
"name": "Liberama",
|
"name": "Liberama",
|
||||||
"version": "0.12.0",
|
"version": "0.12.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",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.4.0"
|
"node": ">=16.16.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon --inspect --ignore server/public --ignore server/data --ignore client --exec 'node server'",
|
"dev": "nodemon --inspect --ignore server/public --ignore server/data --ignore client --exec 'node server'",
|
||||||
"build:client": "webpack --config build/webpack.prod.config.js",
|
"build:client": "webpack --config build/webpack.prod.config.js",
|
||||||
"build:linux": "npm run build:client && node build/linux && pkg -t node14-linux-x64 -C GZip -o dist/linux/liberama .",
|
"build:linux": "npm run build:client && node build/linux && pkg -t node16-linux-x64 -C GZip -o dist/linux/liberama .",
|
||||||
"build:win": "npm run build:client && node build/win && pkg -t node14-win-x64 -C GZip -o dist/win/liberama .",
|
"build:win": "npm run build:client && node build/win && pkg -t node16-win-x64 -C GZip -o dist/win/liberama .",
|
||||||
"lint": "eslint --ext=.js,.vue client server",
|
"lint": "eslint --ext=.js,.vue client server",
|
||||||
"build:client-dev": "webpack --config build/webpack.dev.config.js",
|
"build:client-dev": "webpack --config build/webpack.dev.config.js",
|
||||||
"postinstall": "npm run build:client-dev && node build/linux"
|
"postinstall": "npm run build:client-dev && node build/linux"
|
||||||
@@ -21,35 +21,35 @@
|
|||||||
"scripts": "server/config/*.js"
|
"scripts": "server/config/*.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.18.9",
|
"@babel/core": "^7.18.13",
|
||||||
"@babel/eslint-parser": "^7.18.9",
|
"@babel/eslint-parser": "^7.18.9",
|
||||||
"@babel/eslint-plugin": "^7.17.7",
|
"@babel/eslint-plugin": "^7.18.10",
|
||||||
"@babel/plugin-proposal-decorators": "^7.18.9",
|
"@babel/plugin-proposal-decorators": "^7.18.10",
|
||||||
"@babel/preset-env": "^7.18.9",
|
"@babel/preset-env": "^7.18.10",
|
||||||
"@vue/compiler-sfc": "^3.2.22",
|
"@vue/compiler-sfc": "^3.2.22",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"copy-webpack-plugin": "^11.0.0",
|
"copy-webpack-plugin": "^11.0.0",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"css-minimizer-webpack-plugin": "^4.0.0",
|
"css-minimizer-webpack-plugin": "^4.0.0",
|
||||||
"eslint": "^8.20.0",
|
"eslint": "^8.23.0",
|
||||||
"eslint-plugin-vue": "^9.3.0",
|
"eslint-plugin-vue": "^9.4.0",
|
||||||
"html-webpack-plugin": "^5.5.0",
|
"html-webpack-plugin": "^5.5.0",
|
||||||
"mini-css-extract-plugin": "^2.6.1",
|
"mini-css-extract-plugin": "^2.6.1",
|
||||||
"pkg": "^5.8.0",
|
"pkg": "^5.8.0",
|
||||||
"terser-webpack-plugin": "^5.3.3",
|
"terser-webpack-plugin": "^5.3.6",
|
||||||
"vue-eslint-parser": "^9.0.3",
|
"vue-eslint-parser": "^9.0.3",
|
||||||
"vue-loader": "^17.0.0",
|
"vue-loader": "^17.0.0",
|
||||||
"vue-style-loader": "^4.1.3",
|
"vue-style-loader": "^4.1.3",
|
||||||
"webpack": "^5.74.0",
|
"webpack": "^5.74.0",
|
||||||
"webpack-cli": "^4.10.0",
|
"webpack-cli": "^4.10.0",
|
||||||
"webpack-dev-middleware": "^5.3.3",
|
"webpack-dev-middleware": "^5.3.3",
|
||||||
"webpack-hot-middleware": "^2.25.1",
|
"webpack-hot-middleware": "^2.25.2",
|
||||||
"webpack-merge": "^5.8.0",
|
"webpack-merge": "^5.8.0",
|
||||||
"workbox-webpack-plugin": "^6.5.3"
|
"workbox-webpack-plugin": "^6.5.4"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.15.0",
|
"@quasar/extras": "^1.15.2",
|
||||||
"@vue/compat": "^3.2.37",
|
"@vue/compat": "^3.2.38",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"base-x": "^4.0.0",
|
"base-x": "^4.0.0",
|
||||||
"chardet": "^1.4.0",
|
"chardet": "^1.4.0",
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"fs-extra": "^10.1.0",
|
"fs-extra": "^10.1.0",
|
||||||
"he": "^1.2.0",
|
"he": "^1.2.0",
|
||||||
"iconv-lite": "^0.6.3",
|
"iconv-lite": "^0.6.3",
|
||||||
"jembadb": "^3.0.9",
|
"jembadb": "^4.2.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"minimist": "^1.2.6",
|
"minimist": "^1.2.6",
|
||||||
@@ -67,17 +67,17 @@
|
|||||||
"pako": "^2.0.4",
|
"pako": "^2.0.4",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"pidusage": "^3.0.0",
|
"pidusage": "^3.0.0",
|
||||||
"quasar": "^2.7.5",
|
"quasar": "^2.7.7",
|
||||||
"safe-buffer": "^5.2.1",
|
"safe-buffer": "^5.2.1",
|
||||||
"sanitize-html": "^2.7.1",
|
"sanitize-html": "^2.7.1",
|
||||||
"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.1.2",
|
"vue-router": "^4.1.5",
|
||||||
"vuex": "^4.0.2",
|
"vuex": "^4.0.2",
|
||||||
"vuex-persist": "^3.1.3",
|
"vuex-persist": "^3.1.3",
|
||||||
"webdav": "^4.10.0",
|
"webdav": "^4.11.0",
|
||||||
"ws": "^8.8.1",
|
"ws": "^8.8.1",
|
||||||
"zip-stream": "^4.1.0"
|
"zip-stream": "^4.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,8 +177,10 @@ class BUCClient {
|
|||||||
|
|
||||||
const ids = new Set();
|
const ids = new Set();
|
||||||
let id = iter.next();
|
let id = iter.next();
|
||||||
while (!id.done && ids.size < 1000) {
|
while (!id.done) {
|
||||||
ids.add(id.value);
|
ids.add(id.value);
|
||||||
|
if (ids.size >= 1000)
|
||||||
|
break;
|
||||||
id = iter.next();
|
id = iter.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +251,7 @@ class BUCClient {
|
|||||||
this.periodicSendBookUrls();//no await
|
this.periodicSendBookUrls();//no await
|
||||||
this.periodicSync();//no await
|
this.periodicSync();//no await
|
||||||
|
|
||||||
log(`BUC Client started`);
|
log(`BUC Client Worker started`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(LM_FATAL, e.stack);
|
log(LM_FATAL, e.stack);
|
||||||
ayncExit.exit(1);
|
ayncExit.exit(1);
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class BUCServer {
|
|||||||
this.periodicCheckWait = 500;//пауза, если нечего делать
|
this.periodicCheckWait = 500;//пауза, если нечего делать
|
||||||
|
|
||||||
this.cleanQueryInterval = 300*dayMs;//интервал очистки устаревших
|
this.cleanQueryInterval = 300*dayMs;//интервал очистки устаревших
|
||||||
this.oldQueryInterval = 30*dayMs;//интервал устаревания запроса на обновление
|
this.oldQueryInterval = 14*dayMs;//интервал устаревания запроса на обновление
|
||||||
this.checkingInterval = 3*hourMs;//интервал проверки обновления одного и того же файла
|
this.checkingInterval = 5*hourMs;//интервал проверки обновления одного и того же файла
|
||||||
this.sameHostCheckInterval = 1000;//интервал проверки файла на том же сайте, не менее
|
this.sameHostCheckInterval = 1000;//интервал проверки файла на том же сайте, не менее
|
||||||
} else {
|
} else {
|
||||||
this.maxCheckQueueLength = 10;//максимальная длина checkQueue
|
this.maxCheckQueueLength = 10;//максимальная длина checkQueue
|
||||||
@@ -78,8 +78,10 @@ class BUCServer {
|
|||||||
|
|
||||||
const ids = new Set();
|
const ids = new Set();
|
||||||
let id = iter.next();
|
let id = iter.next();
|
||||||
while (!id.done && ids.size < 100) {
|
while (!id.done) {
|
||||||
ids.add(id.value);
|
ids.add(id.value);
|
||||||
|
if (ids.size >= 100)
|
||||||
|
break;
|
||||||
id = iter.next();
|
id = iter.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,6 +136,7 @@ class BUCServer {
|
|||||||
id,
|
id,
|
||||||
queryTime: now,
|
queryTime: now,
|
||||||
checkTime: 0, // 0 - never checked
|
checkTime: 0, // 0 - never checked
|
||||||
|
etag: '',
|
||||||
modTime: '',
|
modTime: '',
|
||||||
size: 0,
|
size: 0,
|
||||||
checkSum: '', //sha256
|
checkSum: '', //sha256
|
||||||
@@ -184,7 +187,7 @@ class BUCServer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rows = await db.select({table: 'buc', count: true});
|
rows = await db.select({table: 'buc', count: true});
|
||||||
log(LM_WARN, `'buc' table length: ${rows[0].count}`);
|
log(LM_WARN, `'buc' table size: ${rows[0].count}`);
|
||||||
|
|
||||||
now = Date.now();
|
now = Date.now();
|
||||||
//выборка кандидатов
|
//выборка кандидатов
|
||||||
@@ -199,25 +202,33 @@ class BUCServer {
|
|||||||
`
|
`
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log(rows);
|
//формирование checkQueue
|
||||||
|
|
||||||
if (rows.length) {
|
if (rows.length) {
|
||||||
const ids = [];
|
const ids = [];
|
||||||
|
const rowsToPush = [];
|
||||||
|
|
||||||
|
//сначала выберем сколько надо
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (this.checkQueue.length >= this.maxCheckQueueLength)
|
if (this.checkQueue.length + rowsToPush.length >= this.maxCheckQueueLength)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
rowsToPush.push(row);
|
||||||
ids.push(row.id);
|
ids.push(row.id);
|
||||||
this.checkQueue.push(row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//установим у них флаг "в обработке"
|
||||||
await db.update({
|
await db.update({
|
||||||
table: 'buc',
|
table: 'buc',
|
||||||
mod: `(r) => r.state = 1`,
|
mod: `(r) => r.state = 1`,
|
||||||
where: `@@id(${db.esc(ids)})`
|
where: `@@id(${db.esc(ids)})`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//пушим в очередь, после этого их обработает periodicCheck
|
||||||
|
for (const row of rowsToPush) {
|
||||||
|
this.checkQueue.push(row);
|
||||||
|
log(LM_INFO, ` add ${row.id}`);
|
||||||
|
}
|
||||||
|
|
||||||
log(LM_WARN, `checkQueue: added ${ids.length} recs, total ${this.checkQueue.length}`);
|
log(LM_WARN, `checkQueue: added ${ids.length} recs, total ${this.checkQueue.length}`);
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
@@ -249,13 +260,22 @@ class BUCServer {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let unchanged = true;
|
let unchanged = true;
|
||||||
let size = 0;
|
|
||||||
let hash = '';
|
let hash = '';
|
||||||
|
|
||||||
const headers = await this.down.head(row.id);
|
const headers = await this.down.head(row.id);
|
||||||
const modTime = headers['last-modified']
|
|
||||||
|
|
||||||
if (!modTime || !row.modTime || (modTime !== row.modTime)) {
|
const etag = headers['etag'] || '';
|
||||||
|
const modTime = headers['last-modified'] || '';
|
||||||
|
let size = parseInt(headers['content-length'], 10) || 0;
|
||||||
|
|
||||||
|
//log(row.id);
|
||||||
|
//log(`etag: ${etag}, modTime: ${modTime}, size: ${size}`)
|
||||||
|
|
||||||
|
if ((!etag || !row.etag || (etag !== row.etag))
|
||||||
|
&& (!modTime || !row.modTime || (modTime !== row.modTime))
|
||||||
|
&& (!size || !row.size || (size !== row.size))
|
||||||
|
) {
|
||||||
|
|
||||||
const downdata = await this.down.load(row.id);
|
const downdata = await this.down.load(row.id);
|
||||||
|
|
||||||
size = downdata.length;
|
size = downdata.length;
|
||||||
@@ -267,6 +287,7 @@ class BUCServer {
|
|||||||
table: 'buc',
|
table: 'buc',
|
||||||
mod: `(r) => {
|
mod: `(r) => {
|
||||||
r.checkTime = ${db.esc(Date.now())};
|
r.checkTime = ${db.esc(Date.now())};
|
||||||
|
r.etag = ${(unchanged ? 'r.etag' : db.esc(etag))};
|
||||||
r.modTime = ${(unchanged ? 'r.modTime' : db.esc(modTime))};
|
r.modTime = ${(unchanged ? 'r.modTime' : db.esc(modTime))};
|
||||||
r.size = ${(unchanged ? 'r.size' : db.esc(size))};
|
r.size = ${(unchanged ? 'r.size' : db.esc(size))};
|
||||||
r.checkSum = ${(unchanged ? 'r.checkSum' : db.esc(hash))};
|
r.checkSum = ${(unchanged ? 'r.checkSum' : db.esc(hash))};
|
||||||
@@ -291,6 +312,8 @@ class BUCServer {
|
|||||||
}`,
|
}`,
|
||||||
where: `@@id(${db.esc(row.id)})`
|
where: `@@id(${db.esc(row.id)})`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
log(LM_ERR, `error ${row.id} > ${e.stack ? e.stack : e.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
(async() => {
|
(async() => {
|
||||||
await utils.sleep(this.sameHostCheckInterval);
|
await utils.sleep(this.sameHostCheckInterval);
|
||||||
@@ -319,9 +342,9 @@ class BUCServer {
|
|||||||
for (let i = 0; i < 10; i++)
|
for (let i = 0; i < 10; i++)
|
||||||
this.periodicCheck();//no await
|
this.periodicCheck();//no await
|
||||||
|
|
||||||
log(`------------------`);
|
log(`-------------------------`);
|
||||||
log(`BUC Server started`);
|
log(`BUC Server Worker started`);
|
||||||
log(`------------------`);
|
log(`-------------------------`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(LM_FATAL, e.stack);
|
log(LM_FATAL, e.stack);
|
||||||
ayncExit.exit(1);
|
ayncExit.exit(1);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
const utils = require('./utils');
|
||||||
|
|
||||||
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';
|
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';
|
||||||
|
|
||||||
@@ -12,7 +13,8 @@ class FileDownloader {
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': userAgent
|
'user-agent': userAgent,
|
||||||
|
timeout: 300*1000,
|
||||||
},
|
},
|
||||||
responseType: 'stream',
|
responseType: 'stream',
|
||||||
};
|
};
|
||||||
@@ -67,7 +69,8 @@ class FileDownloader {
|
|||||||
async head(url) {
|
async head(url) {
|
||||||
const options = {
|
const options = {
|
||||||
headers: {
|
headers: {
|
||||||
'user-agent': userAgent
|
'user-agent': userAgent,
|
||||||
|
timeout: 10*1000,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,25 +78,42 @@ class FileDownloader {
|
|||||||
return res.headers;
|
return res.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamToBuffer(stream, progress) {
|
streamToBuffer(stream, progress, timeout = 30*1000) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|
||||||
if (!progress)
|
if (!progress)
|
||||||
progress = () => {};
|
progress = () => {};
|
||||||
|
|
||||||
const _buf = [];
|
const _buf = [];
|
||||||
|
let resolved = false;
|
||||||
|
let timer = 0;
|
||||||
|
|
||||||
stream.on('data', (chunk) => {
|
stream.on('data', (chunk) => {
|
||||||
|
timer = 0;
|
||||||
_buf.push(chunk);
|
_buf.push(chunk);
|
||||||
progress(chunk);
|
progress(chunk);
|
||||||
});
|
});
|
||||||
stream.on('end', () => resolve(Buffer.concat(_buf)));
|
stream.on('end', () => {
|
||||||
|
resolved = true;
|
||||||
|
timer = timeout;
|
||||||
|
resolve(Buffer.concat(_buf));
|
||||||
|
});
|
||||||
stream.on('error', (err) => {
|
stream.on('error', (err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
stream.on('aborted', () => {
|
stream.on('aborted', () => {
|
||||||
reject(new Error('aborted'));
|
reject(new Error('aborted'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//бодяга с timer и timeout, чтобы гарантировать отсутствие зависания по каким-либо причинам
|
||||||
|
(async() => {
|
||||||
|
while (timer < timeout) {
|
||||||
|
await utils.sleep(1000);
|
||||||
|
timer += 1000;
|
||||||
|
}
|
||||||
|
if (!resolved)
|
||||||
|
reject(new Error('FileDownloader: timed out'))
|
||||||
|
})();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class WorkerState {
|
|||||||
return {
|
return {
|
||||||
set: state => this.setState(workerId, state),
|
set: state => this.setState(workerId, state),
|
||||||
finish: state => this.finishState(workerId, state),
|
finish: state => this.finishState(workerId, state),
|
||||||
get: workerId => this.getState(workerId),
|
get: () => this.getState(workerId),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user