+
+
+
+ Доступна новая версия {{ 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/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",
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
diff --git a/server/core/opds/BookPage.js b/server/core/opds/BookPage.js
index da04dcb..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
@@ -147,8 +147,13 @@ 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;
+ e['dc:format'] = ext;
//genre
const genre = bookInfo.book.genre.split(',');
@@ -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}));
}
@@ -194,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')
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;