增加多文件支持
parent
9113d7472d
commit
e855b5cd26
|
@ -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:'🌘'}}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
||||||
|
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)
|
console.log(res)
|
||||||
|
if (res) {
|
||||||
|
this.books.push(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.timeEnd(1)
|
||||||
|
|
||||||
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
methods: {}
|
methods: {}
|
||||||
|
|
|
@ -44,7 +44,7 @@ protocol.registerSchemesAsPrivileged([
|
||||||
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
app.dock.hide()
|
// app.dock.hide()
|
||||||
|
|
||||||
// 初始化应用
|
// 初始化应用
|
||||||
app.once('ready', () => {
|
app.once('ready', () => {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,13 +46,18 @@ 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))
|
||||||
|
|
||||||
|
eb.on('end', async _ => {
|
||||||
|
let { title, cover } = eb.metadata
|
||||||
|
let dir = path.join(CACHE_DIR, title)
|
||||||
|
|
||||||
function saveImage(id, name) {
|
function saveImage(id, name) {
|
||||||
return new Promise(done => {
|
return new Promise(done => {
|
||||||
eb.getImage(id, (err, buf) => {
|
eb.getImage(id, (err, buf) => {
|
||||||
fs.echo(buf, path.resolve(CACHE_DIR, name))
|
fs.echo(buf, path.join(dir, name))
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -60,14 +66,16 @@ module.exports = function(app) {
|
||||||
function saveHtml(id, name) {
|
function saveHtml(id, name) {
|
||||||
return new Promise(done => {
|
return new Promise(done => {
|
||||||
eb.getChapter(id, (err, txt) => {
|
eb.getChapter(id, (err, txt) => {
|
||||||
txt = (txt + '').replace(/<([\w\-]+)[^>]*?>/g, '<$1>')
|
// txt = (txt + '').replace(
|
||||||
fs.echo(txt, path.resolve(CACHE_DIR, name))
|
// /<(?!img|image)([\w\-]+)[^>]*>/g,
|
||||||
|
// '<$1>'
|
||||||
|
// )
|
||||||
|
fs.echo(txt, path.join(dir, name.replace('.xhtml', '.html')))
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
eb.on('end', async _ => {
|
|
||||||
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()
|
||||||
|
|
Loading…
Reference in New Issue