Ver Fonte

Merge branch 'release/0.6.8'

Book Pauk há 6 anos atrás
pai
commit
e671e4b6f5

+ 13 - 3
client/components/Reader/LoaderPage/LoaderPage.vue

@@ -22,7 +22,15 @@
                 Из буфера обмена
             </el-button>
             <div class="space"></div>
-            <span v-if="mode == 'omnireader'" class="bottom-span clickable" @click="openComments">Комментарии</span>
+            <div class="space"></div>
+            <div v-if="mode == 'omnireader'" ref="yaShare2" class="ya-share2" 
+                data-services="collections,vkontakte,facebook,odnoklassniki,twitter,telegram"
+                data-description="Чтение fb2-книг онлайн. Загрузка любой страницы интернета одним кликом, синхронизация между устройствами, удобное управление, регистрация не требуется."
+                data-title="Omni Reader - браузерная онлайн-читалка"
+                data-url="http://omnireader.ru">
+            </div>
+            <div class="space"></div>
+            <span v-if="mode == 'omnireader'" class="bottom-span clickable" @click="openComments">Отзывы о читалке</span>
         </div>
 
         <div class="part bottom">
@@ -57,6 +65,8 @@ class LoaderPage extends Vue {
 
     mounted() {
         this.progress = this.$refs.progress;
+        if (this.mode == 'omnireader')
+            Ya.share2(this.$refs.yaShare2);// eslint-disable-line no-undef
     }
 
     activated() {
@@ -64,7 +74,7 @@ class LoaderPage extends Vue {
     }
 
     get title() {
-        if (this.$store.state.config.mode == 'omnireader')
+        if (this.mode == 'omnireader')
             return 'Omni Reader - браузерная онлайн-читалка.';
         return 'Универсальная читалка книг и ресурсов интернета.';
 
@@ -160,7 +170,7 @@ class LoaderPage extends Vue {
     flex: 1;
     display: flex;
     flex-direction: column;
-    min-height: 340px;
+    min-height: 400px;
 }
 
 .part {

+ 9 - 6
client/components/Reader/LoaderPage/PasteTextPage/PasteTextPage.vue

@@ -26,6 +26,7 @@ import Component from 'vue-class-component';
 
 import Window from '../../../share/Window.vue';
 import _ from 'lodash';
+import * as utils from '../../../../share/utils';
 
 export default @Component({
     components: {
@@ -42,7 +43,7 @@ class PasteTextPage extends Vue {
         this.$refs.textArea.focus();
     }
 
-    getNonEmptyLine(text, count) {
+    getNonEmptyLine3words(text, count) {
         let result = '';
         const lines = text.split("\n");
         let i = 0;
@@ -56,21 +57,23 @@ class PasteTextPage extends Vue {
             }
             i++;
         }
-        return result;
+
+        result = result.trim().split(' ');
+        return result.slice(0, 3).join(' ');
     }
 
     calcTitle(event) {
         if (this.bookTitle == '') {
             let text = event.clipboardData.getData('text');
-            this.bookTitle = _.compact([
-                this.getNonEmptyLine(text, 1),
-                this.getNonEmptyLine(text, 2)
+            this.bookTitle = `Из буфера обмена ${utils.formatDate(new Date(), 'noDate')}: ` + _.compact([
+                this.getNonEmptyLine3words(text, 1),
+                this.getNonEmptyLine3words(text, 2)
             ]).join(' - ');
         }
     }
 
     loadBuffer() {
-        this.$emit('load-buffer', {buffer: `<title>${this.bookTitle}</title>${this.$refs.textArea.value}`});
+        this.$emit('load-buffer', {buffer: `<cut-title>${this.bookTitle}</cut-title>${this.$refs.textArea.value}`});
         this.close();
     }
 

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

@@ -381,6 +381,8 @@
                                         <el-option label="Вправо-влево" value="rightShift"></el-option>
                                         <el-option label="Протаивание" value="thaw"></el-option>
                                         <el-option label="Мерцание" value="blink"></el-option>
+                                        <el-option label="Вращение" value="rotate"></el-option>
+                                        <el-option v-show="wallpaper == ''" label="Листание" value="flip"></el-option>
                                     </el-select>
                                 </el-col>
                             </el-form-item>
@@ -539,6 +541,10 @@ export default @Component({
             const font = (newValue ? newValue : this.fontName);
             this.vertShift = this.fontShifts[font] || 0;
         },
+        wallpaper: function(newValue) {
+            if (newValue != '' && this.pageChangeAnimation == 'flip')
+                this.pageChangeAnimation = '';
+        },
     },
 })
 class SettingsPage extends Vue {

+ 54 - 0
client/components/Reader/TextPage/DrawHelper.js

@@ -317,4 +317,58 @@ export default class DrawHelper {
             await animation1Finish(duration);
         }
     }
+
+    async doPageAnimationRotate(page1, page2, duration, isDown, animation1Finish, animation2Finish) {
+        if (isDown) {
+            page1.style.transform = `rotateY(90deg)`;
+            await sleep(30);
+
+            page2.style.transition = `${duration/2}ms ease-in`;
+            page2.style.transform = `rotateY(-90deg)`;
+
+            await animation2Finish(duration/2);
+
+            page1.style.transition = `${duration/2}ms ease-out`;
+            page1.style.transform = `rotateY(0deg)`;
+            await animation1Finish(duration/2);
+        } else {
+            page1.style.transform = `rotateY(-90deg)`;
+            await sleep(30);
+
+            page2.style.transition = `${duration/2}ms ease-in`;
+            page2.style.transform = `rotateY(90deg)`;
+
+            await animation2Finish(duration/2);
+
+            page1.style.transition = `${duration/2}ms ease-out`;
+            page1.style.transform = `rotateY(0deg)`;
+            await animation1Finish(duration/2);
+        }
+    }
+
+    async doPageAnimationFlip(page1, page2, duration, isDown, animation1Finish, animation2Finish, backgroundColor) {
+        page2.style.background = backgroundColor;
+
+        if (isDown) {
+            page2.style.transformOrigin = '10%';
+            await sleep(30);
+
+            page2.style.transformOrigin = '0%';
+            page2.style.transition = `${duration}ms ease-in-out`;
+            page2.style.transform = `rotateY(-120deg)`;
+            await animation2Finish(duration);
+        } else {
+            page2.style.transformOrigin = '90%';
+            await sleep(30);
+
+            page2.style.transformOrigin = '100%';
+            page2.style.transition = `${duration}ms ease-in-out`;
+            page2.style.transform = `rotateY(120deg)`;
+            await animation2Finish(duration);
+        }
+
+        page2.style.transformOrigin = 'center';
+        page2.style.background = '';
+    }
+
 }

+ 32 - 18
client/components/Reader/TextPage/TextPage.vue

@@ -23,7 +23,6 @@
             oncontextmenu="return false;">
             <div v-show="showStatusBar" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop
                 @click.prevent.stop="onStatusBarClick"></div>
-            <div v-show="fontsLoading" ref="fontsLoading"></div>
         </div>
         <div v-show="!clickControl && showStatusBar" class="layout" v-html="statusBarClickable" @mousedown.prevent.stop @touchstart.stop
             @click.prevent.stop="onStatusBarClick"></div>
@@ -77,7 +76,6 @@ class TextPage extends Vue {
     page2 = null;
     statusBar = null;
     statusBarClickable = null;
-    fontsLoading = null;
 
     lastBook = null;
     bookPos = 0;
@@ -203,21 +201,6 @@ class TextPage extends Vue {
         this.drawHelper.lineHeight = this.lineHeight;
         this.drawHelper.context = this.context;
 
-        //сообщение "Загрузка шрифтов..."
-        this.$refs.fontsLoading.innerHTML = '';
-        (async() => {
-            await sleep(500);
-            const flText = 'Загрузка шрифта';
-            this.$refs.fontsLoading.innerHTML = flText + ' &nbsp;<i class="el-icon-loading"></i>';
-            const fontsLoadingStyle = this.$refs.fontsLoading.style;
-            fontsLoadingStyle.position = 'absolute';
-            fontsLoadingStyle.fontSize = this.fontSize + 'px';
-            fontsLoadingStyle.top = (this.realHeight/2 - 2*this.fontSize) + 'px';
-            fontsLoadingStyle.left = (this.realWidth - this.drawHelper.measureText(flText, {}))/2 + 'px';
-            await sleep(10500);
-            this.$refs.fontsLoading.innerHTML = '';
-        })();
-
         //parsed
         if (this.parsed) {
             this.parsed.p = this.p;
@@ -245,6 +228,10 @@ class TextPage extends Vue {
             y += this.statusBarHeight*(this.statusBarTop ? 1 : 0);
         let page1 = this.$refs.scrollBox1;
         let page2 = this.$refs.scrollBox2;
+        
+        page1.style.perspective = '3072px';
+        page2.style.perspective = '3072px';
+
         page1.style.width = this.w + this.indentLR + 'px';
         page2.style.width = this.w + this.indentLR + 'px';
         page1.style.height = this.scrollHeight - (pageSpace > 0 ? pageSpace : 0) + 'px';
@@ -274,6 +261,18 @@ class TextPage extends Vue {
     async loadFonts() {
         this.fontsLoading = true;
 
+        let inst = null;
+        (async() => {
+            await sleep(500);
+            if (this.fontsLoading)
+                inst = this.$notify({
+                  title: '',
+                  dangerouslyUseHTMLString: true,
+                  message: 'Загрузка шрифта &nbsp;<i class="el-icon-loading"></i>',
+                  duration: 0
+                });
+        })();
+
         if (!this.fontsLoaded)
             this.fontsLoaded = {};
         //загрузка дин.шрифта
@@ -304,6 +303,8 @@ class TextPage extends Vue {
         }
 
         this.fontsLoading = false;
+        if (inst)
+            inst.close();
     }
 
     getSettings() {
@@ -631,7 +632,7 @@ class TextPage extends Vue {
             const animation1Finish = this.generateWaitingFunc('resolveAnimation1Finish', 'stopAnimation');
             const animation2Finish = this.generateWaitingFunc('resolveAnimation2Finish', 'stopAnimation');
             const transition1Finish = this.generateWaitingFunc('resolveTransition1Finish', 'stopAnimation');
-            //const transition2Finish = this.generateWaitingFunc('resolveTransition2Finish', 'stopAnimation');
+            const transition2Finish = this.generateWaitingFunc('resolveTransition2Finish', 'stopAnimation');
             
             const duration = Math.round(3000*(1 - this.pageChangeAnimationSpeed/100));
             let page1 = this.$refs.scrollingPage1;
@@ -660,6 +661,14 @@ class TextPage extends Vue {
                     page1.style.height = this.scrollHeight + this.lineHeight + 'px';
                     page2.style.height = this.scrollHeight + this.lineHeight + 'px';
                     break;
+                case 'rotate':
+                    await this.drawHelper.doPageAnimationRotate(page1, page2, 
+                        duration, this.pageChangeDirectionDown, transition1Finish, transition2Finish);
+                    break;
+                case 'flip':
+                    await this.drawHelper.doPageAnimationFlip(page1, page2, 
+                        duration, this.pageChangeDirectionDown, transition1Finish, transition2Finish, this.backgroundColor);
+                    break;
             }
             
             this.resolveAnimation1Finish = null;
@@ -1126,6 +1135,10 @@ class TextPage extends Vue {
     overflow: hidden;
 }
 
+.on-top {
+    z-index: 100;
+}
+
 .back {
     z-index: 5;
 }
@@ -1191,4 +1204,5 @@ class TextPage extends Vue {
     0%   { opacity: 1; }
     100% { opacity: 0; }
 }
+
 </style>

+ 43 - 4
client/components/Reader/share/bookManager.js

@@ -143,6 +143,34 @@ class BookManager {
         }
     }
 
+
+    async deflateWithProgress(data, callback) {
+        const chunkSize = 16384;
+        const deflator = new utils.pako.Deflate({level: 9});
+
+        let chunkTotal = 1 + Math.floor(data.length/chunkSize);
+        let chunkNum = 0;
+
+        for (var i = 0; i < data.length; i += chunkSize) {
+            if ((i + chunkSize) >= data.length) {
+                deflator.push(data.substring(i, i + chunkSize), true);
+            } else {
+                deflator.push(data.substring(i, i + chunkSize), false);
+            }
+            chunkNum++;
+            callback(Math.round(chunkNum/chunkTotal*100));
+            await utils.sleep(1);
+        }
+
+        if (deflator.err) {
+            throw new Error(deflator.msg);
+        }
+        
+        callback(100);
+
+        return deflator.result;
+    }
+
     async addBook(newBook, callback) {
         if (!this.books) 
             await this.init();
@@ -151,7 +179,12 @@ class BookManager {
         meta.addTime = Date.now();
 
         const cb = (perc) => {
-            const p = Math.round(80*perc/100);
+            const p = Math.round(30*perc/100);
+            callback(p);
+        };
+
+        const cb2 = (perc) => {
+            const p = Math.round(30 + 65*perc/100);
             callback(p);
         };
 
@@ -160,10 +193,11 @@ class BookManager {
 
         let data = newBook.data;
         if (result.dataCompressed) {
-            data = utils.pako.deflate(data, {level: 9});
+            //data = utils.pako.deflate(data, {level: 9});
+            data = await this.deflateWithProgress(data, cb2);
             result.dataCompressedLength = data.byteLength;
         }
-        callback(90);
+        callback(95);
 
         this.books[meta.key] = result;
         this.booksCached[meta.key] = this.metaOnly(result);
@@ -202,7 +236,12 @@ class BookManager {
             await utils.sleep(10);
 
             if (result.dataCompressed) {
-                data = utils.pako.inflate(data, {to: 'string'});
+                try {
+                    data = utils.pako.inflate(data, {to: 'string'});
+                } catch (e) {
+                    this.delBook(meta);
+                    throw e;
+                }
             }
             callback(20);
 

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

@@ -1,4 +1,20 @@
 export const versionHistory = [
+{
+    showUntil: '2019-06-22',
+    header: '0.6.8 (2019-06-23)',
+    content:
+`
+<ul>
+    <li>исправлен баг - падение сервера при распаковке битых архивов книг</li>
+    <li>исправлен баг - не распознавались некоторые книги формата fb2 в кодировке utf8</li>
+    <li>добавлены новые варианты анимации перелистывания</li>
+    <li>на страницу загрузки добавлен блок "Поделиться"</li>
+    <li>улучшены прогрессбары</li>
+    <li>исправления недочетов</li>
+</ul>
+`
+},
+
 {
     showUntil: '2019-06-05',
     header: '0.6.7 (2019-05-30)',

+ 1 - 0
client/index.html.template

@@ -9,5 +9,6 @@
   </head>
   <body>
     <div id="app"></div>
+    <script src="https://yastatic.net/share2/share.js" async="async"></script>
   </body>
 </html>

+ 2 - 0
client/share/utils.js

@@ -41,6 +41,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 'noDate':
+            return `${d.getDate().toString().padStart(2, '0')}.${(d.getMonth() + 1).toString().padStart(2, '0')}.${d.getFullYear()}`;
     }
     
 }

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

@@ -153,7 +153,7 @@ const settingDefaults = {
     indentLR: 15,// px, отступ всего текста слева и справа
     indentTB: 0,// px, отступ всего текста сверху и снизу
     wordWrap: true,//перенос по слогам
-    keepLastToFirst: true,// перенос последней строки в первую при листании
+    keepLastToFirst: false,// перенос последней строки в первую при листании
 
     showStatusBar: true,
     statusBarTop: false,// top, bottom
@@ -163,7 +163,7 @@ const settingDefaults = {
     scrollingDelay: 3000,// замедление, ms
     scrollingType: 'ease-in-out', //linear, ease, ease-in, ease-out, ease-in-out
 
-    pageChangeAnimation: 'blink',// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание
+    pageChangeAnimation: 'flip',// '' - нет, downShift, rightShift, thaw - протаивание, blink - мерцание, rotate - вращение, flip - листание
     pageChangeAnimationSpeed: 80, //0-100%
 
     allowUrlParamBookPos: false,

+ 108 - 75
package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "Liberama",
-  "version": "0.6.5",
+  "version": "0.6.7",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1623,6 +1623,15 @@
       "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
       "dev": true
     },
+    "binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=",
+      "requires": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      }
+    },
     "binary-extensions": {
       "version": "1.12.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz",
@@ -1847,6 +1856,11 @@
       "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
       "dev": true
     },
+    "buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
+    },
     "builtin-status-codes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
@@ -2057,6 +2071,14 @@
       "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
     },
+    "chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
+      "requires": {
+        "traverse": ">=0.3.0 <0.4"
+      }
+    },
     "chalk": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@@ -3074,6 +3096,51 @@
         "mimic-response": "^1.0.0"
       }
     },
+    "decompress-zip": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.2.2.tgz",
+      "integrity": "sha512-v+Na3Ck86Px7s2ix+f77pMQC3GlkxHHN+YyvnkEW7+xX5F39pcDpIV/VFvGYk8MznTFcMoPjL3XNWEJLXWoSPw==",
+      "requires": {
+        "binary": "^0.3.0",
+        "graceful-fs": "^4.1.3",
+        "mkpath": "^0.1.0",
+        "nopt": "^3.0.1",
+        "q": "^1.1.2",
+        "readable-stream": "^1.1.8",
+        "touch": "0.0.3"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+        },
+        "nopt": {
+          "version": "3.0.6",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
+          "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
+          "requires": {
+            "abbrev": "1"
+          }
+        },
+        "readable-stream": {
+          "version": "1.1.14",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+          "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.1",
+            "isarray": "0.0.1",
+            "string_decoder": "~0.10.x"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
     "deep-extend": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -4062,43 +4129,6 @@
         }
       }
     },
-    "extract-zip": {
-      "version": "1.6.7",
-      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
-      "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
-      "requires": {
-        "concat-stream": "1.6.2",
-        "debug": "2.6.9",
-        "mkdirp": "0.5.1",
-        "yauzl": "2.4.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.6.9",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "fd-slicer": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
-          "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
-          "requires": {
-            "pend": "~1.2.0"
-          }
-        },
-        "yauzl": {
-          "version": "2.4.1",
-          "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
-          "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
-          "requires": {
-            "fd-slicer": "~1.0.1"
-          }
-        }
-      }
-    },
     "extsprintf": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -4410,8 +4440,7 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -4432,14 +4461,12 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -4454,20 +4481,17 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -4584,8 +4608,7 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "ini": {
           "version": "1.3.5",
@@ -4597,7 +4620,6 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -4612,7 +4634,6 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -4620,14 +4641,12 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "minipass": {
           "version": "2.2.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.1",
             "yallist": "^3.0.0"
@@ -4646,7 +4665,6 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -4727,8 +4745,7 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -4740,7 +4757,6 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -4826,8 +4842,7 @@
         "safe-buffer": {
           "version": "5.1.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -4863,7 +4878,6 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -4883,7 +4897,6 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -4927,14 +4940,12 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "yallist": {
           "version": "3.0.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         }
       }
     },
@@ -6512,6 +6523,11 @@
         }
       }
     },
+    "mkpath": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/mkpath/-/mkpath-0.1.0.tgz",
+      "integrity": "sha1-dVSm+Nhxg0zJe1RisSLEwSTW3pE="
+    },
     "move-concurrently": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -7300,11 +7316,6 @@
         "sha.js": "^2.4.8"
       }
     },
-    "pend": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
-      "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
-    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@@ -9436,8 +9447,7 @@
     "q": {
       "version": "1.5.1",
       "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
-      "dev": true
+      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
     },
     "qs": {
       "version": "6.5.2",
@@ -11010,6 +11020,24 @@
       "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
       "dev": true
     },
+    "touch": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/touch/-/touch-0.0.3.tgz",
+      "integrity": "sha1-Ua7z1ElXHU8oel2Hyci0kYGg2x0=",
+      "requires": {
+        "nopt": "~1.0.10"
+      },
+      "dependencies": {
+        "nopt": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+          "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
+          "requires": {
+            "abbrev": "1"
+          }
+        }
+      }
+    },
     "tough-cookie": {
       "version": "2.4.3",
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
@@ -11026,6 +11054,11 @@
         }
       }
     },
+    "traverse": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+      "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
+    },
     "trim-right": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "Liberama",
-  "version": "0.6.7",
+  "version": "0.6.8",
   "engines": {
     "node": ">=10.0.0"
   },
@@ -59,9 +59,9 @@
     "base-x": "^3.0.5",
     "chardet": "^0.7.0",
     "compression": "^1.7.3",
+    "decompress-zip": "^0.2.2",
     "element-ui": "^2.4.11",
     "express": "^4.16.4",
-    "extract-zip": "^1.6.7",
     "fg-loadcss": "^2.1.0",
     "fs-extra": "^7.0.1",
     "got": "^9.5.1",

+ 6 - 3
server/core/BookConverter/ConvertHtml.js

@@ -28,7 +28,7 @@ class ConvertHtml extends ConvertBase {
         } else {
             isText = opts.isText;
         }
-        const {cutTitle} = opts;
+        let {cutTitle} = opts;
 
         let titleInfo = {};
         let desc = {_n: 'description', 'title-info': titleInfo};
@@ -123,8 +123,11 @@ class ConvertHtml extends ConvertBase {
                 }
             }
 
-            if (tag == 'title')
+            if (tag == 'title' || tag == 'cut-title') {
                 inTitle = true;
+                if (tag == 'cut-title')
+                    cutTitle = true;
+            }
 
             if (tag == 'fb2-image') {
                 inImage = true;
@@ -153,7 +156,7 @@ class ConvertHtml extends ConvertBase {
                 }
             }
 
-            if (tag == 'title')
+            if (tag == 'title' || tag == 'cut-title')
                 inTitle = false;
 
             if (tag == 'fb2-image')

+ 22 - 10
server/core/FileDecompressor.js

@@ -2,9 +2,9 @@ const fs = require('fs-extra');
 const zlib = require('zlib');
 const crypto = require('crypto');
 const path = require('path');
-const extractZip = require('extract-zip');
 const unbzip2Stream = require('unbzip2-stream');
-const tar = require('tar-fs')
+const tar = require('tar-fs');
+const DecompressZip = require('decompress-zip');
 
 const utils = require('./utils');
 const FileDetector = require('./FileDetector');
@@ -114,16 +114,24 @@ class FileDecompressor {
     async unZip(filename, outputDir) {
         return new Promise((resolve, reject) => {
             const files = [];
-            extractZip(filename, {
-                dir: outputDir,
-                onEntry: (entry) => {
-                    files.push({path: entry.fileName, size: entry.uncompressedSize});
-                }
-            }, (err) => {
-                if (err)
-                    reject(err);
+            const unzipper = new DecompressZip(filename);
+
+            unzipper.on('error', function(err) {
+                reject(err);
+            });
+
+            unzipper.on('extract', function() {
                 resolve(files);
             });
+
+            unzipper.extract({
+                path: outputDir,
+                filter: function(file) {
+                    if (file.type == 'File')
+                        files.push({path: file.path, size: file.uncompressedSize});
+                    return true;
+                }
+            });
         });
     }
 
@@ -184,6 +192,10 @@ class FileDecompressor {
                 resolve([file]);
             });
 
+            stream.on('error', (err) => {
+                reject(err);
+            });
+
             inputStream.on('error', (err) => {
                 reject(err);
             });

+ 2 - 1
server/core/FileDetector/signatures.json

@@ -707,7 +707,8 @@
     "rules": [
       { "type": "or", "rules":
       [
-        { "type": "equal", "end": 19, "bytes": "3c3f786d6c2076657273696f6e3d22312e3022" }
+        { "type": "equal", "end": 19, "bytes": "3c3f786d6c2076657273696f6e3d22312e3022" },
+        { "type": "equal", "end": 22, "bytes": "efbbbf3c3f786d6c2076657273696f6e3d22312e3022" }
       ]
       }
     ]

+ 1 - 1
server/dev.js

@@ -20,7 +20,7 @@ function webpackDevMiddleware(app) {
 function logQueries(app) {
     app.use(function(req, res, next) {
         const start = Date.now();
-        log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body)}`);
+        log(`${req.method} ${req.originalUrl} ${JSON.stringify(req.body).substr(0, 2000)}`);
         //log(`${JSON.stringify(req.headers, null, 2)}`)
         res.once('finish', () => {
             log(`${Date.now() - start}ms`);