Compare commits

...

13 Commits

Author SHA1 Message Date
dependabot[bot]
34437310f2 Bump webpack from 5.75.0 to 5.76.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-15 09:13:08 +00:00
Book Pauk
1370bae4d6 Merge branch 'release/1.1.3' 2023-02-06 19:47:56 +07:00
Book Pauk
01fbdf38fa Версия 1.1.3 2023-02-06 19:47:28 +07:00
Book Pauk
be6b07a0cf Исправление бага при обнулении libs 2023-02-06 19:45:13 +07:00
Book Pauk
1b057029c8 Улучшено хранение ключа доступа 2023-02-05 16:04:52 +07:00
Book Pauk
b6b567f20b Улучшение парсинга невалидных fb2 2023-02-03 17:30:22 +07:00
Book Pauk
c4c109fe0e Мелкий рефакторинг 2023-02-03 16:28:24 +07:00
Book Pauk
4c8c921b03 Улучшения механизма запуска периодических задач 2023-02-03 16:23:13 +07:00
Book Pauk
69a2e5cda3 Merge tag '1.1.2-1' into develop
1.1.2-1
2023-01-25 17:06:39 +07:00
Book Pauk
c2adf8d5b8 Merge branch 'release/1.1.2-1' 2023-01-25 17:06:35 +07:00
Book Pauk
5c8d257923 Добавлены отладочные сообщения в журнал 2023-01-25 17:05:53 +07:00
Book Pauk
55dae33e60 "jembadb": "^5.1.7" 2023-01-25 15:46:09 +07:00
Book Pauk
57d8e9061f Merge tag '1.1.2' into develop
1.1.2
2023-01-22 20:56:12 +07:00
9 changed files with 224 additions and 173 deletions

View File

@@ -34,8 +34,8 @@ class LibsPage {
if (!this.mode)
return;
//TODO: убрать второе условие в 24г
if (!this.libs || (this.mode === 'omnireader' && this.libs.mode !== this.mode)) {
//TODO: убрать условие с mode в 24г
if (!this.libs || !this.libs.groups || (this.mode === 'omnireader' && this.libs.mode !== this.mode)) {
const defaults = rstore.getLibsDefaults(this.mode);
this.commit('reader/setLibs', defaults);
}

View File

@@ -393,6 +393,9 @@ class Reader {
this.recentItemKeys = [];
//сохранение в удаленном хранилище
await this.$refs.serverStorage.saveRecent(itemKeys);
//periodicTasks
this.periodicTasks();//no await
} catch (e) {
if (!this.offlineModeActive)
this.$root.notify.error(e.message);
@@ -442,26 +445,15 @@ class Reader {
this.$refs.recentBooksPage.init();
})();
//проверки обновлений читалки
//единственный запуск periodicTasks при инициализации
//дальнейшие запуски periodicTasks выполняются из debouncedSaveRecent
//т.е. только по действию пользователя
(async() => {
await utils.sleep(15*1000);
this.isFirstNeedUpdateNotify = true;
//вечный цикл, запрашиваем периодически конфиг для проверки выхода новой версии читалки
while (1) {// eslint-disable-line no-constant-condition
await this.checkNewVersionAvailable();
await utils.sleep(60*60*1000); //каждый час
}
//дальше хода нет
})();
//проверки обновлений книг
(async() => {
await utils.sleep(15*1000); //подождем неск. секунд перед первым запросом
//вечный цикл, запрашиваем периодически обновления
while (1) {// eslint-disable-line no-constant-condition
await this.checkBuc();
await utils.sleep(70*60*1000); //каждые 70 минут
}
//дальше хода нет
this.allowPeriodicTasks = true;
this.periodicTasks();//no await
})();
}
@@ -560,26 +552,56 @@ class Reader {
}
}
async checkNewVersionAvailable() {
if (!this.checkingNewVersion && this.showNeedUpdateNotify) {
this.checkingNewVersion = true;
try {
await utils.sleep(15*1000); //подождем 15 секунд, чтобы прогрузился ServiceWorker при выходе новой версии
const config = await miscApi.loadConfig();
this.commit('config/setConfig', config);
async periodicTasks() {
if (!this.allowPeriodicTasks || this.doingPeriodicTasks)
return;
let againMes = '';
if (this.isFirstNeedUpdateNotify) {
againMes = ' еще один раз';
this.doingPeriodicTasks = true;
try {
if (!this.taskList) {
const taskArr = [
[this.checkNewVersionAvailable, 60], //проверки обновлений читалки, каждый час
[this.checkBuc, 70], //проверки обновлений книг, каждые 70 минут
];
this.taskList = [];
for (const task of taskArr) {
const [method, period] = task;
this.taskList.push({method, period, lastRunTime: 0});
}
}
for (const task of this.taskList) {
if (Date.now() - task.lastRunTime >= task.period*60*1000) {
try {
//console.log('task run', task.method.name);
await task.method();
} catch (e) {
console.error(e);
}
task.lastRunTime = Date.now();
}
}
} catch (e) {
console.error(e);
} finally {
this.doingPeriodicTasks = false;
}
}
async checkNewVersionAvailable() {
if (this.showNeedUpdateNotify) {
const config = await miscApi.loadConfig();
this.commit('config/setConfig', config);
let againMes = '';
if (this.isFirstNeedUpdateNotify) {
againMes = ' еще один раз';
}
if (this.version != this.clientVersion)
this.$root.notify.info(`Вышла новая версия (v${this.version}) читалки.<br>Пожалуйста, обновите страницу${againMes}.`, 'Обновление');
if (this.version != this.clientVersion)
this.$root.notify.info(`Вышла новая версия (v${this.version}) читалки.<br>Пожалуйста, обновите страницу${againMes}.`, 'Обновление');
} catch(e) {
console.error(e);
} finally {
this.checkingNewVersion = false;
}
this.isFirstNeedUpdateNotify = false;
}
}
@@ -588,82 +610,78 @@ class Reader {
if (!this.bothBucEnabled)
return;
try {
const sorted = bookManager.getSortedRecent();
const sorted = bookManager.getSortedRecent();
//выберем все кандидиаты на обновление
const updateUrls = new Set();
for (const book of sorted) {
if (!book.deleted && book.checkBuc && book.url && book.url.indexOf('disk://') !== 0)
updateUrls.add(book.url);
//выберем все кандидиаты на обновление
const updateUrls = new Set();
for (const book of sorted) {
if (!book.deleted && book.checkBuc && book.url && book.url.indexOf('disk://') !== 0)
updateUrls.add(book.url);
}
//теперь по кусочкам запросим сервер
const arr = Array.from(updateUrls);
const bucSize = {};
const chunkSize = 100;
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
const data = await readerApi.checkBuc(chunk);
for (const item of data) {
bucSize[item.id] = item.size;
}
//теперь по кусочкам запросим сервер
const arr = Array.from(updateUrls);
const bucSize = {};
const chunkSize = 100;
for (let i = 0; i < arr.length; i += chunkSize) {
const chunk = arr.slice(i, i + chunkSize);
await utils.sleep(1000);//чтобы не ддосить сервер
}
const data = await readerApi.checkBuc(chunk);
for (const item of data) {
bucSize[item.id] = item.size;
}
await utils.sleep(1000);//чтобы не ддосить сервер
const checkSetTime = {};
//проставим новые размеры у книг
for (const book of sorted) {
if (book.deleted)
continue;
//размер 0 считаем отсутствующим
if (book.url && bucSize[book.url] && bucSize[book.url] !== book.bucSize) {
book.bucSize = bucSize[book.url];
await bookManager.recentSetItem(book);
}
const checkSetTime = {};
//проставим новые размеры у книг
for (const book of sorted) {
if (book.deleted)
continue;
//размер 0 считаем отсутствующим
if (book.url && bucSize[book.url] && bucSize[book.url] !== book.bucSize) {
book.bucSize = bucSize[book.url];
await bookManager.recentSetItem(book);
}
//подготовка к следующему шагу, ищем книгу по url с максимальной датой установки checkBucTime/loadTime
//от этой даты будем потом отсчитывать bucCancelDays
if (updateUrls.has(book.url)) {
let rec = checkSetTime[book.url] || {time: 0, loadTime: 0};
//подготовка к следующему шагу, ищем книгу по 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};
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;
}
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)
;
//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);//!!!
}
if (book && !needBookUpdate) {
await bookManager.setCheckBuc(book, undefined);//!!!
}
}
}
await this.$refs.recentBooksPage.updateTableData();
} catch (e) {
console.error(e);
}
await this.$refs.recentBooksPage.updateTableData();
}
updateCountChanged(event) {
@@ -1409,8 +1427,6 @@ class Reader {
if (!this.showHelpOnErrorIfNeeded(url)) {
this.$root.stdDialog.alert(e.message, 'Ошибка', {color: 'negative'});
}
} finally {
this.checkNewVersionAvailable();
}
}

View File

@@ -22,10 +22,12 @@ const ssCacheStore = localForage.createInstance({
const componentOptions = {
watch: {
serverSyncEnabled: function() {
this.serverSyncEnabledChanged();
if (this.inited)
this.serverSyncEnabledChanged();
},
serverStorageKey: function() {
this.serverStorageKeyChanged(true);
if (this.inited)
this.serverStorageKeyChanged(true);
},
settings: function() {
this.debouncedSaveSettings();
@@ -85,6 +87,13 @@ class ServerStorage {
if (!this.cachedRecentMod)
await this.cleanCachedRecent('cachedRecentMod');
//подстраховка хранения ключа, восстановим из IndexedDB при проблемах в localStorage
if (!this.serverStorageKey) {
const key = await ssCacheStore.getItem('storageKey');
if (key)
this.commit('reader/setServerStorageKey', key);
}
if (!this.serverStorageKey) {
//генерируем новый ключ
await this.generateNewServerStorageKey();
@@ -123,6 +132,7 @@ class ServerStorage {
async generateNewServerStorageKey() {
const key = utils.toBase58(utils.randomArray(32));
this.commit('reader/setServerStorageKey', key);
//дождемся serverStorageKeyChanged, событие по watch не работает при this.inited == false
await this.serverStorageKeyChanged(true);
}
@@ -141,6 +151,10 @@ class ServerStorage {
async serverStorageKeyChanged(force) {
if (this.prevServerStorageKey != this.serverStorageKey) {
this.prevServerStorageKey = this.serverStorageKey;
//сохраним ключ также в IndexedDB, чтобы была возможность восстановить при проблемах с localStorage
await ssCacheStore.setItem('storageKey', this.serverStorageKey);
this.hashedStorageKey = utils.toBase58(cryptoUtils.sha256(this.serverStorageKey));
this.keyInited = true;

View File

@@ -438,61 +438,63 @@ export default class BookParser {
};
const onEndNode = (elemName) => {// eslint-disable-line no-unused-vars
if (tag == elemName) {
if (tag == 'binary') {
binaryId = '';
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
isFirstTitlePara = false;
bold = false;
center = false;
inTitle = false;
}
tag = elemName;
if (tag == 'section') {
sectionLevel--;
}
if (tag == 'emphasis' || tag == 'strong' || tag == 'sup' || tag == 'sub') {
growParagraph(`</${tag}>`, 0);
}
if (tag == 'p') {
inPara = false;
}
if (tag == 'subtitle') {
isFirstTitlePara = false;
bold = false;
center = false;
inSubtitle = false;
}
if (tag == 'epigraph' || tag == 'annotation') {
italic = false;
space -= 1;
newParagraph();
}
if (tag == 'stanza') {
newParagraph();
}
if (tag == 'text-author') {
bold = false;
space -= 1;
}
if (tag == 'binary') {
binaryId = '';
}
if (path.indexOf('/fictionbook/body') == 0) {
if (tag == 'title') {
isFirstTitlePara = false;
bold = false;
center = false;
inTitle = false;
}
path = path.substr(0, path.length - tag.length - 1);
let i = path.lastIndexOf('/');
if (i >= 0) {
tag = path.substr(i + 1);
} else {
if (tag == 'section') {
sectionLevel--;
}
if (tag == 'emphasis' || tag == 'strong' || tag == 'sup' || tag == 'sub') {
growParagraph(`</${tag}>`, 0);
}
if (tag == 'p') {
inPara = false;
}
if (tag == 'subtitle') {
isFirstTitlePara = false;
bold = false;
center = false;
inSubtitle = false;
}
if (tag == 'epigraph' || tag == 'annotation') {
italic = false;
space -= 1;
newParagraph();
}
if (tag == 'stanza') {
newParagraph();
}
if (tag == 'text-author') {
bold = false;
space -= 1;
}
}
let i = path.lastIndexOf(tag);
if (i >= 0) {
path = path.substring(0, i - 1);
i = path.lastIndexOf('/');
if (i >= 0)
tag = path.substring(i + 1);
else
tag = path;
}
}
};

View File

@@ -1,4 +1,17 @@
export const versionHistory = [
{
version: '1.1.3',
releaseDate: '2023-02-06',
showUntil: '2023-02-05',
content:
`
<ul>
<li>исправление багов</li>
</ul>
`
},
{
version: '1.1.2',
releaseDate: '2023-01-22',

View File

@@ -325,7 +325,7 @@ const state = {
currentProfile: '',
settings: _.cloneDeep(settingDefaults),
settingsRev: {},
libs: false,
libs: {},
libsRev: 0,
};

32
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "liberama",
"version": "1.1.2",
"version": "1.1.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "liberama",
"version": "1.1.2",
"version": "1.1.3",
"hasInstallScript": true,
"license": "CC0-1.0",
"dependencies": {
@@ -22,7 +22,7 @@
"fs-extra": "^10.1.0",
"he": "^1.2.0",
"iconv-lite": "^0.6.3",
"jembadb": "^5.1.5",
"jembadb": "^5.1.7",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"minimist": "^1.2.7",
@@ -68,7 +68,7 @@
"vue-eslint-parser": "^9.1.0",
"vue-loader": "^17.0.1",
"vue-style-loader": "^4.1.3",
"webpack": "^5.75.0",
"webpack": "^5.76.0",
"webpack-cli": "^5.0.1",
"webpack-dev-middleware": "^6.0.1",
"webpack-hot-middleware": "^2.25.3",
@@ -5989,9 +5989,9 @@
}
},
"node_modules/jembadb": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/jembadb/-/jembadb-5.1.5.tgz",
"integrity": "sha512-Vb+TkTg3JVXLPTG5BiqboZjJ2wvZRONnLd2+qU4gTuaqt2JSniigbniKSl3kACAEFfuRXEjfs9dLlKWjBX2Aiw==",
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/jembadb/-/jembadb-5.1.7.tgz",
"integrity": "sha512-TNZjiKQ7Zfh89Q1x25PKKtsbkxiC5uOnx953dxJEP6RqfcdR6uVpr4cf+kmyq6IQ1GhwhXTELnoTIdvLWrpEvw==",
"engines": {
"node": ">=16.16.0"
}
@@ -10024,9 +10024,9 @@
"dev": true
},
"node_modules/webpack": {
"version": "5.75.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
"version": "5.76.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
"dev": true,
"dependencies": {
"@types/eslint-scope": "^3.7.3",
@@ -15154,9 +15154,9 @@
}
},
"jembadb": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/jembadb/-/jembadb-5.1.5.tgz",
"integrity": "sha512-Vb+TkTg3JVXLPTG5BiqboZjJ2wvZRONnLd2+qU4gTuaqt2JSniigbniKSl3kACAEFfuRXEjfs9dLlKWjBX2Aiw=="
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/jembadb/-/jembadb-5.1.7.tgz",
"integrity": "sha512-TNZjiKQ7Zfh89Q1x25PKKtsbkxiC5uOnx953dxJEP6RqfcdR6uVpr4cf+kmyq6IQ1GhwhXTELnoTIdvLWrpEvw=="
},
"jest-util": {
"version": "29.3.1",
@@ -18091,9 +18091,9 @@
"dev": true
},
"webpack": {
"version": "5.75.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
"version": "5.76.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz",
"integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.3",

View File

@@ -1,6 +1,6 @@
{
"name": "liberama",
"version": "1.1.2",
"version": "1.1.3",
"author": "Book Pauk <bookpauk@gmail.com>",
"license": "CC0-1.0",
"repository": "bookpauk/liberama",
@@ -45,7 +45,7 @@
"vue-eslint-parser": "^9.1.0",
"vue-loader": "^17.0.1",
"vue-style-loader": "^4.1.3",
"webpack": "^5.75.0",
"webpack": "^5.76.0",
"webpack-cli": "^5.0.1",
"webpack-dev-middleware": "^6.0.1",
"webpack-hot-middleware": "^2.25.3",
@@ -65,7 +65,7 @@
"fs-extra": "^10.1.0",
"he": "^1.2.0",
"iconv-lite": "^0.6.3",
"jembadb": "^5.1.5",
"jembadb": "^5.1.7",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"minimist": "^1.2.7",

View File

@@ -24,6 +24,7 @@ class JembaReaderStorage {
getCache(id) {
const obj = this.cacheMap.get(id);
//обновляем время доступа и при чтении тоже
if (obj)
obj.time = Date.now();
return obj;
@@ -118,6 +119,7 @@ class JembaReaderStorage {
//identity необходимо для работы при нестабильной связи,
//одному и тому же клиенту разрешается перезаписывать данные при расхождении на 0 или 1 ревизию
const obj = this.getCache(id) || {};
const oldIdentity = obj.identity;
const sameClient = (identity && obj.identity === identity);
if (identity && obj.identity !== identity) {
obj.identity = identity;
@@ -126,8 +128,12 @@ class JembaReaderStorage {
const revDiff = items[id].rev - check.items[id].rev;
const allowUpdate = force || revDiff === 1 || (sameClient && (revDiff === 0 || revDiff === 1));
if (!allowUpdate)
if (!allowUpdate) {
log(LM_ERR, `JembaReaderStorage-Reject: revDiff: ${revDiff}, sameClient: ${sameClient}, oldIdentity: ${oldIdentity}, identity: ${identity}`);
return {state: 'reject', items: check.items};
}
}
const db = this.db;