增加多文件支持

master
宇天 2021-01-06 17:58:14 +08:00
parent 9113d7472d
commit e855b5cd26
7 changed files with 116 additions and 63 deletions

View File

@ -1 +1 @@
html{font-size:12.8px;width:100%;height:100vh}body{overflow:hidden;display:flex;flex-direction:column;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app-drag{-webkit-app-region:drag;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.app-nodrag{-webkit-app-region:no-drag}.app{position:relative;display:flex;height:100%}.app .category{width:200px;height:100%;background:#fff}.app .category .item{display:flex;justify-content:space-between;align-items:center;height:54px;padding:8px;border-bottom:1px solid var(--color-plain-1);background:#fff;transition:background 0.2s ease-in-out, color 0.2s ease-in-out;cursor:pointer}.app .category .item strong{max-width:150px}.app .category .item .num{display:flex;justify-content:center;align-items:center;min-width:16px;height:16px;padding:2px;line-height:1;border-radius:50%;font-size:12px;background:var(--color-grey-1);color:#fff}.app .category .item:last-child{border-bottom:0}.app .category .item:hover{color:var(--color-blue-1);background:var(--color-plain-1)}.app .category .item.active{color:var(--color-plain-1);background:var(--color-blue-1)}.app .category .item.active .num{background:#fff;color:var(--color-blue-1)}.app .detail{position:relative;flex:1;height:100%;border-left:1px solid var(--color-plain-2);background:rgba(255,255,255,0.5)}.app .detail .title{display:flex;justify-content:space-between;align-items:center;width:100%;height:35px;padding:0 16px;font-size:16px;font-weight:bold}.app .detail .title span{display:inline-flex}.app .detail .title wc-button{margin:0 6px}.app .detail .card{width:96%;padding:12px 12px 16px;margin:12px 2% 24px;border:0;background:#fff;box-shadow:0 0 8px rgba(0,0,0,0.075)}.app .detail .card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#64b5f6}.app.loading::after{display:flex;justify-content:center;align-items:center;position:absolute;left:0;top:0;z-index:999;width:100%;height:100%;content:'🌑';background:rgba(255,255,255,0.01);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);color:var(--color-orange-1);font-size:50px;-webkit-animation:loading 1s infinite;animation:loading 1s infinite}.app .drag-mask{display:flex;align-items:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;background:linear-gradient(to right, transparent, transparent 200px, #fff3e3 200px)}.app .drag-mask::after{font-size:46px;text-indent:300px;content:'Drop epub file here...';color:var(--color-grey-1)}@-webkit-keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}@keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}} html{font-size:12.8px;width:100%;height:100vh}body{overflow:hidden;display:flex;flex-direction:column;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app-drag{-webkit-app-region:drag;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.app-nodrag{-webkit-app-region:no-drag}.app{position:relative;display:flex;height:100%}.app .category{width:200px;height:100%;background:#fff}.app .category .item{display:flex;justify-content:space-between;align-items:center;height:54px;padding:8px;border-bottom:1px solid var(--color-plain-1);background:#fff;transition:background 0.2s ease-in-out, color 0.2s ease-in-out;cursor:pointer}.app .category .item strong{max-width:150px}.app .category .item .num{display:flex;justify-content:center;align-items:center;min-width:16px;height:16px;padding:2px;line-height:1;border-radius:50%;font-size:12px;background:var(--color-grey-1);color:#fff}.app .category .item:last-child{border-bottom:0}.app .category .item:hover{color:var(--color-blue-1);background:var(--color-plain-1)}.app .category .item.active{color:var(--color-plain-1);background:var(--color-blue-1)}.app .category .item.active .num{background:#fff;color:var(--color-blue-1)}.app .detail{position:relative;flex:1;height:100%;border-left:1px solid var(--color-plain-2);background:rgba(255,255,255,0.5)}.app .detail .title{display:flex;justify-content:space-between;align-items:center;width:100%;height:35px;padding:0 16px;font-size:16px;font-weight:bold}.app .detail .title span{display:inline-flex}.app .detail .title wc-button{margin:0 6px}.app .detail .card{width:96%;padding:12px 12px 16px;margin:12px 2% 24px;border:0;background:#fff;box-shadow:0 0 8px rgba(0,0,0,0.075)}.app .detail .card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#64b5f6}.app .drag-mask{display:flex;align-items:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;background:linear-gradient(to right, transparent, transparent 200px, #fff3e3 200px)}.app .drag-mask::after{font-size:46px;text-indent:300px;content:'Drop epub file here...';color:var(--color-grey-1)}.app .book-loading{display:flex;align-items:center;justify-content:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;font-size:20px;background:rgba(255,255,255,0.01);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.app .book-loading .loading{display:flex;flex-direction:column;align-items:center;justify-content:center}.app .book-loading .loading::before{content:'🌑';font-size:36px;-webkit-animation:loading 1s infinite;animation:loading 1s infinite}@-webkit-keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}@keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}

View File

@ -131,26 +131,6 @@ body {
} }
} }
&.loading {
&::after {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
left: 0;
top: 0;
z-index: 999;
width: 100%;
height: 100%;
content: '🌑';
background: rgba(255, 255, 255, 0.01);
backdrop-filter: blur(2px);
color: var(--color-orange-1);
font-size: 50px;
animation: loading 1s infinite;
}
}
.drag-mask { .drag-mask {
display: flex; display: flex;
align-items: center; align-items: center;
@ -174,6 +154,34 @@ body {
color: var(--color-grey-1); color: var(--color-grey-1);
} }
} }
.book-loading {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
left: 0;
top: 0;
z-index: 9999;
width: 100%;
height: 100%;
font-size: 20px;
background: rgba(255, 255, 255, 0.01);
backdrop-filter: blur(2px);
.loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
&::before {
content: '🌑';
font-size: 36px;
animation: loading 1s infinite;
}
}
}
} }
@keyframes loading { @keyframes loading {

View File

@ -11,13 +11,13 @@
</head> </head>
<body class="noselect"> <body class="noselect">
<div class="app" anot="app" :class="{loading: loading}"> <div class="app" anot="app">
<wc-scroll class="category"> <wc-scroll class="category">
<item <item
class="item" class="item"
:class="{active: curr === it.id}" :class="{active: curr === it.name}"
:for="it in list"> :for="it in cates">
<strong :text="it.name"></strong> <strong :text="it.name"></strong>
<span class="num" :text="it.num"></span> <span class="num" :text="it.num"></span>
</item> </item>
@ -27,7 +27,10 @@
<div class="detail" :class="{blur: !curr.code}"> <div class="detail" :class="{blur: !curr.code}">
<book :for="it in books">
<img :src="'book://' + it.title + '/' + it.cover">
{{it.title}}
</book>
</div> </div>
@ -35,6 +38,13 @@
<div class="drag-mask" ref="mask" :visible="isDragIn"></div> <div class="drag-mask" ref="mask" :visible="isDragIn"></div>
<div class="book-loading" ref="books" :visible="loading">
<div class="loading">
<span>共 {{load.num}} 本书</span>
<span>当前正在解析第 {{load.curr}} 本</span>
</div>
</div>
</div> </div>

View File

@ -29,14 +29,14 @@ Anot({
$id: 'app', $id: 'app',
state: { state: {
input: '', input: '',
curr: 1, curr: '默认分类',
list: [{ id: 1, name: '默认分类', num: 12 }], cates: [{ name: '默认分类', num: 12 }],
$dict: {}, books: [],
loading: false, loading: false,
isDragIn: false, isDragIn: false,
preferences: { load: {
tab: 1, num: 0,
notify: Anot.ls('notify') === '1' curr: 0
} }
}, },
@ -65,11 +65,27 @@ Anot({
.filter(it => it.type === 'application/epub+zip') .filter(it => it.type === 'application/epub+zip')
.map(it => { .map(it => {
let { name, path } = it let { name, path } = it
name = name.replace(/\.epub$/, '')
return { name, path } return { name, path }
}) })
let res = app.dispatch('parse-book', files)
console.log(res) this.load.num = files.length
this.load.curr = 0
this.loading = true
console.time(1)
while (this.load.curr < this.load.num) {
this.load.curr++
let book = files.pop()
let res = app.dispatch('parse-book', { book, cate: this.burr })
console.log(res)
if (res) {
this.books.push(res)
}
}
console.timeEnd(1)
this.loading = false
}) })
}, },
methods: {} methods: {}

View File

@ -44,7 +44,7 @@ protocol.registerSchemesAsPrivileged([
/* ----------------------------------------------------- */ /* ----------------------------------------------------- */
app.dock.hide() // app.dock.hide()
// 初始化应用 // 初始化应用
app.once('ready', () => { app.once('ready', () => {

View File

@ -23,10 +23,10 @@ PATH_SET = null
/* ********** 修复环境变量 end *********** */ /* ********** 修复环境变量 end *********** */
const INIT_FILE = path.join(HOME, 'app.cache') const DB_FILE = path.join(HOME, 'app.cache')
const CACHE_DIR = path.join(HOME, 'book_cache') const CACHE_DIR = path.join(HOME, 'book_cache')
if (!fs.exists(INIT_FILE)) { if (!fs.exists(DB_FILE)) {
fs.echo('[]', INIT_FILE) fs.echo('{}', DB_FILE)
fs.mkdir(CACHE_DIR) fs.mkdir(CACHE_DIR)
} }

View File

@ -10,6 +10,7 @@ const path = require('path')
const Epub = require('epub') const Epub = require('epub')
const HOME = path.resolve(app.getPath('userData')) const HOME = path.resolve(app.getPath('userData'))
const DB_FILE = path.join(HOME, 'app.cache')
const CACHE_DIR = path.join(HOME, 'book_cache') const CACHE_DIR = path.join(HOME, 'book_cache')
function fetch(url) { function fetch(url) {
@ -45,29 +46,36 @@ module.exports = function(app) {
break break
case 'parse-book': case 'parse-book':
let books = conn.data let { book, cate } = conn.data
let eb = new Epub(books[0].path) let eb = new Epub(book.path)
let cache = JSON.parse(fs.cat(DB_FILE))
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 _ => { eb.on('end', async _ => {
let { title, cover } = eb.metadata
let dir = path.join(CACHE_DIR, title)
function saveImage(id, name) {
return new Promise(done => {
eb.getImage(id, (err, buf) => {
fs.echo(buf, path.join(dir, name))
done()
})
})
}
function saveHtml(id, name) {
return new Promise(done => {
eb.getChapter(id, (err, txt) => {
// txt = (txt + '').replace(
// /<(?!img|image)([\w\-]+)[^>]*>/g,
// '<$1>'
// )
fs.echo(txt, path.join(dir, name.replace('.xhtml', '.html')))
done()
})
})
}
loop: for (let k in eb.manifest) { loop: for (let k in eb.manifest) {
let it = eb.manifest[k] let it = eb.manifest[k]
@ -77,10 +85,7 @@ module.exports = function(app) {
break break
case 'application/x-dtbncx+xml': case 'application/x-dtbncx+xml':
fs.echo( fs.echo(JSON.stringify(eb.toc), path.join(dir, 'toc.json'))
JSON.stringify(eb.toc),
path.resolve(CACHE_DIR, it.href)
)
break break
case 'application/xhtml+xml': case 'application/xhtml+xml':
@ -90,11 +95,25 @@ module.exports = function(app) {
default: default:
if (it['media-type'].startsWith('image')) { if (it['media-type'].startsWith('image')) {
saveImage(it.id, it.href) saveImage(it.id, it.href)
if (it.href.includes(cover)) {
cover = it.href
}
} }
break break
} }
} }
ev.returnValue = [eb.manifest, eb.flow]
let info = { title, cover }
if (cache[cate]) {
if (!cache[cate].some(it => it.title === title)) {
cache[cate].push(info)
} else {
info = null
}
} else {
cache[cate] = [info]
}
ev.returnValue = info
}) })
eb.parse() eb.parse()