增加多文件支持
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -174,6 +154,34 @@ body {
|
|||
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 {
|
||||
|
|
|
@ -11,13 +11,13 @@
|
|||
</head>
|
||||
<body class="noselect">
|
||||
|
||||
<div class="app" anot="app" :class="{loading: loading}">
|
||||
<div class="app" anot="app">
|
||||
|
||||
<wc-scroll class="category">
|
||||
<item
|
||||
class="item"
|
||||
:class="{active: curr === it.id}"
|
||||
:for="it in list">
|
||||
:class="{active: curr === it.name}"
|
||||
:for="it in cates">
|
||||
<strong :text="it.name"></strong>
|
||||
<span class="num" :text="it.num"></span>
|
||||
</item>
|
||||
|
@ -27,7 +27,10 @@
|
|||
|
||||
<div class="detail" :class="{blur: !curr.code}">
|
||||
|
||||
|
||||
<book :for="it in books">
|
||||
<img :src="'book://' + it.title + '/' + it.cover">
|
||||
{{it.title}}
|
||||
</book>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -35,6 +38,13 @@
|
|||
|
||||
<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>
|
||||
|
||||
|
||||
|
|
|
@ -29,14 +29,14 @@ Anot({
|
|||
$id: 'app',
|
||||
state: {
|
||||
input: '',
|
||||
curr: 1,
|
||||
list: [{ id: 1, name: '默认分类', num: 12 }],
|
||||
$dict: {},
|
||||
curr: '默认分类',
|
||||
cates: [{ name: '默认分类', num: 12 }],
|
||||
books: [],
|
||||
loading: false,
|
||||
isDragIn: false,
|
||||
preferences: {
|
||||
tab: 1,
|
||||
notify: Anot.ls('notify') === '1'
|
||||
load: {
|
||||
num: 0,
|
||||
curr: 0
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -65,11 +65,27 @@ Anot({
|
|||
.filter(it => it.type === 'application/epub+zip')
|
||||
.map(it => {
|
||||
let { name, path } = it
|
||||
name = name.replace(/\.epub$/, '')
|
||||
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: {}
|
||||
|
|
|
@ -44,7 +44,7 @@ protocol.registerSchemesAsPrivileged([
|
|||
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
app.dock.hide()
|
||||
// app.dock.hide()
|
||||
|
||||
// 初始化应用
|
||||
app.once('ready', () => {
|
||||
|
|
|
@ -23,10 +23,10 @@ PATH_SET = null
|
|||
|
||||
/* ********** 修复环境变量 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')
|
||||
|
||||
if (!fs.exists(INIT_FILE)) {
|
||||
fs.echo('[]', INIT_FILE)
|
||||
if (!fs.exists(DB_FILE)) {
|
||||
fs.echo('{}', DB_FILE)
|
||||
fs.mkdir(CACHE_DIR)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ const path = require('path')
|
|||
const Epub = require('epub')
|
||||
|
||||
const HOME = path.resolve(app.getPath('userData'))
|
||||
const DB_FILE = path.join(HOME, 'app.cache')
|
||||
const CACHE_DIR = path.join(HOME, 'book_cache')
|
||||
|
||||
function fetch(url) {
|
||||
|
@ -45,29 +46,36 @@ 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()
|
||||
})
|
||||
})
|
||||
}
|
||||
let { book, cate } = conn.data
|
||||
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) {
|
||||
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) {
|
||||
let it = eb.manifest[k]
|
||||
|
||||
|
@ -77,10 +85,7 @@ module.exports = function(app) {
|
|||
break
|
||||
|
||||
case 'application/x-dtbncx+xml':
|
||||
fs.echo(
|
||||
JSON.stringify(eb.toc),
|
||||
path.resolve(CACHE_DIR, it.href)
|
||||
)
|
||||
fs.echo(JSON.stringify(eb.toc), path.join(dir, 'toc.json'))
|
||||
break
|
||||
|
||||
case 'application/xhtml+xml':
|
||||
|
@ -90,11 +95,25 @@ module.exports = function(app) {
|
|||
default:
|
||||
if (it['media-type'].startsWith('image')) {
|
||||
saveImage(it.id, it.href)
|
||||
if (it.href.includes(cover)) {
|
||||
cover = it.href
|
||||
}
|
||||
}
|
||||
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()
|
||||
|
|
Loading…
Reference in New Issue