From 06300e30b45c6ac9e04bd4ea3c1a5bea8e4264da Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 14:33:01 +0700 Subject: [PATCH 1/9] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BA=D0=BE=D1=81=D1=82=D1=8B=D0=BB=D1=8C=20-=20?= =?UTF-8?q?=D0=BD=D0=B5=D0=B2=D0=B5=D1=80=D0=BD=D0=B0=D1=8F=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=B4=D0=B8=D1=80=D0=BE=D0=B2=D0=BA=D0=B0=20=D0=BE=D1=82=20kor?= =?UTF-8?q?eader=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=BE=D0=B8=D1=81=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=B2=20opds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/core/opds/SearchPage.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/server/core/opds/SearchPage.js b/server/core/opds/SearchPage.js index 58ae1ba..bbdf768 100644 --- a/server/core/opds/SearchPage.js +++ b/server/core/opds/SearchPage.js @@ -1,5 +1,6 @@ const BasePage = require('./BasePage'); const utils = require('../utils'); +const iconv = require('iconv-lite'); class SearchPage extends BasePage { constructor(config) { @@ -28,7 +29,14 @@ class SearchPage extends BasePage { const limit = 100; const offset = (page - 1)*limit; - const queryRes = await this.webWorker.search(from, {[from]: query.term, genre: query.genre, del: '0', offset, limit}); + + const searchQuery = {[from]: query.term, genre: query.genre, del: '0', offset, limit}; + let queryRes = await this.webWorker.search(from, searchQuery); + + if (queryRes.totalFound === 0) { // не нашли ничего, проверим, может term в кодировке ISO-8859-1 (баг koreader) + searchQuery[from] = iconv.encode(query.term, 'ISO-8859-1').toString(); + queryRes = await this.webWorker.search(from, searchQuery); + } const found = queryRes.found; From 386a93723915088f8a6f17b48af5594e21b92ad0 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 14:34:45 +0700 Subject: [PATCH 2/9] CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3d9497..5c3f955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +1.5.3 / 2023-03-?? + +- Исправление проблемы поиска в opds для koreader + 1.5.2 / 2023-02-05 - Исправление проблемы чтения каталога opds для koreader From 192b92cab866a30cb1b413b99004fa6316d91f91 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 14:58:12 +0700 Subject: [PATCH 3/9] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=B1=D0=B0=D0=B3=D0=B0=20(=D0=BD=D0=B5=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D0=BB=D0=BE=D1=81?= =?UTF-8?q?=D1=8C=20=D0=B8=D0=BC=D1=8F=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D0=B0=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=B5-fb2=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/core/opds/BookPage.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/core/opds/BookPage.js b/server/core/opds/BookPage.js index da04dcb..7ec2b31 100644 --- a/server/core/opds/BookPage.js +++ b/server/core/opds/BookPage.js @@ -147,6 +147,11 @@ class BookPage extends BasePage { title: bookInfo.book.title || 'Без названия', }); + //author bookInfo + if (bookInfo.book.author) { + e.author = bookInfo.book.author.split(',').map(a => ({name: a})); + } + e['dc:language'] = bookInfo.book.lang; e['dc:format'] = fileFormat; @@ -172,7 +177,8 @@ class BookPage extends BasePage { const infoObj = parser.bookInfo(); if (infoObj.titleInfo) { - if (infoObj.titleInfo.author.length) { + //author fb2Info + if (!e.author && infoObj.titleInfo.author.length) { e.author = infoObj.titleInfo.author.map(a => ({name: a})); } From a2423fb704c6df6bd80cc357ddbb47e2741b5bca Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 15:50:26 +0700 Subject: [PATCH 4/9] =?UTF-8?q?opds:=20=D1=83=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=20=D1=81=D0=BA=D0=B0=D1=87=D0=B8=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BB=D1=8F=20=D0=BD=D0=B5-fb2=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=BE=D0=B2=20=D1=84=D0=B0?= =?UTF-8?q?=D0=B9=D0=BB=D0=BE=D0=B2=20(djvu,=20pdf=20=D0=B8=20=D0=BF=D1=80?= =?UTF-8?q?.)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/core/opds/BookPage.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/server/core/opds/BookPage.js b/server/core/opds/BookPage.js index 7ec2b31..72ea59e 100644 --- a/server/core/opds/BookPage.js +++ b/server/core/opds/BookPage.js @@ -130,15 +130,15 @@ class BookPage extends BasePage { //format const ext = bookInfo.book.ext; - let fileFormat = `${ext}+zip`; - let downHref = bookInfo.link; + const formats = { + [`${ext}+zip`]: `${bookInfo.link}/zip`, + [ext]: bookInfo.link, + }; if (ext === 'mobi') { - fileFormat = 'x-mobipocket-ebook'; + formats['x-mobipocket-ebook'] = bookInfo.link; } else if (ext == 'epub') { - // - } else { - downHref = `${bookInfo.link}/zip`; + formats[`${ext}+zip`] = bookInfo.link; } //entry @@ -153,7 +153,7 @@ class BookPage extends BasePage { } e['dc:language'] = bookInfo.book.lang; - e['dc:format'] = fileFormat; + e['dc:format'] = ext; //genre const genre = bookInfo.book.genre.split(','); @@ -200,7 +200,10 @@ class BookPage extends BasePage { } //links - e.link = [ this.downLink({href: downHref, type: `application/${fileFormat}`}) ]; + e.link = []; + for (const [fileFormat, downHref] of Object.entries(formats)) + e.link.push(this.downLink({href: downHref, type: `application/${fileFormat}`})); + if (bookInfo.cover) { let coverType = 'image/jpeg'; if (path.extname(bookInfo.cover) == '.png') From d87e2ce632522a81a019cdf91a9d3ba551f7e2d1 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 15:59:58 +0700 Subject: [PATCH 5/9] CHANGELOG --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3f955..83fc316 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ 1.5.3 / 2023-03-?? -- Исправление проблемы поиска в opds для koreader +- OPDS: исправление проблемы поиска для koreader +- OPDS: улучшено скачивание для не-fb2 форматов файлов (djvu, pdf и пр.) 1.5.2 / 2023-02-05 From 12304c13a1695824ac104c641d579a0d0e6b7cbc Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 18:05:46 +0700 Subject: [PATCH 6/9] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=BB=D0=BE=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=83=D0=B2=D0=B5=D0=B4=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BE=20=D0=B2=D1=8B=D1=85=D0=BE=D0=B4=D0=B5=20=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D0=B8?= =?UTF-8?q?=20(=D0=BE=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B0=D0=B5=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=B2=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B0=D1=85=20=D0=B2=D0=B5=D0=B1-=D0=B8=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81=D0=B0).=20=D0=9F?= =?UTF-8?q?=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=BA=D0=B0=20=D0=BD=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=BC=20?= =?UTF-8?q?checkReleaseLink=20=D0=B2=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8?= =?UTF-8?q?=D0=B3=D0=B5=20=D1=81=D1=80=D0=B5=D0=B2=D0=B5=D1=80=D0=B0=20(#1?= =?UTF-8?q?5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++++++- client/components/Search/Search.vue | 29 +++++++++++++++++-- .../Search/SettingsDialog/SettingsDialog.vue | 10 +++++++ client/components/share/DivBtn.vue | 6 ++-- client/store/root.js | 1 + server/config/base.js | 10 +++++-- server/config/index.js | 2 ++ server/core/WebWorker.js | 28 ++++++++++++++++-- 8 files changed, 87 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7bafd07..eb574cd 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,13 @@ Options: "root": "/opds" }, + // страница для скачивания свежего релиза + "latestReleaseLink": "https://github.com/bookpauk/inpx-web/releases/latest", + + // api для проверки новой версии, + // пустая строка - отключить проверку выхода новых версий + "checkReleaseLink": "https://api.github.com/repos/bookpauk/inpx-web/releases/latest", + // настройки по умолчанию для веб-интерфейса // устанавливаются при первой загрузке страницы в браузере // дальнейшие изменения настроек с помощью веб-интерфейса уже сохраняются в самом браузере @@ -188,7 +195,8 @@ Options: "showDeleted": false, // показывать удаленные "abCacheEnabled": true, // кешировать запросы "langDefault": "", // язык по умолчанию (например "ru,en") - "showJson": false // показывать JSON (в расширенном поиске) + "showJson": false, // показывать JSON (в расширенном поиске) + "showNewReleaseAvailable": true // уведомлять о выходе новой версии } } ``` diff --git a/client/components/Search/Search.vue b/client/components/Search/Search.vue index d995ab9..90d71e9 100644 --- a/client/components/Search/Search.vue +++ b/client/components/Search/Search.vue @@ -3,6 +3,19 @@
+ +
+
+ Доступна новая версия {{ config.name }} v{{ config.latestVersion }} +
+ + Скачать + + + Отключить уведомление + +
+
@@ -504,6 +517,7 @@ class Search { limit = 20; extendedParams = false; showJson = false; + showNewReleaseAvailable = true; //stuff prevList = {}; @@ -555,6 +569,7 @@ class Search { mounted() { (async() => { + //для срабатывания watch.config await this.api.updateConfig(); //устанавливаем uiDefaults от сервера, если это необходимо @@ -604,6 +619,7 @@ class Search { this.abCacheEnabled = settings.abCacheEnabled; this.langDefault = settings.langDefault; this.showJson = settings.showJson; + this.showNewReleaseAvailable = settings.showNewReleaseAvailable; } recvMessage(d) { @@ -631,6 +647,10 @@ class Search { return this.$store.state.config; } + get newReleaseAvailable() { + return (this.config.latestVersion && this.config.version != this.config.latestVersion); + } + get recStruct() { if (this.config.dbConfig && this.config.dbConfig.inpxInfo.recStruct) return this.config.dbConfig.inpxInfo.recStruct; @@ -728,14 +748,19 @@ class Search { } openReleasePage() { - window.open('https://github.com/bookpauk/inpx-web/releases', '_blank'); + if (this.config.latestReleaseLink) + window.open(this.config.latestReleaseLink, '_blank'); } makeProjectName() { const collection = this.config.dbConfig.inpxInfo.collection.split('\n'); this.collection = collection[0].trim(); - this.projectName = `${this.config.name} v${this.config.webAppVersion}`; + let projectName = `${this.config.name} v${this.config.webAppVersion}`; + if (this.newReleaseAvailable) + projectName += `, доступно обновление: v${this.config.latestVersion}`; + + this.projectName = projectName; this.makeTitle(); } diff --git a/client/components/Search/SettingsDialog/SettingsDialog.vue b/client/components/Search/SettingsDialog/SettingsDialog.vue index 42e8074..f7bfbc3 100644 --- a/client/components/Search/SettingsDialog/SettingsDialog.vue +++ b/client/components/Search/SettingsDialog/SettingsDialog.vue @@ -19,6 +19,7 @@ />
+ @@ -85,6 +86,9 @@ const componentOptions = { abCacheEnabled(newValue) { this.commit('setSettings', {'abCacheEnabled': newValue}); }, + showNewReleaseAvailable(newValue) { + this.commit('setSettings', {'showNewReleaseAvailable': newValue}); + }, } }; class SettingsDialog { @@ -105,6 +109,7 @@ class SettingsDialog { showDates = true; showDeleted = false; abCacheEnabled = true; + showNewReleaseAvailable = true; limitOptions = [ {label: '10', value: 10}, @@ -125,6 +130,10 @@ class SettingsDialog { mounted() { } + get config() { + return this.$store.state.config; + } + get settings() { return this.$store.state.settings; } @@ -142,6 +151,7 @@ class SettingsDialog { this.showDates = settings.showDates; this.showDeleted = settings.showDeleted; this.abCacheEnabled = settings.abCacheEnabled; + this.showNewReleaseAvailable = settings.showNewReleaseAvailable; } okClick() { diff --git a/client/components/share/DivBtn.vue b/client/components/share/DivBtn.vue index fa4c841..f7583df 100644 --- a/client/components/share/DivBtn.vue +++ b/client/components/share/DivBtn.vue @@ -89,8 +89,10 @@ export default vueComponent(DivBtn); } .button-pressed { - margin-left: 2px; - margin-top: 2px; + margin-left: 1px; + margin-top: 1px; + margin-right: -1px; + margin-bottom: -1px; } .clickable { diff --git a/client/store/root.js b/client/store/root.js index 357d2c0..71082f7 100644 --- a/client/store/root.js +++ b/client/store/root.js @@ -21,6 +21,7 @@ const state = { abCacheEnabled: true, langDefault: '', showJson: false, + showNewReleaseAvailable: true, }, }; diff --git a/server/config/base.js b/server/config/base.js index c349dd0..2cf732b 100644 --- a/server/config/base.js +++ b/server/config/base.js @@ -6,6 +6,7 @@ const execDir = path.resolve(__dirname, '..'); module.exports = { branch: 'unknown', version: pckg.version, + latestVersion: '', name: pckg.name, execDir, @@ -19,7 +20,7 @@ module.exports = { loggingEnabled: true, //поправить в случае, если были критические изменения в DbCreator или InpxParser - //иначе будет рассинхронизация между сервером и клиентом на уровне БД + //иначе будет рассинхронизация по кешу между сервером и клиентом на уровне БД dbVersion: '11', dbCacheSize: 5, @@ -33,7 +34,7 @@ module.exports = { lowMemoryMode: false, fullOptimization: false, - webConfigParams: ['name', 'version', 'branch', 'bookReadLink', 'dbVersion', 'extendedSearch', 'uiDefaults'], + webConfigParams: ['name', 'version', 'latestVersion', 'branch', 'bookReadLink', 'dbVersion', 'extendedSearch', 'latestReleaseLink', 'uiDefaults'], allowRemoteLib: false, remoteLib: false, @@ -57,6 +58,10 @@ module.exports = { password: '', root: '/opds', }, + + latestReleaseLink: 'https://github.com/bookpauk/inpx-web/releases/latest', + checkReleaseLink: 'https://api.github.com/repos/bookpauk/inpx-web/releases/latest', + uiDefaults: { limit: 20, downloadAsZip: false, @@ -69,6 +74,7 @@ module.exports = { abCacheEnabled: true, langDefault: '', showJson: false, + showNewReleaseAvailable: true, }, }; diff --git a/server/config/index.js b/server/config/index.js index b6549a5..902eded 100644 --- a/server/config/index.js +++ b/server/config/index.js @@ -25,6 +25,8 @@ const propsToSave = [ 'remoteLib', 'server', 'opds', + 'latestReleaseLink', + 'checkReleaseLink', 'uiDefaults', ]; diff --git a/server/core/WebWorker.js b/server/core/WebWorker.js index 657d177..06c4bb8 100644 --- a/server/core/WebWorker.js +++ b/server/core/WebWorker.js @@ -10,6 +10,7 @@ const DbCreator = require('./DbCreator'); const DbSearcher = require('./DbSearcher'); const InpxHashCreator = require('./InpxHashCreator'); const RemoteLib = require('./RemoteLib');//singleton +const FileDownloader = require('./FileDownloader'); const asyncExit = new (require('./AsyncExit'))(); const log = new (require('./AppLogger'))().log;//singleton @@ -28,7 +29,8 @@ const stateToText = { [ssDbCreating]: 'Создание поисковой базы', }; -const cleanDirPeriod = 60*60*1000;//каждый час +const cleanDirInterval = 60*60*1000;//каждый час +const checkReleaseInterval = 2*60*60*1000;//каждые 2 часа //singleton let instance = null; @@ -67,6 +69,7 @@ class WebWorker { this.periodicCleanDir(dirConfig);//no await this.periodicCheckInpx();//no await + this.periodicCheckNewRelease();//no await instance = this; } @@ -638,7 +641,7 @@ class WebWorker { let lastCleanDirTime = 0; while (1) {// eslint-disable-line no-constant-condition //чистка папок - if (Date.now() - lastCleanDirTime >= cleanDirPeriod) { + if (Date.now() - lastCleanDirTime >= cleanDirInterval) { for (const config of dirConfig) { try { await this.cleanDir(config); @@ -690,6 +693,27 @@ class WebWorker { await utils.sleep(inpxCheckInterval*60*1000); } } + + async periodicCheckNewRelease() { + const checkReleaseLink = this.config.checkReleaseLink; + if (!checkReleaseLink) + return; + const down = new FileDownloader(1024*1024); + + while (1) {// eslint-disable-line no-constant-condition + try { + let release = await down.load(checkReleaseLink); + release = JSON.parse(release.toString()); + + if (release.tag_name) + this.config.latestVersion = release.tag_name; + } catch(e) { + log(LM_ERR, `periodicCheckNewRelease: ${e.message}`); + } + + await utils.sleep(checkReleaseInterval); + } + } } module.exports = WebWorker; \ No newline at end of file From a7cd019a97c55b8b2b9a2306e61dbefd80614dab Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 18:12:13 +0700 Subject: [PATCH 7/9] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83fc316..2665a5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - OPDS: исправление проблемы поиска для koreader - OPDS: улучшено скачивание для не-fb2 форматов файлов (djvu, pdf и пр.) +- Добавлена полоска уведомления о выходе новой версии (отключается в настройках веб-интерфейса). + Проверка новой версии настраивается параметром checkReleaseLink в конфиге сревера (#15) 1.5.2 / 2023-02-05 From 27fc46c410b958b49a02ebd12b1209ee145725c2 Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 18:14:38 +0700 Subject: [PATCH 8/9] =?UTF-8?q?=D0=92=D0=B5=D1=80=D1=81=D0=B8=D1=8F=201.5.?= =?UTF-8?q?3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f7fb831..409bd5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "inpx-web", - "version": "1.5.2", + "version": "1.5.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "inpx-web", - "version": "1.5.2", + "version": "1.5.3", "hasInstallScript": true, "license": "CC0-1.0", "dependencies": { diff --git a/package.json b/package.json index 5848d12..6b085f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "inpx-web", - "version": "1.5.2", + "version": "1.5.3", "author": "Book Pauk ", "license": "CC0-1.0", "repository": "bookpauk/inpx-web", From 2c687c7af9bff6ec2984bd54f3b1ba5152b8bbba Mon Sep 17 00:00:00 2001 From: Book Pauk Date: Thu, 2 Mar 2023 18:14:54 +0700 Subject: [PATCH 9/9] CHANGELOG --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2665a5a..d4cb90e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,9 @@ -1.5.3 / 2023-03-?? +1.5.3 / 2023-03-02 - OPDS: исправление проблемы поиска для koreader - OPDS: улучшено скачивание для не-fb2 форматов файлов (djvu, pdf и пр.) - Добавлена полоска уведомления о выходе новой версии (отключается в настройках веб-интерфейса). - Проверка новой версии настраивается параметром checkReleaseLink в конфиге сревера (#15) + Проверка новой версии настраивается параметром checkReleaseLink в конфиге сервера (#15) 1.5.2 / 2023-02-05