diff --git a/package.json b/package.json index d5bc8f2..3974ec0 100644 --- a/package.json +++ b/package.json @@ -26,9 +26,9 @@ "version": "11.0.4", "mirror": "https://npm.taobao.org/mirrors/electron/" }, - "files": ["src/**/*", "node_modules/iofs/*"], + "files": ["src/**/*", "node_modules/iofs/*", "node_modules/epub/*"], "mac": { - "category": "public.app-category.developer-tools", + "category": "public.app-category.utilities", "target": "dmg", "icon": "icons/app.icns", "darkModeSupport": false @@ -39,6 +39,7 @@ "electron-builder": "^22.1.0" }, "dependencies": { + "epub": "^1.2.1", "iofs": "^1.3.2" } } diff --git a/src/js/app.js b/src/js/app.js index d571c02..e2e7370 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -60,6 +60,16 @@ Anot({ ev.preventDefault() // clearTimeout(this.timer) this.isDragIn = false + + let files = Array.from(ev.dataTransfer.files) + .filter(it => it.type === 'application/epub+zip') + .map(it => { + let { name, path } = it + return { name, path } + }) + let res = app.dispatch('parse-book', files) + + console.log(res) }) }, methods: {} diff --git a/src/main.js b/src/main.js index 8c4bab3..01fe230 100644 --- a/src/main.js +++ b/src/main.js @@ -8,6 +8,7 @@ const { app, BrowserWindow, protocol, ipcMain } = require('electron') const path = require('path') const fs = require('iofs') +require('./tools/init') const { createMainWindow, createFloatWindow } = require('./tools/window') const createMenu = require('./tools/menu') const Socket = require('./tools/socket') @@ -17,14 +18,18 @@ const MIME_TYPES = { '.html': 'text/html', '.htm': 'text/plain', '.css': 'text/css', - '.jpg': 'image/jpg', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', '.png': 'image/png', '.gif': 'image/gif', '.svg': 'image/svg+xml', - '.ico': 'image/ico' + '.ico': 'image/ico', + all: 'text/*' } const ROOT = __dirname +const HOME = path.resolve(app.getPath('userData')) +const CACHE_DIR = path.join(HOME, 'book_cache') var timer @@ -33,7 +38,8 @@ app.commandLine.appendSwitch('--lang', 'zh-CN') app.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required') protocol.registerSchemesAsPrivileged([ - { scheme: 'app', privileges: { secure: true, standard: true } } + { scheme: 'app', privileges: { secure: true, standard: true } }, + { scheme: 'book', privileges: { secure: true, standard: true } } ]) /* ----------------------------------------------------- */ @@ -43,16 +49,39 @@ app.dock.hide() // 初始化应用 app.once('ready', () => { // 注册协议 - protocol.registerBufferProtocol('app', (req, cb) => { - let file = req.url.replace(/^app:\/\/local\//, '') - let ext = path.extname(req.url) - let buff = fs.cat(path.resolve(ROOT, file)) - cb({ data: buff, mimeType: MIME_TYPES[ext] }) + protocol.registerStreamProtocol('app', function(req, cb) { + var file = decodeURIComponent(req.url.replace(/^app:\/\/local\//, '')) + var ext = path.extname(file) + + file = path.resolve(ROOT, file) + + cb({ + data: fs.origin.createReadStream(file), + mimeType: MIME_TYPES[ext], + headers: { + 'Cache-Control': 'max-age=144000000' + } + }) + }) + + protocol.registerStreamProtocol('book', function(req, cb) { + var file = decodeURIComponent(req.url.replace(/^book:[\/]+/, '/')) + var ext = path.extname(file) + + file = path.resolve(CACHE_DIR, file) + + cb({ + data: fs.origin.createReadStream(file), + mimeType: MIME_TYPES[ext] || MIME_TYPES.all, + headers: { + 'Cache-Control': 'max-age=144000000' + } + }) }) // 创建浏览器窗口 app.__main__ = createMainWindow(path.resolve(ROOT, './images/app.png')) - app.__float__ = createFloatWindow() + // app.__float__ = createFloatWindow() createMenu(app.__main__) Socket(app) @@ -63,10 +92,10 @@ app.once('ready', () => { app.exit() }) - // mac专属事件,点击dock栏图标,可激活窗口 - // app.on('activate', _ => { - // if (app.__main__) { - // app.__main__.restore() - // } - // }) + // mac专属事件, 点击dock栏图标, 可激活窗口 + app.on('activate', _ => { + if (app.__main__) { + app.__main__.restore() + } + }) }) diff --git a/src/tools/init.js b/src/tools/init.js new file mode 100644 index 0000000..e5dbcc4 --- /dev/null +++ b/src/tools/init.js @@ -0,0 +1,32 @@ +/** + * 初始化 + * @author yutent + * @date 2021/01/05 10:02:02 + */ + +const { app } = require('electron') +const path = require('path') +const fs = require('iofs') + +const HOME = path.resolve(app.getPath('userData')) + +/* ********** 修复环境变量 start *********** */ +let PATH_SET = new Set() +process.env.PATH.split(':').forEach(_ => { + PATH_SET.add(_) +}) +PATH_SET.add('/usr/local/bin') +PATH_SET.add('/usr/local/sbin') + +process.env.PATH = Array.from(PATH_SET).join(':') +PATH_SET = null + +/* ********** 修复环境变量 end *********** */ + +const INIT_FILE = path.join(HOME, 'app.cache') +const CACHE_DIR = path.join(HOME, 'book_cache') + +if (!fs.exists(INIT_FILE)) { + fs.echo('[]', INIT_FILE) + fs.mkdir(CACHE_DIR) +} diff --git a/src/tools/socket.js b/src/tools/socket.js index 6451086..5977164 100644 --- a/src/tools/socket.js +++ b/src/tools/socket.js @@ -4,7 +4,13 @@ * @date 2021/01/04 14:58:46 */ -const { ipcMain, net } = require('electron') +const { app, ipcMain, net } = require('electron') +const fs = require('iofs') +const path = require('path') +const Epub = require('epub') + +const HOME = path.resolve(app.getPath('userData')) +const CACHE_DIR = path.join(HOME, 'book_cache') function fetch(url) { return new Promise((y, n) => { @@ -39,6 +45,59 @@ module.exports = function(app) { break case 'parse-book': + let books = conn.data + let eb = new Epub(books[0].path) + + function saveImage(id, name) { + return new Promise(done => { + eb.getImage(id, (err, buf) => { + fs.echo(buf, path.resolve(CACHE_DIR, name)) + done() + }) + }) + } + + function saveHtml(id, name) { + return new Promise(done => { + eb.getChapter(id, (err, txt) => { + txt = (txt + '').replace(/<([\w\-]+)[^>]*?>/g, '<$1>') + fs.echo(txt, path.resolve(CACHE_DIR, name)) + done() + }) + }) + } + + eb.on('end', async _ => { + loop: for (let k in eb.manifest) { + let it = eb.manifest[k] + + switch (it['media-type']) { + case 'text/css': + continue loop + break + + case 'application/x-dtbncx+xml': + fs.echo( + JSON.stringify(eb.toc), + path.resolve(CACHE_DIR, it.href) + ) + break + + case 'application/xhtml+xml': + await saveHtml(it.id, it.href) + break + + default: + if (it['media-type'].startsWith('image')) { + saveImage(it.id, it.href) + } + break + } + } + ev.returnValue = [eb.manifest, eb.flow] + }) + + eb.parse() break } })