diff --git a/.gitignore b/.gitignore
index 11254ed0..8d9e48f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,5 @@
-/node_modules
-/server/data
-/server/public
-/server/ipfs
-/dist
+/node_modules
+/server/.liberama*
+/dist
+dev*.sh
+
diff --git a/README.md b/README.md
index 674324f7..f8a2b627 100644
--- a/README.md
+++ b/README.md
@@ -1,43 +1,156 @@
# Liberama
-Браузерная онлайн-читалка книг и децентрализованная библиотека.
+Браузерная онлайн-читалка книг.
-Читалка [OmniReader](https://omnireader.ru) является частью данного проекта, размещенной на VPS:
+Выглядит соледующим образом: [OmniReader](https://omnireader.ru)


+При запуске приложения, по умолчанию веб-сервер доступен по адресу [http://127.0.0.1:44080](http://127.0.0.1:44080)
+
+Для указания местоположения рабочей директории, воспользуйтесь [параметрами командной строки](#cli).
+Дополнительные параметры сервера настраиваются в [конфигурационном файле](#config).
+
+[Отблагодарить автора проекта](https://donatty.com/liberama)
+
+##
+* [Возможности читалки](#capabilities)
+* [Использование](#usage)
+ * [Параметры командной строки](#cli)
+ * [Конфигурация](#config)
+ * [Разворачивание на VPS](#vps)
+* [Сборка проекта](#build)
+* [Разработка](#development)
+
+
+
+## Возможности читалки
+- загрузка любой страницы интернета
+- синхронизация данных (настроек и читаемых книг) между различными устройствами
+- работа в автономном режиме (без связи)
+- изменение цвета фона, текста, размер и тип шрифта и прочее
+- установка и запоминание текущей позиции и настроек в браузере и на сервере
+- кэширование файлов книг на клиенте и на сервере
+- открытие книг с локального диска
+- плавный скроллинг текста
+- анимация перелистывания
+- поиск по тексту и копирование фрагмента
+- запоминание недавних книг, скачивание книги из читалки в формате fb2
+- управление кликом и с клавиатуры
+- регистрация не требуется
+- поддерживаемые браузеры: Google Chrome, Mozilla Firefox последних версий
+- релизы сервера под Linux, MacOS и Windows
+
+
+
+## Использование
+Приложение представляет собой полноценный веб-сервер в виде единого исполнимого файла.
+При первом запуске, будет создана рабочая директория `.liberama` (по умолчанию - в той же папке, где исполнимый файл),
+в которой хранится конфигурационный файл `config.json`, файлы веб-приложения, файлы базы данных, журналы и прочее.
+Изменить рабочую директорию можно с помощью cli-параметра --app-dir
+
+По умолчанию веб-интерфейс будет доступен по адресу [http://127.0.0.1:44080](http://127.0.0.1:44080)
+
+
+
+### Параметры командной строки
+Запустите `liberama --help`, чтобы увидеть список опций:
+```console
+Usage: liberama [options]
+
+Options:
+ --help Показать опции командной строки
+ --app-dir= Задать рабочую директорию, по умолчанию: /.liberama
+ --auto-repair Починить БД приложения при запуске, если она повреждена
+```
+
+
+
+### Конфигурация
+При первом запуске в рабочей директории будет создан конфигурационный файл `config.json`:
+```js
+{
+ // Максимальный размер файла загружаемой книги (в байтах)
+ "maxUploadFileSize": 52428800,
+
+ // Максимальный размер каталога /public-files/tmp для хранения конвертированных
+ // файлов книг пользователей (в байтах)
+ "maxTempPublicDirSize": 536870912,
+
+ // Максимальный размер каталога /public-files/upload для хранения
+ // загруженных в /upload (кнопка "Загрузить файл с диска") файлов книг пользователей (в байтах)
+ "maxUploadPublicDirSize": 209715200,
+
+ // Использование внешних конвертеров (только в среде Linux)
+ // Без них читалка может работать только с файлами формата fb2, txt, html, xml
+ // Инструкции установки внешних конвертеров см. в docs/omnireader.ru/README.md
+ "useExternalBookConverter": false,
+
+ // Настройки для списка серверов.
+ // Приложение может запускать одновременно несколько веб-серверов на разных портах
+ "servers": [
+ {
+ // Произвольное название сервера
+ "serverName": "1",
+
+ // Режим работы сервера:
+ // "reader" - обычная читалка
+ // "omnireader" - модификации для сайта omnireader.ru
+ // "liberama" - модификации для сайта liberama.top
+ // "book_update_checker" - сервер обновлений
+ "mode": "reader",
+
+ // Хост, порт сервера
+ "ip": "0.0.0.0",
+ "port": "44080"
+ }
+ ],
+
+ // Настройки удаленного хранилища
+ "remoteStorage": false,
+
+ // Для веб-приложения: включение/выключение работы с сервером обновлений
+ "bucEnabled": false,
+
+ // Подключение себя, как клиента, к серверу обновлений
+ "bucServer": false
+}
+```
+
+При необходимости, можно настроить нужный параметр в этом файле вручную.
+
+
+
## VPS
Для разворачивания читалки на чистом VPS с нуля смотрите [docs/omnireader.ru](docs/omnireader.ru/README.md)
-## Сборка проекта
-Необходима версия node.js не ниже 14.
+
-```
-$ git clone https://github.com/bookpauk/liberama
-$ cd liberama
-$ npm i
+### Сборка проекта
+Сборка только в среде Linux.
+Необходима версия node.js не ниже 16.
+
+Для сборки linux-arm64 необходимо предварительно установить [QEMU](https://wiki.debian.org/QemuUserEmulation).
+
+```sh
+git clone https://github.com/bookpauk/liberama
+cd liberama
+npm i
```
-### Windows
-```
-$ npm run build:win
+#### Релизы
+```sh
+npm run release
```
-### Linux
-```
-$ npm run build:linux
-```
+Результат сборки будет доступен в каталоге `dist/release`
-Результат сборки будет доступен в каталоге `dist/linux|win` в виде исполнимого (standalone) файла
+
### Разработка
-```
-$ npm run dev
+```sh
+npm run dev
```
-## Помочь проекту
-
-* bitcoin: bc1q3tyumaj648pp2e69jalsez2lnt462ttc33nup9
-* litecoin: MP39Riec4oSNB3XMjiquKoLWxbufRYNXxZ
-* monero: 8BQPnvHcPSHM5gMQsmuypDgx9NNsYqwXKfDDuswEyF2Q2ewQSfd2pkK6ydH2wmMyq2JViZvy9DQ35hLMx7g72mFWNJTPtnz
+Связаться с автором проекта: [bookpauk@gmail.com](mailto:bookpauk@gmail.com)
diff --git a/build/includer.js b/build/includer.js
deleted file mode 100644
index eff3e452..00000000
--- a/build/includer.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const path = require('path');
-const fs = require('fs');
-
-//пример в коде:
-// @@include('./test/testFile.inc');
-
-function includeRecursive(self, parentFile, source, depth) {
- depth = (depth ? depth : 0);
- if (depth > 50)
- throw new Error('includer: stack too big');
- const lines = source.split('\n');
- let result = [];
- for (const line of lines) {
- const trimmed = line.trim();
- const m = trimmed.match(/^@@[\s]*?include[\s]*?\(['"](.*)['"]\)/);
- if (m) {
- const includedFile = path.resolve(path.dirname(parentFile), m[1]);
- self.addDependency(includedFile);
-
- const fileContent = fs.readFileSync(includedFile, 'utf8');
- result = result.concat(includeRecursive(self, includedFile, fileContent, depth + 1));
- } else {
- result.push(line);
- }
- }
- return result;
-}
-
-exports.default = function includer(source) {
- return includeRecursive(this, this.resourcePath, source).join('\n');
-}
\ No newline at end of file
diff --git a/build/linux.js b/build/linux.js
deleted file mode 100644
index 5abdf1bf..00000000
--- a/build/linux.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const fs = require('fs-extra');
-const path = require('path');
-const util = require('util');
-const stream = require('stream');
-const pipeline = util.promisify(stream.pipeline);
-
-const axios = require('axios');
-const FileDecompressor = require('../server/core/FileDecompressor');
-
-const distDir = path.resolve(__dirname, '../dist');
-const publicDir = `${distDir}/tmp/public`;
-const outDir = `${distDir}/linux`;
-
-const tempDownloadDir = `${distDir}/tmp/download`;
-
-async function main() {
- const decomp = new FileDecompressor();
-
- await fs.emptyDir(outDir);
- // перемещаем public на место
- if (await fs.pathExists(publicDir))
- await fs.move(publicDir, `${outDir}/public`);
-
- await fs.ensureDir(tempDownloadDir);
-
- //ipfs
- const ipfsDecompressedFilename = `${tempDownloadDir}/go-ipfs/ipfs`;
- if (!await fs.pathExists(ipfsDecompressedFilename)) {
- // Скачиваем ipfs
- const ipfsRemoteUrl = 'https://dist.ipfs.io/go-ipfs/v0.4.18/go-ipfs_v0.4.18_linux-amd64.tar.gz';
-
- const res = await axios.get(ipfsRemoteUrl, {responseType: 'stream'})
- await pipeline(res.data, fs.createWriteStream(`${tempDownloadDir}/ipfs.tar.gz`));
- console.log(`done downloading ${ipfsRemoteUrl}`);
-
- //распаковываем
- console.log(await decomp.unpackTarZZ(`${tempDownloadDir}/ipfs.tar.gz`, tempDownloadDir));
- console.log('files decompressed');
- }
-
- // копируем в дистрибутив
- await fs.copy(ipfsDecompressedFilename, `${outDir}/ipfs`);
- console.log(`copied ${tempDownloadDir}/go-ipfs/ipfs to ${outDir}/ipfs`);
- //для development
- const devIpfsFile = path.resolve(__dirname, '../server/ipfs');
- if (!await fs.pathExists(devIpfsFile)) {
- await fs.copy(ipfsDecompressedFilename, devIpfsFile);
- }
-}
-
-main();
diff --git a/build/prepkg.js b/build/prepkg.js
new file mode 100644
index 00000000..ea915758
--- /dev/null
+++ b/build/prepkg.js
@@ -0,0 +1,51 @@
+const fs = require('fs-extra');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const showdown = require('showdown');
+
+const platform = process.argv[2];
+
+const distDir = path.resolve(__dirname, '../dist');
+const tmpDir = `${distDir}/tmp`;
+const publicDir = `${tmpDir}/public`;
+const outDir = `${distDir}/${platform}`;
+
+async function build() {
+ if (!platform)
+ throw new Error(`Please set platform`);
+
+ await fs.emptyDir(outDir);
+
+ //добавляем readme в релиз
+ let readme = await fs.readFile(path.resolve(__dirname, '../README.md'), 'utf-8');
+ const converter = new showdown.Converter();
+ readme = converter.makeHtml(readme);
+ await fs.writeFile(`${outDir}/readme.html`, readme);
+
+ // перемещаем public на место
+ if (await fs.pathExists(publicDir)) {
+
+ const zipFile = `${tmpDir}/public.zip`;
+ const jsonFile = `${distDir}/public.json`;//distDir !!!
+
+ await fs.remove(zipFile);
+ execSync(`zip -r ${zipFile} .`, {cwd: publicDir, stdio: 'inherit'});
+
+ const data = (await fs.readFile(zipFile)).toString('base64');
+ await fs.writeFile(jsonFile, JSON.stringify({data}));
+ } else {
+ throw new Error(`publicDir: ${publicDir} does not exist`);
+ }
+}
+
+async function main() {
+ try {
+ await build();
+ } catch(e) {
+ console.error(e);
+ process.exit(1);
+ }
+}
+
+main();
diff --git a/build/release.js b/build/release.js
new file mode 100644
index 00000000..85839d1d
--- /dev/null
+++ b/build/release.js
@@ -0,0 +1,33 @@
+const fs = require('fs-extra');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const pckg = require('../package.json');
+
+const distDir = path.resolve(__dirname, '../dist');
+const outDir = `${distDir}/release`;
+
+async function makeRelease(target) {
+ const srcDir = `${distDir}/${target}`;
+
+ if (await fs.pathExists(srcDir)) {
+ const zipFile = `${outDir}/${pckg.name}-${pckg.version}-${target}.zip`;
+
+ execSync(`zip -r ${zipFile} .`, {cwd: srcDir, stdio: 'inherit'});
+ }
+}
+
+async function main() {
+ try {
+ await fs.emptyDir(outDir);
+ await makeRelease('win');
+ await makeRelease('linux');
+ await makeRelease('linux-arm64');
+ await makeRelease('macos');
+ } catch(e) {
+ console.error(e);
+ process.exit(1);
+ }
+}
+
+main();
diff --git a/build/webpack.base.config.js b/build/webpack.base.config.js
index a2d6e82d..90a876c2 100644
--- a/build/webpack.base.config.js
+++ b/build/webpack.base.config.js
@@ -30,10 +30,6 @@ module.exports = {
}
}*/
},
- {
- resourceQuery: /^\?vue/,
- use: path.resolve(__dirname, 'includer.js')
- },
{
test: /\.js$/,
loader: 'babel-loader',
diff --git a/build/webpack.dev.config.js b/build/webpack.dev.config.js
index 088f3cf5..19556b5c 100644
--- a/build/webpack.dev.config.js
+++ b/build/webpack.dev.config.js
@@ -1,5 +1,6 @@
const path = require('path');
const webpack = require('webpack');
+const pckg = require('../package.json');
const { merge } = require('webpack-merge');
const baseWpConfig = require('./webpack.base.config');
@@ -8,16 +9,15 @@ baseWpConfig.entry.unshift('webpack-hot-middleware/client');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
-const publicDir = path.resolve(__dirname, '../server/public');
+const publicDir = path.resolve(__dirname, `../server/.${pckg.name}/public`);
const clientDir = path.resolve(__dirname, '../client');
module.exports = merge(baseWpConfig, {
mode: 'development',
devtool: 'inline-source-map',
output: {
- path: `${publicDir}/app`,
+ path: `${publicDir}${baseWpConfig.output.publicPath}`,
filename: 'bundle.js',
- clean: true
},
module: {
diff --git a/build/webpack.prod.config.js b/build/webpack.prod.config.js
index 2ee142b2..fa63de06 100644
--- a/build/webpack.prod.config.js
+++ b/build/webpack.prod.config.js
@@ -17,9 +17,8 @@ const clientDir = path.resolve(__dirname, '../client');
module.exports = merge(baseWpConfig, {
mode: 'production',
output: {
- path: `${publicDir}/app_new`,
+ path: `${publicDir}${baseWpConfig.output.publicPath}`,
filename: 'bundle.[contenthash].js',
- clean: true
},
module: {
rules: [
diff --git a/build/win.js b/build/win.js
deleted file mode 100644
index 016e236b..00000000
--- a/build/win.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const fs = require('fs-extra');
-const path = require('path');
-const util = require('util');
-const stream = require('stream');
-const pipeline = util.promisify(stream.pipeline);
-
-const axios = require('axios');
-const FileDecompressor = require('../server/core/FileDecompressor');
-
-const distDir = path.resolve(__dirname, '../dist');
-const publicDir = `${distDir}/tmp/public`;
-const outDir = `${distDir}/win`;
-
-const tempDownloadDir = `${distDir}/tmp/download`;
-
-async function main() {
- const decomp = new FileDecompressor();
-
- await fs.emptyDir(outDir);
- // перемещаем public на место
- if (await fs.pathExists(publicDir))
- await fs.move(publicDir, `${outDir}/public`);
-
- await fs.ensureDir(tempDownloadDir);
-
- //ipfs
- const ipfsDecompressedFilename = `${tempDownloadDir}/go-ipfs/ipfs.exe`;
- if (!await fs.pathExists(ipfsDecompressedFilename)) {
- // Скачиваем ipfs
- const ipfsRemoteUrl = 'https://dist.ipfs.io/go-ipfs/v0.4.18/go-ipfs_v0.4.18_windows-amd64.zip';
-
- const res = await axios.get(ipfsRemoteUrl, {responseType: 'stream'})
- await pipeline(res.data, fs.createWriteStream(`${tempDownloadDir}/ipfs.zip`));
- console.log(`done downloading ${ipfsRemoteUrl}`);
-
- //распаковываем
- console.log(await decomp.unpack(`${tempDownloadDir}/ipfs.zip`, tempDownloadDir));
- console.log('files decompressed');
- }
- // копируем в дистрибутив
- await fs.copy(ipfsDecompressedFilename, `${outDir}/ipfs.exe`);
- console.log(`copied ${ipfsDecompressedFilename} to ${outDir}/ipfs.exe`);
-}
-
-main();
\ No newline at end of file
diff --git a/client/api/misc.js b/client/api/misc.js
index 141fd3cf..e3c4b3fb 100644
--- a/client/api/misc.js
+++ b/client/api/misc.js
@@ -1,10 +1,5 @@
-import axios from 'axios';
import wsc from './webSocketConnection';
-const api = axios.create({
- baseURL: '/api'
-});
-
class Misc {
async loadConfig() {
@@ -12,18 +7,11 @@ class Misc {
'name', 'version', 'mode', 'maxUploadFileSize', 'useExternalBookConverter', 'acceptFileExt', 'bucEnabled', 'branch',
]};
- try {
- const config = await wsc.message(await wsc.send(Object.assign({action: 'get-config'}, query)));
- if (config.error)
- throw new Error(config.error);
- return config;
- } catch (e) {
- console.error(e);
- }
+ const config = await wsc.message(await wsc.send(Object.assign({action: 'get-config'}, query)));
+ if (config.error)
+ throw new Error(config.error);
- //если с WebSocket проблема, работаем по http
- const response = await api.post('/config', query);
- return response.data;
+ return config;
}
}
diff --git a/client/api/reader.js b/client/api/reader.js
index 1cf1339e..0beb0e07 100644
--- a/client/api/reader.js
+++ b/client/api/reader.js
@@ -7,9 +7,9 @@ const api = axios.create({
baseURL: '/api/reader'
});
-const workerApi = axios.create({
+/*const workerApi = axios.create({
baseURL: '/api/worker'
-});
+});*/
class Reader {
constructor() {
@@ -19,58 +19,24 @@ class Reader {
if (!callback) callback = () => {};
let response = {};
- try {
- const requestId = await wsc.send({action: 'worker-get-state-finish', workerId});
+ const requestId = await wsc.send({action: 'worker-get-state-finish', workerId});
- let prevResponse = false;
- while (1) {// eslint-disable-line no-constant-condition
- response = await wsc.message(requestId);
-
- if (!response.state && prevResponse !== false) {//экономия траффика
- callback(prevResponse);
- } else {//были изменения worker state
- if (!response.state)
- throw new Error('Неверный ответ api');
- callback(response);
- prevResponse = response;
- }
-
- if (response.state == 'finish' || response.state == 'error') {
- break;
- }
- }
- return response;
- } catch (e) {
- console.error(e);
- }
-
- //если с WebSocket проблема, работаем по http
- const refreshPause = 500;
- let i = 0;
- response = {};
+ let prevResponse = false;
while (1) {// eslint-disable-line no-constant-condition
- const prevProgress = response.progress || 0;
- const prevState = response.state || 0;
- response = await workerApi.post('/get-state', {workerId});
- response = response.data;
- callback(response);
+ response = await wsc.message(requestId);
- if (!response.state)
- throw new Error('Неверный ответ api');
+ if (!response.state && prevResponse !== false) {//экономия траффика
+ callback(prevResponse);
+ } else {//были изменения worker state
+ if (!response.state)
+ throw new Error('Неверный ответ api');
+ callback(response);
+ prevResponse = response;
+ }
if (response.state == 'finish' || response.state == 'error') {
break;
}
-
- if (i > 0)
- await utils.sleep(refreshPause);
-
- i++;
- if (i > 180*1000/refreshPause) {//3 мин ждем телодвижений воркера
- throw new Error('Слишком долгое время ожидания');
- }
- //проверка воркера
- i = (prevProgress != response.progress || prevState != response.state ? 1 : i);
}
return response;
@@ -79,14 +45,13 @@ class Reader {
async loadBook(opts, callback) {
if (!callback) callback = () => {};
- let response = await api.post('/load-book', opts);
-
- const workerId = response.data.workerId;
+ let response = await wsc.message(await wsc.send(Object.assign({action: 'load-book'}, opts)));
+ const workerId = response.workerId;
if (!workerId)
throw new Error('Неверный ответ api');
callback({totalSteps: 4});
- callback(response.data);
+ callback(response);
response = await this.getWorkerStateFinish(workerId, callback);
@@ -181,22 +146,13 @@ class Reader {
}
async storage(request) {
- let response = null;
- try {
- response = await wsc.message(await wsc.send({action: 'reader-storage', body: request}));
- } catch (e) {
- console.error(e);
- //если с WebSocket проблема, работаем по http
- response = await api.post('/storage', request);
- response = response.data;
- }
+ const response = await wsc.message(await wsc.send({action: 'reader-storage', body: request}));
- const state = response.state;
- if (!state)
- throw new Error('Неверный ответ api');
- if (state == 'error') {
+ if (response.error)
throw new Error(response.error);
- }
+
+ if (!response.state)
+ throw new Error('Неверный ответ api');
return response;
}
diff --git a/client/components/App.vue b/client/components/App.vue
index 5cd5aa22..5d8a4311 100644
--- a/client/components/App.vue
+++ b/client/components/App.vue
@@ -39,16 +39,6 @@ class App {
_options = componentOptions;
showPage = false;
- itemRuText = {
- '/cardindex': 'Картотека',
- '/reader': 'Читалка',
- '/forum': 'Форум-чат',
- '/income': 'Поступления',
- '/sources': 'Источники',
- '/settings': 'Параметры',
- '/help': 'Справка',
- };
-
created() {
this.commit = this.$store.commit;
this.state = this.$store.state;
@@ -130,7 +120,7 @@ class App {
this.setAppTitle();
(async() => {
- //загрузим конфиг сревера
+ //загрузим конфиг сервера
try {
const config = await miscApi.loadConfig();
this.commit('config/setConfig', config);
@@ -197,12 +187,12 @@ class App {
setAppTitle(title) {
if (!title) {
- if (this.mode == 'liberama.top') {
+ if (this.mode == 'liberama') {
document.title = `Liberama Reader - всегда с вами`;
} else if (this.mode == 'omnireader') {
document.title = `Omni Reader - всегда с вами`;
} else if (this.config && this.mode !== null) {
- document.title = `${this.config.name} - ${this.itemRuText[this.rootRoute]}`;
+ document.title = `Универсальная читалка книг и ресурсов интернета`;
}
} else {
document.title = title;
@@ -217,19 +207,12 @@ class App {
return this.$store.state.config.mode;
}
- get showAsideBar() {
- return (this.mode !== null && this.mode != 'reader' && this.mode != 'omnireader' && this.mode != 'liberama.top');
- }
-
- set showAsideBar(value) {
- }
-
get isReaderActive() {
return (this.rootRoute == '/reader' || this.rootRoute == '/external-libs');
}
redirectIfNeeded() {
- if ((this.mode == 'reader' || this.mode == 'omnireader' || this.mode == 'liberama.top')) {
+ if ((this.mode == 'reader' || this.mode == 'omnireader' || this.mode == 'liberama')) {
const search = window.location.search.substr(1);
//распознавание параметра url вида "?url= " и редирект при необходимости
@@ -271,8 +254,8 @@ body, html, #app {
font: normal 12pt ReaderDefault;
}
-.notify-margin {
- margin-top: 55px;
+.q-notifications__list--top {
+ top: 55px !important;
}
.dborder {
diff --git a/client/components/CardIndex/Book/Book.vue b/client/components/CardIndex/Book/Book.vue
deleted file mode 100644
index beef252c..00000000
--- a/client/components/CardIndex/Book/Book.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел Book в разработке
-
-
-
-
diff --git a/client/components/CardIndex/Card/Card.vue b/client/components/CardIndex/Card/Card.vue
deleted file mode 100644
index 6da789f0..00000000
--- a/client/components/CardIndex/Card/Card.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел Card в разработке
-
-
-
-
diff --git a/client/components/CardIndex/CardIndex.vue b/client/components/CardIndex/CardIndex.vue
deleted file mode 100644
index 5bbcfd18..00000000
--- a/client/components/CardIndex/CardIndex.vue
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/client/components/CardIndex/History/History.vue b/client/components/CardIndex/History/History.vue
deleted file mode 100644
index 9950a8c3..00000000
--- a/client/components/CardIndex/History/History.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел History в разработке
-
-
-
-
diff --git a/client/components/CardIndex/Search/Search.vue b/client/components/CardIndex/Search/Search.vue
deleted file mode 100644
index 1e5072c9..00000000
--- a/client/components/CardIndex/Search/Search.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел Search в разработке
-
-
-
-
diff --git a/client/components/ExternalLibs/BookmarkSettings/BookmarkSettings.vue b/client/components/ExternalLibs/BookmarkSettings/BookmarkSettings.vue
index b43ac51c..162d1b66 100644
--- a/client/components/ExternalLibs/BookmarkSettings/BookmarkSettings.vue
+++ b/client/components/ExternalLibs/BookmarkSettings/BookmarkSettings.vue
@@ -347,6 +347,7 @@ export default vueComponent(BookmarkSettings);
padding: 0px 10px 10px 10px;
overflow-x: auto;
overflow-y: auto;
+ max-width: 520px;
}
.selected {
diff --git a/client/components/ExternalLibs/ExternalLibs.vue b/client/components/ExternalLibs/ExternalLibs.vue
index aa2ddf7f..56881541 100644
--- a/client/components/ExternalLibs/ExternalLibs.vue
+++ b/client/components/ExternalLibs/ExternalLibs.vue
@@ -110,7 +110,7 @@
@@ -304,6 +304,10 @@ class ExternalLibs {
openInFrameOnAdd = false;
frameScale = 1;
+ inpxReady = false;
+ inpxTitle = '';
+ inpxUrl = '';
+
created() {
this.oldStartLink = '';
this.justOpened = true;
@@ -321,8 +325,6 @@ class ExternalLibs {
this.debouncedGoToLink = _.debounce((link) => {
this.goToLink(link);
}, 100, {'maxWait':200});
- //this.commit = this.$store.commit;
- //this.commit('reader/setLibs', rstore.libsDefaults);
}
mounted() {
@@ -334,10 +336,7 @@ class ExternalLibs {
i++;
}
- if (this.mode != 'liberama.top') {
- this.$router.replace('/404');
- return;
- }
+ this.libsDefaults = rstore.getLibsDefaults(this.mode);
this.$refs.window.init();
@@ -348,17 +347,28 @@ class ExternalLibs {
const openerOrigin2 = `https://${openerHost}`;
window.addEventListener('message', (event) => {
+ //from inpx-web
+ if (_.isObject(event.data) && event.data.from === 'inpx-web') {
+ //console.log(event);
+
+ this.inpxOrigin = event.origin;
+
+ this.recvInpxMessage(event.data);
+ return;
+ }
+
+ //from parent
if (event.origin !== openerOrigin1 && event.origin !== openerOrigin2)
return;
+
if (!_.isObject(event.data) || event.data.from != 'LibsPage')
return;
if (event.origin == openerOrigin1)
this.opener = window.opener;
else
this.opener = event.source;
- this.openerOrigin = event.origin;
- //console.log(event);
+ this.openerOrigin = event.origin;
this.recvMessage(event.data);
});
@@ -389,7 +399,8 @@ class ExternalLibs {
}
} else if (d.type == 'libs') {
this.ready = true;
- this.libs = _.cloneDeep(d.data);
+ if (d.data)
+ this.libs = _.cloneDeep(d.data);
} else if (d.type == 'notify') {
this.$root.notify.success(d.data, '', {position: 'bottom-right'});
}
@@ -403,6 +414,30 @@ class ExternalLibs {
})();
}
+ recvInpxMessage(d) {
+ if (d.type == 'mes') {
+ switch(d.data) {
+ case 'hello-from-inpx-web':
+ this.sendInpxMessage({type: 'mes', data: 'ready'});
+ break;
+ case 'ready':
+ this.inpxReady = true;
+ break;
+ }
+ } else if (d.type == 'submitUrl') {
+ this.submitUrl(d.data);
+ } else if (d.type == 'titleChange') {
+ this.inpxTitle = d.data;
+ } else if (d.type == 'urlChange') {
+ this.inpxUrl = d.data;
+ }
+ }
+
+ sendInpxMessage(d) {
+ if (this.$refs.frame && this.inpxOrigin)
+ this.$refs.frame.contentWindow.postMessage(Object.assign({}, {from: 'ExternalLibs'}, d), this.inpxOrigin);
+ }
+
async checkOpener() {
if (this.opener.closed) {
await this.$root.stdDialog.alert('Потеряна связь с читалкой. Окно будет закрыто', 'Ошибка');
@@ -461,7 +496,10 @@ class ExternalLibs {
get header() {
let result = (this.ready ? 'Сетевая библиотека' : 'Загрузка...');
if (this.ready && this.selectedLink) {
- result += ` | ${(this.libs.comment ? this.libs.comment + ' ': '') + lu.removeProtocol(this.libs.startLink)}`;
+ let title = `${(this.libs.comment ? this.libs.comment + ' ': '') + lu.removeProtocol(this.libs.startLink)}`;
+ if (this.inpxReady && this.inpxTitle)
+ title = `${this.inpxTitle} ${lu.removeProtocol(this.inpxUrl)}`;
+ result += ` | ${title}`;
}
this.$root.setAppTitle(result);
return result;
@@ -532,7 +570,7 @@ class ExternalLibs {
get defaultRootLinkOptions() {
let result = [];
- rstore.libsDefaults.groups.forEach(group => {
+ this.libsDefaults.groups.forEach(group => {
result.push({label: lu.removeProtocol(group.r), value: group.r});
});
@@ -561,6 +599,11 @@ class ExternalLibs {
}
goToLink(link) {
+ this.inpxReady = false;
+ this.inpxTitle = '';
+ this.inpxUrl = '';
+ this.inpxOrigin = false;
+
if (!this.ready || !link)
return;
@@ -576,6 +619,7 @@ class ExternalLibs {
this.frameVisible = true;
this.$nextTick(() => {
if (this.$refs.frame) {
+ this.$refs.frame.contentWindow.location.reload(true);
this.$refs.frame.contentWindow.focus();
this.frameResize();
}
@@ -648,13 +692,17 @@ class ExternalLibs {
this.updateStartLink(true);
}
- submitUrl() {
- if (this.bookUrl) {
+ submitUrl(url) {
+ if (!url) {
+ url = this.bookUrl;
+ this.bookUrl = '';
+ }
+
+ if (url) {
this.sendMessage({type: 'submitUrl', data: {
- url: this.bookUrl,
+ url,
force: true
}});
- this.bookUrl = '';
if (this.closeAfterSubmit)
this.close();
}
@@ -668,6 +716,12 @@ class ExternalLibs {
} else {
this.bookmarkLink = this.bookUrl;
this.bookmarkDesc = '';
+
+ if (!this.bookmarkLink && this.inpxReady && this.inpxUrl) {
+ this.bookmarkLink = this.inpxUrl;
+ if (this.inpxTitle)
+ this.bookmarkDesc = this.inpxTitle;
+ }
}
this.addBookmarkMode = mode;
@@ -679,10 +733,10 @@ class ExternalLibs {
}
updateBookmarkLink() {
- const index = lu.getSafeRootIndexByUrl(rstore.libsDefaults.groups, this.defaultRootLink);
+ const index = lu.getSafeRootIndexByUrl(this.libsDefaults.groups, this.defaultRootLink);
if (index >= 0) {
- this.bookmarkLink = rstore.libsDefaults.groups[index].s;
- this.bookmarkDesc = this.getCommentByLink(rstore.libsDefaults.groups[index].list, this.bookmarkLink);
+ this.bookmarkLink = this.libsDefaults.groups[index].s;
+ this.bookmarkDesc = this.getCommentByLink(this.libsDefaults.groups[index].list, this.bookmarkLink);
} else {
this.bookmarkLink = '';
this.bookmarkDesc = '';
@@ -837,20 +891,22 @@ class ExternalLibs {
Окно 'Сетевая библиотека' позволяет открывать ссылки в читалке без переключения между окнами,
что особенно актуально для мобильных устройств. Имеется возможность управлять закладками
на понравившиеся ресурсы, книги или страницы авторов. Открытие ссылок и навигация происходят во фрейме, но,
-к сожалению, в нем открываются не все страницы.
+к сожалению, в нем открываются не все страницы.
` +
-Доступ к сайтам http://flibusta.is и http://fantasy-worlds.org работает через прокси.
+(this.mode === 'liberama' ?
+`
Доступ к сайтам http://flibusta.is и http://fantasy-worlds.org работает через прокси.
ПРЕДУПРЕЖДЕНИЕ!
Доступ предназначен только для просмотра и скачивания книг. Авторизоваться на этих сайтах
из фрейма категорически не рекомендуется, т.к. ваше подключение не защищено и данные могут попасть
к третьим лицам.
+`
+: '') +
-Из-за проблем с безопасностью, навигация 'вперед-назад' во фрейме осуществляется с помощью контекстного меню правой кнопкой мыши.
+`
Из-за проблем с безопасностью, навигация 'вперед-назад' во фрейме осуществляется с помощью контекстного меню правой кнопкой мыши.
На мобильных устройствах для этого служит системная клавиша 'Назад (стрелка влево)' и опция 'Вперед (стрелка вправо)' в меню браузера.
-
Приятного пользования ;-)
`, 'Справка', {iconName: 'la la-info-circle'});
diff --git a/client/components/Help/Help.vue b/client/components/Help/Help.vue
deleted file mode 100644
index de1da849..00000000
--- a/client/components/Help/Help.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел Help в разработке
-
-
-
-
diff --git a/client/components/Income/Income.vue b/client/components/Income/Income.vue
deleted file mode 100644
index 737aeb59..00000000
--- a/client/components/Income/Income.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Раздел Income в разработке
-
-
-
-
diff --git a/client/components/NotFound404/NotFound404.vue b/client/components/NotFound404/NotFound404.vue
deleted file mode 100644
index 336348d1..00000000
--- a/client/components/NotFound404/NotFound404.vue
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
- Страница не найдена
-
-
-
-
diff --git a/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue b/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
index d518ce75..4aebb906 100644
--- a/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
+++ b/client/components/Reader/HelpPage/CommonHelpPage/CommonHelpPage.vue
@@ -24,7 +24,7 @@
Поддерживаемые форматы: fb2, fb2.zip, html, txt и другие.
-
+
Вы можете добавить в свой браузер закладку, указав в ее свойствах вместо адреса следующий код:
{{ bookmarkText }}
diff --git a/client/components/Reader/HelpPage/DonateHelpPage/assets/bitcoin.png b/client/components/Reader/HelpPage/DonateHelpPage/assets/bitcoin.png
deleted file mode 100644
index e80ad6d1..00000000
Binary files a/client/components/Reader/HelpPage/DonateHelpPage/assets/bitcoin.png and /dev/null differ
diff --git a/client/components/Reader/HelpPage/DonateHelpPage/assets/litecoin.png b/client/components/Reader/HelpPage/DonateHelpPage/assets/litecoin.png
deleted file mode 100644
index 900e9b96..00000000
Binary files a/client/components/Reader/HelpPage/DonateHelpPage/assets/litecoin.png and /dev/null differ
diff --git a/client/components/Reader/HelpPage/DonateHelpPage/assets/monero.png b/client/components/Reader/HelpPage/DonateHelpPage/assets/monero.png
deleted file mode 100644
index a5112aea..00000000
Binary files a/client/components/Reader/HelpPage/DonateHelpPage/assets/monero.png and /dev/null differ
diff --git a/client/components/Reader/HelpPage/HotkeysHelpPage/HotkeysHelpPage.vue b/client/components/Reader/HelpPage/HotkeysHelpPage/HotkeysHelpPage.vue
index ff0f541e..733b7beb 100644
--- a/client/components/Reader/HelpPage/HotkeysHelpPage/HotkeysHelpPage.vue
+++ b/client/components/Reader/HelpPage/HotkeysHelpPage/HotkeysHelpPage.vue
@@ -19,7 +19,7 @@
//-----------------------------------------------------------------------------
import vueComponent from '../../../vueComponent.js';
-import UserHotKeys from '../../SettingsPage/UserHotKeys/UserHotKeys.vue';
+import UserHotKeys from '../../SettingsPage/KeysTab/UserHotKeys/UserHotKeys.vue';
const componentOptions = {
components: {
diff --git a/client/components/Reader/HelpPage/MouseHelpPage/MouseHelpPage.vue b/client/components/Reader/HelpPage/MouseHelpPage/MouseHelpPage.vue
index 3e819403..17be9055 100644
--- a/client/components/Reader/HelpPage/MouseHelpPage/MouseHelpPage.vue
+++ b/client/components/Reader/HelpPage/MouseHelpPage/MouseHelpPage.vue
@@ -13,7 +13,7 @@
Жесты для тачскрина:
- от центра вверх: на весь экран
+ от центра вверх/двойной тап по центру: на весь экран
от центра вниз: плавный скроллинг
diff --git a/client/components/Reader/LibsPage/LibsPage.vue b/client/components/Reader/LibsPage/LibsPage.vue
index 16352849..4a85c2e7 100644
--- a/client/components/Reader/LibsPage/LibsPage.vue
+++ b/client/components/Reader/LibsPage/LibsPage.vue
@@ -8,7 +8,7 @@ import vueComponent from '../../vueComponent.js';
import Window from '../../share/Window.vue';
import * as utils from '../../../share/utils';
-//import rstore from '../../../store/modules/reader';
+import rstore from '../../../store/modules/reader';
import _ from 'lodash';
const componentOptions = {
@@ -28,13 +28,18 @@ class LibsPage {
this.popupWindow = null;
this.commit = this.$store.commit;
this.messageListener = null;
- //this.commit('reader/setLibs', rstore.libsDefaults);
}
- init() {
- if (this.mode != 'liberama.top')
+ async init() {
+ if (!this.mode)
return;
+ //TODO: убрать второе условие в 24г
+ if (!this.libs || (this.mode === 'omnireader' && this.libs.mode !== this.mode)) {
+ const defaults = rstore.getLibsDefaults(this.mode);
+ this.commit('reader/setLibs', defaults);
+ }
+
this.childReady = false;
const subdomain = (window.location.protocol != 'http:' ? 'b.' : '');
this.origin = `http://${subdomain}${window.location.host}`;
diff --git a/client/components/Reader/LoaderPage/LoaderPage.vue b/client/components/Reader/LoaderPage/LoaderPage.vue
index 1c8b9f13..9bbaedc6 100644
--- a/client/components/Reader/LoaderPage/LoaderPage.vue
+++ b/client/components/Reader/LoaderPage/LoaderPage.vue
@@ -1,6 +1,6 @@
-
+
@@ -55,7 +55,6 @@
- Найти книгу
Справка
Помочь проекту
@@ -64,18 +63,6 @@
-
-
-
- Подсказка ;-)
-
-
-
- Если вы хотите найти определенную книгу, добро пожаловать в
- раздел "Сетевая библиотека" (кнопка
) на сайте читалки
-
liberama.top
-
-
@@ -103,7 +90,6 @@ class LoaderPage {
bookUrl = null;
loadPercent = 0;
pasteTextActive = false;
- findBookVisible = false;
created() {
this.commit = this.$store.commit;
@@ -122,7 +108,7 @@ class LoaderPage {
get title() {
if (this.mode == 'omnireader')
return 'Omni Reader - браузерная онлайн-читалка.';
- if (this.mode == 'liberama.top')
+ if (this.mode == 'liberama')
return 'Liberama Reader - браузерная онлайн-читалка.';
return 'Универсальная читалка книг и ресурсов интернета.';
@@ -193,10 +179,6 @@ class LoaderPage {
this.$emit('do-action', {action: 'donate'});
}
- findBook() {
- this.findBookVisible = true;
- }
-
openComments() {
window.open('http://samlib.ru/comment/b/bookpauk/bookpauk_reader', '_blank');
}
@@ -213,9 +195,6 @@ class LoaderPage {
}
keyHook(event) {
- if (this.$refs.dialog1.active)
- return true;
-
if (this.pasteTextActive) {
return this.$refs.pasteTextPage.keyHook(event);
}
diff --git a/client/components/Reader/LoaderPage/PasteTextPage/PasteTextPage.vue b/client/components/Reader/LoaderPage/PasteTextPage/PasteTextPage.vue
index 3647999d..a197396e 100644
--- a/client/components/Reader/LoaderPage/PasteTextPage/PasteTextPage.vue
+++ b/client/components/Reader/LoaderPage/PasteTextPage/PasteTextPage.vue
@@ -60,7 +60,7 @@ class PasteTextPage {
calcTitle(event) {
if (this.bookTitle == '') {
- this.bookTitle = `Из буфера обмена ${utils.formatDate(new Date(), 'noDate')}`;
+ this.bookTitle = `Из буфера обмена ${utils.dateFormat(new Date())}`;
if (event) {
let text = event.clipboardData.getData('text');
this.bookTitle += ': ' + _.compact([
diff --git a/client/components/Reader/Reader.vue b/client/components/Reader/Reader.vue
index c8fd99c0..98ee34fd 100644
--- a/client/components/Reader/Reader.vue
+++ b/client/components/Reader/Reader.vue
@@ -1,139 +1,138 @@