修复图片显示异常的bug;优化无封面书籍自动生成封面
parent
99a97c5242
commit
fbdef3c56f
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "org.bytedo.epub",
|
"name": "org.bytedo.epub",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"description": "E-pub Reader",
|
"description": "E-pub Reader",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
html{width:100%;height:100vh}body{display:flex;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app{position:relative;display:flex;width:100%;height:100%}.app .toc{width:260px;height:100%}.app .toc item{display:flex;align-items:center;height:36px;padding:0 12px;border-bottom:1px solid var(--color-plain-1);cursor:pointer}.app .toc item.lev-0{font-weight:bold}.app .toc item.lev-1{padding-left:24px;font-weight:bold}.app .toc item.lev-2{padding-left:36px}.app .toc item.lev-3{padding-left:48px}.app .toc item:hover{color:var(--color-blue-1)}.app .toc item.active{color:#fff;background:var(--color-blue-1)}.app .toc item:last-child{border-bottom:0}.app .chapter-box{flex:1;height:100%;border-left:1px solid var(--color-plain-2)}.app .chapter{display:flex;justify-content:center;padding:8px 24px}.app .chapter .detail{max-width:768px;line-height:1.5;font-size:14px}.app .chapter .detail a{text-decoration:underline;color:var(--color-teal-2)}.app .chapter .detail a:hover{color:var(--color-teal-1);text-decoration:none}.app .chapter .detail em,.app .chapter .detail del{color:var(--color-grey-2)}.app .chapter .detail strong,.app .chapter .detail strong em,.app .chapter .detail strong{color:var(--color-dark-3)}.app .chapter .detail a strong,.app .chapter .detail a em{color:inherit}.app .chapter .detail em,.app .chapter .detail strong,.app .chapter .detail del{padding:0 2px}.app .chapter .detail img{max-width:100%}.app .chapter .detail blockquote{margin:10px 0;padding:5px 10px;line-height:1.5;border-left:5px solid var(--color-teal-1);background:#f2faf7;color:var(--color-grey-2)}.app .chapter .detail blockquote p{margin:0}.app .chapter .detail>p{margin:12px 0}.app .chapter .detail ol{margin-left:1em;list-style:decimal outside none}.app .chapter .detail ul{margin-left:1em;list-style:disc outside none}.app .chapter .detail li{margin:0.5em 0}.app .chapter .detail li ol{margin-left:1em}.app .chapter .detail li ul{margin-left:1em;list-style-type:circle}.app .chapter .detail li ol ul,.app .chapter .detail li ul ul{list-style-type:square}.app .chapter .detail h1,.app .chapter .detail h2,.app .chapter .detail h3,.app .chapter .detail h4,.app .chapter .detail h5,.app .chapter .detail h6{margin:15px 0;line-height:2;font-weight:bold;font-size:16px}.app .chapter .detail h1 code.inline,.app .chapter .detail h2 code.inline,.app .chapter .detail h3 code.inline,.app .chapter .detail h4 code.inline,.app .chapter .detail h5 code.inline,.app .chapter .detail h6 code.inline{background:none}.app .chapter .detail h1 a,.app .chapter .detail h2 a,.app .chapter .detail h3 a,.app .chapter .detail h4 a,.app .chapter .detail h5 a,.app .chapter .detail h6 a{text-decoration:none;color:#333}.app .chapter .detail h3 a::before,.app .chapter .detail h4 a::before,.app .chapter .detail h5 a::before,.app .chapter .detail h6 a::before{content:'∮ ';color:var(--color-teal-1);font-weight:normal}.app .chapter .detail h1{margin:0 0 30px;font-size:24px;text-align:center}.app .chapter .detail h2{margin:20px 0;font-size:22px;border-bottom:1px solid var(--color-plain-2)}.app .chapter .detail h3{margin:20px 0 15px;font-size:20px}.app .chapter .detail h4{font-size:18px}.app .chapter .detail table{width:100%;border-spacing:0;border-collapse:collapse}.app .chapter .detail table tr{background-color:#fff}.app .chapter .detail table thead tr{background:var(--color-plain-1)}.app .chapter .detail table th,.app .chapter .detail table td{padding:6px 13px;border:1px solid var(--color-plain-2)}.app .chapter .detail table th{font-weight:bold}.app .chapter .detail table tr:nth-child(2n){background-color:#fcfdff}
|
html{width:100%;height:100vh}body{display:flex;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app{position:relative;display:flex;width:100%;height:100%}.app .toc{width:260px;height:100%}.app .toc item{display:flex;align-items:center;height:36px;padding:0 12px;border-bottom:1px solid var(--color-plain-1);cursor:pointer}.app .toc item.lev-0{font-weight:bold}.app .toc item.lev-1{padding-left:24px;font-weight:bold}.app .toc item.lev-2{padding-left:36px}.app .toc item.lev-3{padding-left:48px}.app .toc item:hover{color:var(--color-blue-1)}.app .toc item.active{color:#fff;background:var(--color-blue-1)}.app .toc item:last-child{border-bottom:0}.app .chapter-box{flex:1;height:100%;border-left:1px solid var(--color-plain-2)}.app .chapter{display:flex;justify-content:center;padding:8px 24px}.app .chapter .detail{max-width:768px;line-height:1.5;font-size:14px}.app .chapter .detail a{text-decoration:underline;color:var(--color-teal-2)}.app .chapter .detail a:hover{color:var(--color-teal-1);text-decoration:none}.app .chapter .detail em,.app .chapter .detail del{color:var(--color-grey-2)}.app .chapter .detail strong,.app .chapter .detail strong em,.app .chapter .detail strong{color:var(--color-dark-3)}.app .chapter .detail a strong,.app .chapter .detail a em{color:inherit}.app .chapter .detail em,.app .chapter .detail strong,.app .chapter .detail del{padding:0 2px}.app .chapter .detail img{max-width:100%}.app .chapter .detail blockquote{margin:10px 0;padding:5px 10px;line-height:1.5;border-left:5px solid var(--color-teal-1);background:#f2faf7;color:var(--color-grey-2)}.app .chapter .detail blockquote p{margin:0}.app .chapter .detail code{display:inline;margin:0 2px;padding:0 2px;color:var(--color-orange-3);background:var(--color-plain-1);border-radius:2px;font-family:Menlo, Monaco, Consolas, 'Courier New', monospace}.app .chapter .detail>p{margin:12px 0}.app .chapter .detail ol{margin-left:1em;list-style:decimal outside none}.app .chapter .detail ul{margin-left:1em;list-style:disc outside none}.app .chapter .detail li{margin:0.5em 0}.app .chapter .detail li ol{margin-left:1em}.app .chapter .detail li ul{margin-left:1em;list-style-type:circle}.app .chapter .detail li ol ul,.app .chapter .detail li ul ul{list-style-type:square}.app .chapter .detail h1,.app .chapter .detail h2,.app .chapter .detail h3,.app .chapter .detail h4,.app .chapter .detail h5,.app .chapter .detail h6{margin:15px 0;line-height:2;font-weight:bold;font-size:16px}.app .chapter .detail h1 code,.app .chapter .detail h2 code,.app .chapter .detail h3 code,.app .chapter .detail h4 code,.app .chapter .detail h5 code,.app .chapter .detail h6 code{background:none}.app .chapter .detail h1 a,.app .chapter .detail h2 a,.app .chapter .detail h3 a,.app .chapter .detail h4 a,.app .chapter .detail h5 a,.app .chapter .detail h6 a{text-decoration:none;color:#333}.app .chapter .detail h3 a::before,.app .chapter .detail h4 a::before,.app .chapter .detail h5 a::before,.app .chapter .detail h6 a::before{content:'∮ ';color:var(--color-teal-1);font-weight:normal}.app .chapter .detail h1{margin:0 0 30px;font-size:24px;text-align:center}.app .chapter .detail h2{margin:20px 0;font-size:22px;border-bottom:1px solid var(--color-plain-2)}.app .chapter .detail h3{margin:20px 0 15px;font-size:20px}.app .chapter .detail h4{font-size:18px}.app .chapter .detail table{width:100%;border-spacing:0;border-collapse:collapse}.app .chapter .detail table tr{background-color:#fff}.app .chapter .detail table thead tr{background:var(--color-plain-1)}.app .chapter .detail table th,.app .chapter .detail table td{padding:6px 13px;border:1px solid var(--color-plain-2)}.app .chapter .detail table th{font-weight:bold}.app .chapter .detail table tr:nth-child(2n){background-color:#fcfdff}
|
||||||
|
|
|
@ -128,6 +128,16 @@ body {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
display: inline;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0 2px;
|
||||||
|
color: var(--color-orange-3);
|
||||||
|
background: var(--color-plain-1);
|
||||||
|
border-radius: 2px;
|
||||||
|
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
> p {
|
> p {
|
||||||
margin: 12px 0;
|
margin: 12px 0;
|
||||||
// text-indent: 2em;
|
// text-indent: 2em;
|
||||||
|
@ -167,7 +177,7 @@ body {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
|
||||||
code.inline {
|
code {
|
||||||
background: none;
|
background: none;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
|
|
|
@ -36,7 +36,10 @@
|
||||||
@dblclick="read(it)"
|
@dblclick="read(it)"
|
||||||
@contextmenu="pickCtx2(it, $event)"
|
@contextmenu="pickCtx2(it, $event)"
|
||||||
>
|
>
|
||||||
<img :src="'book://cache/' + it.title + '/' + it.cover">
|
<img
|
||||||
|
:attr-alt="it.title"
|
||||||
|
:src="it.c ? it.c : 'book://cache/' + it.title + '/' + it.cover"
|
||||||
|
>
|
||||||
</book>
|
</book>
|
||||||
</list>
|
</list>
|
||||||
</wc-scroll>
|
</wc-scroll>
|
||||||
|
|
|
@ -121,6 +121,10 @@ Anot({
|
||||||
this.$db = db
|
this.$db = db
|
||||||
this.cates = cates
|
this.cates = cates
|
||||||
this.books = books || []
|
this.books = books || []
|
||||||
|
|
||||||
|
app.on('draw-cover', title => {
|
||||||
|
this.drawCover(title)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
view(item) {
|
view(item) {
|
||||||
|
@ -174,10 +178,61 @@ Anot({
|
||||||
this.$refs.ctx2.show()
|
this.$refs.ctx2.show()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
saveDB() {
|
saveDB() {
|
||||||
app.dispatch('save-books', Anot.deepCopy(this.$db))
|
app.dispatch('save-books', Anot.deepCopy(this.$db))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
drawCover(name) {
|
||||||
|
var canvas = document.createElement('canvas')
|
||||||
|
var ctx = canvas.getContext('2d')
|
||||||
|
var tmp = name.split('').map(s => (/[\w\s\(\)]/.test(s) ? 1 : 2))
|
||||||
|
|
||||||
|
canvas.width = 128
|
||||||
|
canvas.height = 160
|
||||||
|
|
||||||
|
ctx.fillStyle =
|
||||||
|
'#' +
|
||||||
|
Buffer.from(name)
|
||||||
|
.toString('hex')
|
||||||
|
.slice(-6)
|
||||||
|
|
||||||
|
ctx.fillRect(0, 0, 128, 160)
|
||||||
|
|
||||||
|
ctx.fillStyle = '#fff'
|
||||||
|
ctx.font = '14px menlo,Hiragino Sans GB'
|
||||||
|
ctx.textAlign = 'center'
|
||||||
|
|
||||||
|
let row = 0
|
||||||
|
let last = 0
|
||||||
|
tmp.reduce((sum, c, i) => {
|
||||||
|
sum += c
|
||||||
|
|
||||||
|
if (sum >= 14 && row === 0) {
|
||||||
|
ctx.fillText(name.slice(0, i + 1), 64, 60, 100)
|
||||||
|
last = i
|
||||||
|
row = 1
|
||||||
|
} else if (sum >= 28 && row === 1) {
|
||||||
|
ctx.fillText(name.slice(last, i + 1), 64, 60 + row * 26, 100)
|
||||||
|
row = 2
|
||||||
|
last = i
|
||||||
|
} else if (sum >= 42 && row === 2) {
|
||||||
|
ctx.fillText(name.slice(last, i + 1), 64, 60 + row * 26, 100)
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
if (last === 0) {
|
||||||
|
ctx.fillText(name, 64, 76, 100)
|
||||||
|
} else {
|
||||||
|
if (last < tmp.length) {
|
||||||
|
ctx.fillText(name.slice(last + 1), 64, 60 + row * 26, 100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let base64 = canvas.toDataURL('image/webp', 1).split(',')[1]
|
||||||
|
app.dispatch('save-cover', { base64, name })
|
||||||
|
},
|
||||||
|
|
||||||
deleteCate() {
|
deleteCate() {
|
||||||
//
|
//
|
||||||
this.$refs.ctx1.close()
|
this.$refs.ctx1.close()
|
||||||
|
|
|
@ -12,6 +12,8 @@ import { md5 } from '/lib/md5.js'
|
||||||
import fetch from '/lib/fetch/index.js'
|
import fetch from '/lib/fetch/index.js'
|
||||||
import app from '/lib/socket.js'
|
import app from '/lib/socket.js'
|
||||||
|
|
||||||
|
const { dirname, join } = require('path')
|
||||||
|
|
||||||
Anot({
|
Anot({
|
||||||
$id: 'app',
|
$id: 'app',
|
||||||
state: {
|
state: {
|
||||||
|
@ -89,7 +91,9 @@ Anot({
|
||||||
this.chapter = txt.replace(
|
this.chapter = txt.replace(
|
||||||
/<img[^>]*?src="(.*?)"[^>]*?\/?>/g,
|
/<img[^>]*?src="(.*?)"[^>]*?\/?>/g,
|
||||||
(m, s1) => {
|
(m, s1) => {
|
||||||
s1 = s1.replace('../', '')
|
// s1 = s1.replace('../', '')
|
||||||
|
s1 = join(dirname(file), s1)
|
||||||
|
console.log(file, s1)
|
||||||
return `<img src="book://cache/${this.book}/${s1}">`
|
return `<img src="book://cache/${this.book}/${s1}">`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,8 +44,6 @@ protocol.registerSchemesAsPrivileged([
|
||||||
|
|
||||||
/* ----------------------------------------------------- */
|
/* ----------------------------------------------------- */
|
||||||
|
|
||||||
// app.dock.hide()
|
|
||||||
|
|
||||||
// 初始化应用
|
// 初始化应用
|
||||||
app.once('ready', () => {
|
app.once('ready', () => {
|
||||||
// 注册协议
|
// 注册协议
|
||||||
|
|
|
@ -26,9 +26,10 @@ module.exports = function(app, createViewWindow) {
|
||||||
break
|
break
|
||||||
|
|
||||||
case 'read':
|
case 'read':
|
||||||
|
let params = JSON.parse(Buffer.from(conn.data, 'base64'))
|
||||||
if (app.__view__) {
|
if (app.__view__) {
|
||||||
// 打开同一个文档, 直接忽略
|
// 打开同一个文档, 直接忽略
|
||||||
if (app.__view__.__title__ === conn.data.title) {
|
if (app.__view__.__title__ === params.title) {
|
||||||
app.__view__.focus()
|
app.__view__.focus()
|
||||||
ev.returnValue = true
|
ev.returnValue = true
|
||||||
return
|
return
|
||||||
|
@ -36,7 +37,7 @@ module.exports = function(app, createViewWindow) {
|
||||||
app.__view__.destroy()
|
app.__view__.destroy()
|
||||||
}
|
}
|
||||||
app.__view__ = createViewWindow(conn.data)
|
app.__view__ = createViewWindow(conn.data)
|
||||||
app.__view__.__title__ = conn.data.title
|
app.__view__.__title__ = params.title
|
||||||
ev.returnValue = true
|
ev.returnValue = true
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -46,6 +47,13 @@ module.exports = function(app, createViewWindow) {
|
||||||
ev.returnValue = true
|
ev.returnValue = true
|
||||||
break
|
break
|
||||||
|
|
||||||
|
case 'save-cover':
|
||||||
|
let file = path.join(CACHE_DIR, conn.data.name, 'cover.webp')
|
||||||
|
let buf = Buffer.from(conn.data.base64, 'base64')
|
||||||
|
fs.echo(buf, file)
|
||||||
|
ev.returnValue = true
|
||||||
|
break
|
||||||
|
|
||||||
case 'parse-book':
|
case 'parse-book':
|
||||||
let { book, cate } = conn.data
|
let { book, cate } = conn.data
|
||||||
let eb = new Epub(book.path)
|
let eb = new Epub(book.path)
|
||||||
|
@ -53,7 +61,7 @@ module.exports = function(app, createViewWindow) {
|
||||||
|
|
||||||
eb.on('end', async _ => {
|
eb.on('end', async _ => {
|
||||||
let { title } = eb.metadata
|
let { title } = eb.metadata
|
||||||
let cover = 'cover'
|
let cover = ''
|
||||||
let dir = path.join(CACHE_DIR, title)
|
let dir = path.join(CACHE_DIR, title)
|
||||||
|
|
||||||
function saveImage(id, name) {
|
function saveImage(id, name) {
|
||||||
|
@ -78,6 +86,14 @@ module.exports = function(app, createViewWindow) {
|
||||||
.replace(/<pre><code>/g, '<wc-code>')
|
.replace(/<pre><code>/g, '<wc-code>')
|
||||||
.replace(/<\/code><\/pre>/g, '</wc-code>')
|
.replace(/<\/code><\/pre>/g, '</wc-code>')
|
||||||
|
|
||||||
|
htm = htm.replace(/<wc-code>([\w\W]*?)<\/wc-code>/g, function(
|
||||||
|
m,
|
||||||
|
s
|
||||||
|
) {
|
||||||
|
s = s.replace(/<\/?\w+>/g, '')
|
||||||
|
return `<wc-code>${s}</wc-code>`
|
||||||
|
})
|
||||||
|
|
||||||
fs.echo(htm, path.join(dir, name.replace('.xhtml', '.html')))
|
fs.echo(htm, path.join(dir, name.replace('.xhtml', '.html')))
|
||||||
} else {
|
} else {
|
||||||
console.log(id, name, txt)
|
console.log(id, name, txt)
|
||||||
|
@ -106,15 +122,23 @@ module.exports = function(app, createViewWindow) {
|
||||||
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)) {
|
if (it.href.includes('cover')) {
|
||||||
cover = it.href
|
cover = it.href
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!cover) {
|
||||||
|
cover = 'cover.webp'
|
||||||
|
app.__main__.webContents.send('app', {
|
||||||
|
type: 'draw-cover',
|
||||||
|
data: title
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let info = { title, cover }
|
let info = { title, cover }
|
||||||
|
|
||||||
if (cache[cate]) {
|
if (cache[cate]) {
|
||||||
if (!cache[cate].some(it => it.title === title)) {
|
if (!cache[cate].some(it => it.title === title)) {
|
||||||
cache[cate].push(info)
|
cache[cate].push(info)
|
||||||
|
|
Loading…
Reference in New Issue