Book Pauk 2 лет назад
Родитель
Сommit
428b507257

+ 43 - 43
README.md

@@ -1,43 +1,43 @@
-# Liberama
-
-Браузерная онлайн-читалка книг и децентрализованная библиотека.
-
-Читалка <img src="https://omnireader.ru/favicon.ico" width="14px"/>[OmniReader](https://omnireader.ru) является частью данного проекта, размещенной на VPS:
-
-![](docs/assets/face.jpg)
-![](docs/assets/reader.jpg)
-
-## VPS
-Для разворачивания читалки на чистом VPS с нуля смотрите [docs/omnireader.ru](docs/omnireader.ru/README.md)
-
-## Сборка проекта
-Необходима версия node.js не ниже 14.
-
-```
-$ git clone https://github.com/bookpauk/liberama
-$ cd liberama
-$ npm i
-```
-
-### Windows
-```
-$ npm run build:win
-```
-
-### Linux
-```
-$ npm run build:linux
-```
-
-Результат сборки будет доступен в каталоге `dist/linux|win` в виде исполнимого (standalone) файла
-
-### Разработка
-```
-$ npm run dev
-```
-
-## Помочь проекту
-
-* bitcoin: 3EbgZ7MK1UVaN38Gty5DCBtS4PknM4Ut85
-* litecoin: MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ
-* monero: 8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz
+# Liberama
+
+Браузерная онлайн-читалка книг и децентрализованная библиотека.
+
+Читалка <img src="https://omnireader.ru/favicon.ico" width="14px"/>[OmniReader](https://omnireader.ru) является частью данного проекта, размещенной на VPS:
+
+![](docs/assets/face.jpg)
+![](docs/assets/reader.jpg)
+
+## VPS
+Для разворачивания читалки на чистом VPS с нуля смотрите [docs/omnireader.ru](docs/omnireader.ru/README.md)
+
+## Сборка проекта
+Необходима версия node.js не ниже 14.
+
+```
+$ git clone https://github.com/bookpauk/liberama
+$ cd liberama
+$ npm i
+```
+
+### Windows
+```
+$ npm run build:win
+```
+
+### Linux
+```
+$ npm run build:linux
+```
+
+Результат сборки будет доступен в каталоге `dist/linux|win` в виде исполнимого (standalone) файла
+
+### Разработка
+```
+$ npm run dev
+```
+
+## Помочь проекту
+
+* bitcoin: bc1q3tyumaj648pp2e69jalsez2lnt462ttc33nup9
+* litecoin: MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ
+* monero: 8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz

+ 1 - 1
client/components/App.vue

@@ -238,7 +238,7 @@ class App {
                 const url = s[1] || '';
                 const q = utils.parseQuery(s[0] || '');
                 if (url) {
-                    q.url = decodeURIComponent(url);
+                    q.url = url;
                 }
 
                 window.history.replaceState({}, '', '/');

+ 11 - 105
client/components/Reader/HelpPage/DonateHelpPage/DonateHelpPage.vue

@@ -1,70 +1,17 @@
 <template>
     <div class="page">
-        <div class="box">
+        <div class="column items-center" style="width: 500px">
             <p class="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">                
-                <img class="logo" src="./assets/paypal.png">
-                <div class="para">
-                    {{ paypalAddress }}
-                    <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">                
-                <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>
+            <q-btn no-caps class="q-my-lg" color="green-8" size="14px" style="width: 200px" @click="makeDonation">
+                <q-icon class="q-mr-xs" name="la la-donate" size="24px" />
+                Поддержать проект
+            </q-btn>
 
-            <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 style="font-size: 60%">
+                * Ваш донат является подарком автору проекта
             </div>
         </div>
     </div>
@@ -74,28 +21,14 @@
 //-----------------------------------------------------------------------------
 import vueComponent from '../../../vueComponent.js';
 
-import {copyTextToClipboard} from '../../../../share/utils';
+import * as utils from '../../../../share/utils';
 
 class DonateHelpPage {
-    yooAddress = '410018702323056';
-    paypalAddress = 'bookpauk@gmail.com';
-    bitcoinAddress = '3EbgZ7MK1UVaN38Gty5DCBtS4PknM4Ut85';
-    litecoinAddress = 'MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ';
-    moneroAddress = '8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz';
-
     created() {
     }
 
-    donateYooMoney() {
-        window.open(`https://yoomoney.ru/to/${this.yooAddress}`, '_blank');
-    }
-
-    async copyAddress(address, prefix) {
-        const result = await copyTextToClipboard(address);
-        if (result)
-            this.$root.notify.success(`${prefix} ${address} успешно скопирован в буфер обмена`);
-        else
-            this.$root.notify.error('Копирование не удалось');
+    makeDonation() {
+        utils.makeDonation();
     }
 }
 
@@ -116,31 +49,4 @@ export default vueComponent(DonateHelpPage);
     padding: 0;
     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>

BIN
client/components/Reader/HelpPage/DonateHelpPage/assets/paypal.png


BIN
client/components/Reader/HelpPage/DonateHelpPage/assets/yoomoney.png


+ 5 - 5
client/components/Reader/HelpPage/HelpPage.vue

@@ -1,5 +1,5 @@
 <template>
-    <Window @close="close">
+    <Window @close="close" style="z-index: 200">
         <template #header>
             Справка
         </template>
@@ -36,14 +36,14 @@ import CommonHelpPage from './CommonHelpPage/CommonHelpPage.vue';
 import HotkeysHelpPage from './HotkeysHelpPage/HotkeysHelpPage.vue';
 import MouseHelpPage from './MouseHelpPage/MouseHelpPage.vue';
 import VersionHistoryPage from './VersionHistoryPage/VersionHistoryPage.vue';
-//import DonateHelpPage from './DonateHelpPage/DonateHelpPage.vue';
+import DonateHelpPage from './DonateHelpPage/DonateHelpPage.vue';
 
 const pages = {
     'CommonHelpPage': CommonHelpPage,
     'HotkeysHelpPage': HotkeysHelpPage,
     'MouseHelpPage': MouseHelpPage,
     'VersionHistoryPage': VersionHistoryPage,
-    //'DonateHelpPage': DonateHelpPage,
+    'DonateHelpPage': DonateHelpPage,
 };
 
 const tabs = [
@@ -51,7 +51,7 @@ const tabs = [
     ['MouseHelpPage', 'Мышь/тачскрин'],
     ['HotkeysHelpPage', 'Клавиатура'],
     ['VersionHistoryPage', 'История версий'],
-    //['DonateHelpPage', 'Помочь проекту'],
+    ['DonateHelpPage', 'Помочь проекту'],
 ];
 
 const componentOptions = {
@@ -80,7 +80,7 @@ class HelpPage {
     }
 
     activateDonateHelpPage() {
-        //this.selectedTab = 'DonateHelpPage';
+        this.selectedTab = 'DonateHelpPage';
     }
 
     activateVersionHistoryHelpPage() {

+ 1 - 1
client/components/Reader/LoaderPage/LoaderPage.vue

@@ -57,7 +57,7 @@
         <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 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-else class="bottom-span">Версия сервера {{ version }}, версия клиента {{ clientVersion }}, необходимо обновить страницу</span>

+ 1 - 1
client/components/Reader/Reader.vue

@@ -721,7 +721,7 @@ class Reader {
             return;
         const recent = this.mostRecentBook();
         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)
             this.$router.push(`/reader?${pos}${url}`).catch(() => {});
         else

+ 50 - 58
client/components/Reader/ReaderDialogs/ReaderDialogs.vue

@@ -18,56 +18,51 @@
             </template>
         </Dialog>
 
-        <Dialog ref="dialog2" v-model="donationVisible">
-            <template #header>
-                Здравствуйте, уважаемые читатели!
-            </template>
-
-            <div style="word-break: normal">
-                Стартовала ежегодная акция "Оплатим хостинг вместе".<br><br>
-
-                Для оплаты годового хостинга читалки, необходимо собрать около 2000 рублей.
-                В настоящий момент у автора эта сумма есть в наличии. Однако будет справедливо, если каждый
-                сможет проголосовать рублем за то, чтобы читалка так и оставалась:
-
-                <ul>
-                    <li>непрерывно улучшаемой</li>
-                    <li>без рекламы</li>
-                    <li>без регистрации</li>
-                    <li>Open Source</li>
-                </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>
-                P.S. При необходимости можно воспользоваться подходящим обменником на <a href="https://www.bestchange.ru" target="_blank">bestchange.ru</a>
+        <q-dialog ref="dialog2" v-model="donationVisible" style="z-index: 100" no-route-dismiss no-esc-dismiss no-backdrop-dismiss>
+            <div class="column bg-white no-wrap q-pa-md">
+                <div class="row justify-center q-mb-md" style="font-size: 110%">
+                    Здравствуйте, дорогие читатели!
+                </div>
 
-                <br><br>
-                <div class="row justify-center">
-                    <!--q-btn class="q-px-sm" color="primary" dense no-caps @click="openDonate">
-                        Помочь проекту
-                    </q-btn-->
+                <div class="q-mx-md column" style="word-break: normal">
+                    <div>
+                        Вот уже много лет мы все вместе пользуемся нашей любимой читалкой.<br><br>
+
+                        Напоминаем вам, что проект является некоммерческим и обладает такими
+                        достоинствами, как:
+
+                        <ul>
+                            <li>все функции читалки открыты и доступны совершенно бесплатно</li>
+                            <li>в проекте отсутствует какая-либо реклама или баннеры</li>
+                            <li>нет никакой регистрации и монетизации</li>
+                            <li>нет сбора персональных данных</li>
+                            <li>открытый исходный код</li>
+                            <li>проект постепенно улучшается, по мере возможности</li>
+                        </ul>
+
+                        Однако на оплату хостинга читалки и сервера обновлений автор тратит свои 
+                        собственные средства, а также тратит свое время и силы на улучшение проекта.
+                        <br><br>
+                        Поддержим же материально наш ресурс, чтобы и дальше спокойно существовать и развиваться:
+                    </div>
+
+                    <q-btn style="margin: 10px 50px 10px 50px" color="green-8" size="14px" no-caps @click="makeDonation">
+                        <q-icon class="q-mr-xs" name="la la-donate" size="24px" />
+                        Поддержать проект
+                    </q-btn>
+
+                    <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>
-
-            <template #footer>
-                <span class="clickable row justify-end" style="font-size: 60%; color: grey" @click="donationDialogDisable">Больше не показывать</span>                        
-                <br>
-                <q-btn class="q-px-sm" dense no-caps @click="donationDialogRemind">
-                    Напомнить позже
-                </q-btn>
-            </template>
-        </Dialog>
+        </q-dialog>
 
         <Dialog ref="dialog3" v-model="urlHelpVisible">
             <template #header>
@@ -134,7 +129,7 @@ class ReaderDialogs {
     loadSettings() {
         const settings = this.settings;
         this.showWhatsNewDialog = settings.showWhatsNewDialog;
-        this.showDonationDialog2020 = settings.showDonationDialog2020;
+        this.showDonationDialog = settings.showDonationDialog;
     }
 
     async showWhatsNew() {
@@ -149,9 +144,9 @@ class ReaderDialogs {
     }
 
     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);
             this.donationVisible = true;
         }
@@ -166,20 +161,17 @@ class ReaderDialogs {
         this.urlHelpVisible = false;
     }
 
-    donationDialogDisable() {
+    donationDialogRemind() {
         this.donationVisible = false;
-        if (this.showDonationDialog2020) {
-            this.commit('reader/setSettings', { showDonationDialog2020: false });
-        }
+        this.commit('reader/setDonationRemindDate', utils.formatDate(new Date(), 'coMonth'));
     }
 
-    donationDialogRemind() {
-        this.donationVisible = false;
-        this.commit('reader/setDonationRemindDate', utils.formatDate(new Date(), 'coDate'));
+    makeDonation() {
+        utils.makeDonation();
+        this.donationDialogRemind();
     }
 
     openDonate() {
-        this.donationVisible = false;
         this.$emit('donate-toggle');
     }
 

+ 6 - 0
client/components/Reader/RecentBooksPage/RecentBooksPage.vue

@@ -813,6 +813,12 @@ class RecentBooksPage {
         const book = await bookManager.getRecentBook(item);
         if (book) {
             await bookManager.setCheckBuc(book, item.checkBuc);
+            
+            this.$root.notify.info(item.checkBuc
+                ? 'Проверка обновлений книги включена'
+                : 'Проверка обновлений книги отключена'
+            );
+            
         }
     }
 

+ 5 - 5
client/components/Reader/SettingsPage/OthersTab.inc

@@ -41,15 +41,15 @@
     </q-checkbox>
 </div>
 
-<!--div class="item row">
+<div class="item row">
     <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>
     </q-checkbox>
-</div-->
+</div>
 
 <!---------------------------------------------->
 <div class="part-header">Другое</div>

+ 14 - 0
client/components/Reader/versionHistory.js

@@ -1,4 +1,18 @@
 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',
     releaseDate: '2022-07-27',

+ 7 - 1
client/share/utils.js

@@ -45,6 +45,8 @@ export function formatDate(d, format) {
                 `${d.getHours().toString().padStart(2, '0')}:${d.getMinutes().toString().padStart(2, '0')}`;
         case 'coDate':
             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':
             return `${d.getDate().toString().padStart(2, '0')}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getFullYear()}`;
     }
@@ -409,4 +411,8 @@ export function resizeImage(dataUrl, toWidth, toHeight, quality = 0.9) {
         if (!resolved)
             reject('Не удалось изменить размер');
     })().catch(reject); });
-}
+}
+
+export function makeDonation() {
+    window.open('https://donatty.com/liberama', '_blank');
+}

+ 1 - 1
client/store/modules/reader.js

@@ -180,7 +180,7 @@ const settingDefaults = {
 
     showServerStorageMessages: true,
     showWhatsNewDialog: true,
-    showDonationDialog2020: true,
+    showDonationDialog: true,
     showNeedUpdateNotify: true,
 
     fontShifts: {},

Разница между файлами не показана из-за своего большого размера
+ 293 - 212
package-lock.json


+ 19 - 19
package.json

@@ -1,17 +1,17 @@
 {
   "name": "Liberama",
-  "version": "0.12.0",
+  "version": "0.12.1",
   "author": "Book Pauk <bookpauk@gmail.com>",
   "license": "CC0-1.0",
   "repository": "bookpauk/liberama",
   "engines": {
-    "node": ">=14.4.0"
+    "node": ">=16.16.0"
   },
   "scripts": {
     "dev": "nodemon --inspect --ignore server/public --ignore server/data --ignore client --exec 'node server'",
     "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:win": "npm run build:client && node build/win && pkg -t node14-win-x64 -C GZip -o dist/win/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 node16-win-x64 -C GZip -o dist/win/liberama .",
     "lint": "eslint --ext=.js,.vue client server",
     "build:client-dev": "webpack --config build/webpack.dev.config.js",
     "postinstall": "npm run build:client-dev && node build/linux"
@@ -21,35 +21,35 @@
     "scripts": "server/config/*.js"
   },
   "devDependencies": {
-    "@babel/core": "^7.18.9",
+    "@babel/core": "^7.18.13",
     "@babel/eslint-parser": "^7.18.9",
-    "@babel/eslint-plugin": "^7.17.7",
-    "@babel/plugin-proposal-decorators": "^7.18.9",
-    "@babel/preset-env": "^7.18.9",
+    "@babel/eslint-plugin": "^7.18.10",
+    "@babel/plugin-proposal-decorators": "^7.18.10",
+    "@babel/preset-env": "^7.18.10",
     "@vue/compiler-sfc": "^3.2.22",
     "babel-loader": "^8.2.5",
     "copy-webpack-plugin": "^11.0.0",
     "css-loader": "^6.7.1",
     "css-minimizer-webpack-plugin": "^4.0.0",
-    "eslint": "^8.20.0",
-    "eslint-plugin-vue": "^9.3.0",
+    "eslint": "^8.23.0",
+    "eslint-plugin-vue": "^9.4.0",
     "html-webpack-plugin": "^5.5.0",
     "mini-css-extract-plugin": "^2.6.1",
     "pkg": "^5.8.0",
-    "terser-webpack-plugin": "^5.3.3",
+    "terser-webpack-plugin": "^5.3.6",
     "vue-eslint-parser": "^9.0.3",
     "vue-loader": "^17.0.0",
     "vue-style-loader": "^4.1.3",
     "webpack": "^5.74.0",
     "webpack-cli": "^4.10.0",
     "webpack-dev-middleware": "^5.3.3",
-    "webpack-hot-middleware": "^2.25.1",
+    "webpack-hot-middleware": "^2.25.2",
     "webpack-merge": "^5.8.0",
-    "workbox-webpack-plugin": "^6.5.3"
+    "workbox-webpack-plugin": "^6.5.4"
   },
   "dependencies": {
-    "@quasar/extras": "^1.15.0",
-    "@vue/compat": "^3.2.37",
+    "@quasar/extras": "^1.15.2",
+    "@vue/compat": "^3.2.38",
     "axios": "^0.27.2",
     "base-x": "^4.0.0",
     "chardet": "^1.4.0",
@@ -59,7 +59,7 @@
     "fs-extra": "^10.1.0",
     "he": "^1.2.0",
     "iconv-lite": "^0.6.3",
-    "jembadb": "^3.0.9",
+    "jembadb": "^4.2.0",
     "localforage": "^1.10.0",
     "lodash": "^4.17.21",
     "minimist": "^1.2.6",
@@ -67,17 +67,17 @@
     "pako": "^2.0.4",
     "path-browserify": "^1.0.1",
     "pidusage": "^3.0.0",
-    "quasar": "^2.7.5",
+    "quasar": "^2.7.7",
     "safe-buffer": "^5.2.1",
     "sanitize-html": "^2.7.1",
     "sjcl": "^1.0.8",
     "tar-fs": "^2.1.1",
     "unbzip2-stream": "^1.4.3",
     "vue": "^3.2.37",
-    "vue-router": "^4.1.2",
+    "vue-router": "^4.1.5",
     "vuex": "^4.0.2",
     "vuex-persist": "^3.1.3",
-    "webdav": "^4.10.0",
+    "webdav": "^4.11.0",
     "ws": "^8.8.1",
     "zip-stream": "^4.1.0"
   }

+ 3 - 1
server/core/BookUpdateChecker/BUCClient.js

@@ -177,8 +177,10 @@ class BUCClient {
 
                             const ids = new Set();
                             let id = iter.next();
-                            while (!id.done && ids.size < 1000) {
+                            while (!id.done) {
                                 ids.add(id.value);
+                                if (ids.size >= 1000)
+                                    break;
                                 id = iter.next();
                             }
 

+ 7 - 2
server/core/BookUpdateChecker/BUCServer.js

@@ -78,8 +78,10 @@ class BUCServer {
 
                     const ids = new Set();
                     let id = iter.next();
-                    while (!id.done && ids.size < 100) {
+                    while (!id.done) {
                         ids.add(id.value);
+                        if (ids.size >= 100)
+                            break;
                         id = iter.next();
                     }
 
@@ -222,8 +224,10 @@ class BUCServer {
                     });
 
                     //пушим в очередь, после этого их обработает periodicCheck
-                    for (const row of rowsToPush)
+                    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}`);
                 }
@@ -271,6 +275,7 @@ class BUCServer {
                             && (!modTime || !row.modTime || (modTime !== row.modTime))
                             && (!size || !row.size || (size !== row.size))
                             ) {
+
                             const downdata = await this.down.load(row.id);
 
                             size = downdata.length;

+ 24 - 4
server/core/FileDownloader.js

@@ -1,4 +1,5 @@
 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';
 
@@ -12,7 +13,8 @@ class FileDownloader {
 
         const options = {
             headers: {
-                'user-agent': userAgent
+                'user-agent': userAgent,
+                timeout: 300*1000,
             },
             responseType: 'stream',
         };
@@ -67,7 +69,8 @@ class FileDownloader {
     async head(url) {
         const options = {
             headers: {
-                'user-agent': userAgent
+                'user-agent': userAgent,
+                timeout: 10*1000,
             },
         };
 
@@ -75,25 +78,42 @@ class FileDownloader {
         return res.headers;
     }
 
-    streamToBuffer(stream, progress) {
+    streamToBuffer(stream, progress, timeout = 30*1000) {
         return new Promise((resolve, reject) => {
             
             if (!progress)
                 progress = () => {};
 
             const _buf = [];
+            let resolved = false;
+            let timer = 0;
 
             stream.on('data', (chunk) => {
+                timer = 0;
                 _buf.push(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) => {
                 reject(err);
             });
             stream.on('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'))
+            })();
         });
     }
 }

+ 1 - 1
server/core/WorkerState.js

@@ -25,7 +25,7 @@ class WorkerState {
         return {
             set: state => this.setState(workerId, state),
             finish: state => this.finishState(workerId, state),
-            get: workerId => this.getState(workerId),
+            get: () => this.getState(workerId),
         };
     }
 

Некоторые файлы не были показаны из-за большого количества измененных файлов