reorganize file structure, add sending urls
This commit is contained in:
251
index.js
251
index.js
@@ -5,6 +5,8 @@ const Router = require('@koa/router')
|
||||
const multer = require('@koa/multer')
|
||||
const logger = require('koa-logger')
|
||||
const sendfile = require('koa-sendfile')
|
||||
const serve = require('koa-static')
|
||||
const mount = require('koa-mount')
|
||||
const { mkdirp } = require('mkdirp')
|
||||
const fs = require('fs')
|
||||
const { spawn } = require('child_process')
|
||||
@@ -76,7 +78,7 @@ function expireKey (key) {
|
||||
|
||||
function flash (ctx, data) {
|
||||
console.log(data)
|
||||
ctx.cookies.set('flash', encodeURIComponent(JSON.stringify(data)), {overwrite: true, httpOnly: false})
|
||||
ctx.cookies.set('flash', encodeURIComponent(JSON.stringify(data)), {overwrite: true, httpOnly: false, sameSite: 'strict', maxAge: 10 * 1000})
|
||||
}
|
||||
|
||||
const app = new Koa()
|
||||
@@ -142,7 +144,8 @@ router.post('/generate', async ctx => {
|
||||
const info = {
|
||||
created: new Date(),
|
||||
agent: agent,
|
||||
file: null
|
||||
file: null,
|
||||
urls: []
|
||||
}
|
||||
ctx.keys.set(key, info)
|
||||
expireKey(key)
|
||||
@@ -200,123 +203,153 @@ router.post('/upload', upload.single('file'), async ctx => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!ctx.request.file || ctx.request.file.size === 0) {
|
||||
flash(ctx, {
|
||||
message: 'Invalid file submitted',
|
||||
success: false,
|
||||
key: key
|
||||
})
|
||||
ctx.redirect('back', '/')
|
||||
if (ctx.request.file) {
|
||||
const info = ctx.keys.get(key)
|
||||
expireKey(key)
|
||||
|
||||
let url = null
|
||||
if (ctx.request.body.url) {
|
||||
url = ctx.request.body.url.trim()
|
||||
if (url.length > 0 && !info.urls.includes(url)) {
|
||||
info.urls.push(url)
|
||||
}
|
||||
}
|
||||
|
||||
let conversion = null
|
||||
let filename = ""
|
||||
|
||||
if (ctx.request.file) {
|
||||
if (ctx.request.file.size === 0) {
|
||||
flash(ctx, {
|
||||
message: 'Invalid file submitted',
|
||||
success: false,
|
||||
key: key
|
||||
})
|
||||
ctx.redirect('back', '/')
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const mimetype = ctx.request.file.mimetype
|
||||
|
||||
const type = await FileType.fromFile(ctx.request.file.path)
|
||||
|
||||
if ((!type || !allowedTypes.includes(type.mime)) && !allowedTypes.includes(mimetype)) {
|
||||
flash(ctx, {
|
||||
message: 'Uploaded file is of an invalid type: ' + ctx.request.file.originalname + ' (' + (type? type.mime : 'unknown mimetype') + ')',
|
||||
success: false,
|
||||
key: key
|
||||
})
|
||||
ctx.redirect('back', '/')
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
let data = null
|
||||
filename = ctx.request.file.originalname
|
||||
|
||||
if (mimetype === TYPE_EPUB && info.agent.includes('Kindle')) {
|
||||
// convert to .mobi
|
||||
conversion = 'kindlegen'
|
||||
const outname = ctx.request.file.path.replace(/\.epub$/i, '.mobi')
|
||||
filename = filename.replace(/\.kepub\.epub$/i, '.epub').replace(/\.epub$/i, '.mobi')
|
||||
|
||||
data = await new Promise((resolve, reject) => {
|
||||
const kindlegen = spawn('kindlegen', [basename(ctx.request.file.path), '-dont_append_source', '-c1', '-o', basename(outname)], {
|
||||
stdio: 'inherit',
|
||||
cwd: dirname(ctx.request.file.path)
|
||||
})
|
||||
kindlegen.once('close', (code) => {
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
fs.unlink(ctx.request.file.path.replace(/\.epub$/i, '.mobi8'), (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path.replace(/\.epub$/i, '.mobi8'))
|
||||
})
|
||||
if (code !== 0) {
|
||||
console.warn('kindlegen error code ' + code)
|
||||
}
|
||||
|
||||
resolve(outname)
|
||||
})
|
||||
})
|
||||
|
||||
} else if (mimetype === TYPE_EPUB && info.agent.includes('Kobo') && ctx.request.body.kepubify) {
|
||||
// convert to Kobo EPUB
|
||||
conversion = 'kepubify'
|
||||
const outname = ctx.request.file.path.replace(/\.epub$/i, '.kepub.epub')
|
||||
filename = filename.replace(/\.kepub\.epub$/i, '.epub').replace(/\.epub$/i, '.kepub.epub')
|
||||
|
||||
data = await new Promise((resolve, reject) => {
|
||||
const kepubify = spawn('kepubify', ['-v', '-u', '-o', basename(outname), basename(ctx.request.file.path)], {
|
||||
stdio: 'inherit',
|
||||
cwd: dirname(ctx.request.file.path)
|
||||
})
|
||||
kepubify.once('close', (code) => {
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
if (code !== 0) {
|
||||
reject('kepubify error code ' + code)
|
||||
return
|
||||
}
|
||||
|
||||
resolve(outname)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// No conversion
|
||||
data = ctx.request.file.path
|
||||
}
|
||||
|
||||
expireKey(key)
|
||||
if (info.file && info.file.path) {
|
||||
await new Promise((resolve, reject) => fs.unlink(info.file.path, (err) => {
|
||||
if (err) return reject(err)
|
||||
else console.log('Removed previously uploaded file', info.file.path)
|
||||
resolve()
|
||||
}))
|
||||
}
|
||||
info.file = {
|
||||
name: filename,
|
||||
path: data,
|
||||
// size: ctx.request.file.size,
|
||||
uploaded: new Date()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const mimetype = ctx.request.file.mimetype
|
||||
let messages = []
|
||||
if (ctx.request.file) {
|
||||
messages.push('Upload successful! ' + (conversion ? ' Ebook was converted with ' + conversion + ' and sent' : ' Sent')+' to '+(info.agent.includes('Kobo') ? 'a Kobo device.' : (info.agent.includes('Kindle') ? 'a Kindle device.' : 'a device.')))
|
||||
messages.push('Filename: ' + filename)
|
||||
}
|
||||
if (url) {
|
||||
messages.push("Added url: " + url)
|
||||
}
|
||||
|
||||
const type = await FileType.fromFile(ctx.request.file.path)
|
||||
|
||||
if ((!type || !allowedTypes.includes(type.mime)) && !allowedTypes.includes(mimetype)) {
|
||||
if (messages.length === 0) {
|
||||
flash(ctx, {
|
||||
message: 'Uploaded file is of an invalid type: ' + ctx.request.file.originalname + ' (' + (type? type.mime : 'unknown mimetype') + ')',
|
||||
message: 'No file or url selected',
|
||||
success: false,
|
||||
key: key
|
||||
})
|
||||
ctx.redirect('back', '/')
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const info = ctx.keys.get(key)
|
||||
expireKey(key)
|
||||
|
||||
let data = null
|
||||
let filename = ctx.request.file.originalname
|
||||
let conversion = null
|
||||
|
||||
if (mimetype === TYPE_EPUB && info.agent.includes('Kindle')) {
|
||||
// convert to .mobi
|
||||
conversion = 'kindlegen'
|
||||
const outname = ctx.request.file.path.replace(/\.epub$/i, '.mobi')
|
||||
filename = filename.replace(/\.kepub\.epub$/i, '.epub').replace(/\.epub$/i, '.mobi')
|
||||
|
||||
data = await new Promise((resolve, reject) => {
|
||||
const kindlegen = spawn('kindlegen', [basename(ctx.request.file.path), '-dont_append_source', '-c1', '-o', basename(outname)], {
|
||||
stdio: 'inherit',
|
||||
cwd: dirname(ctx.request.file.path)
|
||||
})
|
||||
kindlegen.once('close', (code) => {
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
fs.unlink(ctx.request.file.path.replace(/\.epub$/i, '.mobi8'), (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path.replace(/\.epub$/i, '.mobi8'))
|
||||
})
|
||||
if (code !== 0) {
|
||||
console.warn('kindlegen error code ' + code)
|
||||
}
|
||||
|
||||
resolve(outname)
|
||||
})
|
||||
})
|
||||
|
||||
} else if (mimetype === TYPE_EPUB && info.agent.includes('Kobo') && ctx.request.body.kepubify) {
|
||||
// convert to Kobo EPUB
|
||||
conversion = 'kepubify'
|
||||
const outname = ctx.request.file.path.replace(/\.epub$/i, '.kepub.epub')
|
||||
filename = filename.replace(/\.kepub\.epub$/i, '.epub').replace(/\.epub$/i, '.kepub.epub')
|
||||
|
||||
data = await new Promise((resolve, reject) => {
|
||||
const kepubify = spawn('kepubify', ['-v', '-u', '-o', basename(outname), basename(ctx.request.file.path)], {
|
||||
stdio: 'inherit',
|
||||
cwd: dirname(ctx.request.file.path)
|
||||
})
|
||||
kepubify.once('close', (code) => {
|
||||
fs.unlink(ctx.request.file.path, (err) => {
|
||||
if (err) console.error(err)
|
||||
else console.log('Removed file', ctx.request.file.path)
|
||||
})
|
||||
if (code !== 0) {
|
||||
reject('kepubify error code ' + code)
|
||||
return
|
||||
}
|
||||
|
||||
resolve(outname)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// No conversion
|
||||
data = ctx.request.file.path
|
||||
}
|
||||
|
||||
expireKey(key)
|
||||
if (info.file && info.file.path) {
|
||||
await new Promise((resolve, reject) => fs.unlink(info.file.path, (err) => {
|
||||
if (err) return reject(err)
|
||||
else console.log('Removed previously uploaded file', info.file.path)
|
||||
resolve()
|
||||
}))
|
||||
}
|
||||
info.file = {
|
||||
name: filename,
|
||||
path: data,
|
||||
// size: ctx.request.file.size,
|
||||
uploaded: new Date()
|
||||
}
|
||||
|
||||
flash(ctx, {
|
||||
message: 'Upload successful!<br/>'+(conversion ? ' Ebook was converted with ' + conversion + ' and sent' : ' Sent')+' to '+(info.agent.includes('Kobo') ? 'a Kobo device.' : (info.agent.includes('Kindle') ? 'a Kindle device.' : 'a device.'))+'<br/>Filename: ' + filename,
|
||||
message: messages.join("<br/>"),
|
||||
success: true,
|
||||
key: key
|
||||
key: key,
|
||||
url: url
|
||||
})
|
||||
ctx.redirect('back', '/')
|
||||
})
|
||||
@@ -349,28 +382,30 @@ router.get('/status/:key', async ctx => {
|
||||
file: info.file ? {
|
||||
name: info.file.name,
|
||||
// size: info.file.size
|
||||
} : null
|
||||
} : null,
|
||||
urls: info.urls
|
||||
}
|
||||
})
|
||||
|
||||
router.get('/style.css', async ctx => {
|
||||
await sendfile(ctx, 'style.css')
|
||||
})
|
||||
|
||||
router.get('/receive', async ctx => {
|
||||
await sendfile(ctx, 'download.html')
|
||||
await sendfile(ctx, 'static/download.html')
|
||||
})
|
||||
|
||||
router.get('/', async ctx => {
|
||||
const agent = ctx.get('user-agent')
|
||||
console.log(ctx.ip, agent)
|
||||
await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle')? 'download.html' : 'upload.html')
|
||||
await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle')? 'static/download.html' : 'static/upload.html')
|
||||
})
|
||||
|
||||
|
||||
app.use(router.routes())
|
||||
app.use(router.allowedMethods())
|
||||
|
||||
app.use(serve("static"))
|
||||
|
||||
app.use(mount("/node_modules/crypto-js", serve("node_modules/crypto-js")))
|
||||
|
||||
|
||||
fs.rm('uploads', {recursive: true}, (err) => {
|
||||
if (err) throw err
|
||||
mkdirp('uploads').then (() => {
|
||||
|
||||
138
package-lock.json
generated
138
package-lock.json
generated
@@ -14,7 +14,9 @@
|
||||
"file-type": "^16.5.4",
|
||||
"koa": "^2.14.2",
|
||||
"koa-logger": "^3.2.1",
|
||||
"koa-mount": "^4.0.0",
|
||||
"koa-sendfile": "^3.0.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"mkdirp": "^3.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"transliteration": "^2.3.5"
|
||||
@@ -1054,6 +1056,62 @@
|
||||
"node": ">= 7.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-mount": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-mount/-/koa-mount-4.0.0.tgz",
|
||||
"integrity": "sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==",
|
||||
"dependencies": {
|
||||
"debug": "^4.0.1",
|
||||
"koa-compose": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 7.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-send": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.1.tgz",
|
||||
"integrity": "sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"http-errors": "^1.7.3",
|
||||
"resolve-path": "^1.4.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-send/node_modules/depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-send/node_modules/http-errors": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
|
||||
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
|
||||
"dependencies": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-send/node_modules/statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-sendfile": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-sendfile/-/koa-sendfile-3.0.0.tgz",
|
||||
@@ -1066,6 +1124,26 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-static": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz",
|
||||
"integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==",
|
||||
"dependencies": {
|
||||
"debug": "^3.1.0",
|
||||
"koa-send": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 7.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/koa-static/node_modules/debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/koa/node_modules/http-errors": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
|
||||
@@ -1245,6 +1323,14 @@
|
||||
"resolved": "https://registry.npmjs.org/passthrough-counter/-/passthrough-counter-1.0.0.tgz",
|
||||
"integrity": "sha512-Wy8PXTLqPAN0oEgBrlnsXPMww3SYJ44tQ8aVrGAI4h4JZYCS0oYqsPqtPR8OhJpv6qFbpbB7XAn0liKV7EXubA=="
|
||||
},
|
||||
"node_modules/path-is-absolute": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
|
||||
@@ -1327,6 +1413,58 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-path": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz",
|
||||
"integrity": "sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==",
|
||||
"dependencies": {
|
||||
"http-errors": "~1.6.2",
|
||||
"path-is-absolute": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-path/node_modules/depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-path/node_modules/http-errors": {
|
||||
"version": "1.6.3",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
|
||||
"integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
|
||||
"dependencies": {
|
||||
"depd": "~1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.0",
|
||||
"statuses": ">= 1.4.0 < 2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-path/node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
|
||||
},
|
||||
"node_modules/resolve-path/node_modules/setprototypeof": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
|
||||
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
|
||||
},
|
||||
"node_modules/resolve-path/node_modules/statuses": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||
"integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"file-type": "^16.5.4",
|
||||
"koa": "^2.14.2",
|
||||
"koa-logger": "^3.2.1",
|
||||
"koa-mount": "^4.0.0",
|
||||
"koa-sendfile": "^3.0.0",
|
||||
"koa-static": "^5.0.0",
|
||||
"mkdirp": "^3.0.1",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"transliteration": "^2.3.5"
|
||||
|
||||
41
static/common.js
Normal file
41
static/common.js
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict'
|
||||
|
||||
function log(str) {
|
||||
var node = document.createElement("div")
|
||||
node.textContent = str
|
||||
logs.appendChild(node)
|
||||
}
|
||||
window.addEventListener("error", function (event) {
|
||||
log(event.filename + ":" + event.lineno + " " + event.message)
|
||||
}, false)
|
||||
|
||||
function xhr(method, url, cb) {
|
||||
var x = new XMLHttpRequest()
|
||||
x.onload = function () {
|
||||
cb(x)
|
||||
}
|
||||
x.onerror = function () {
|
||||
cb(x)
|
||||
}
|
||||
x.open(method, url, true)
|
||||
x.send(null)
|
||||
}
|
||||
|
||||
var isIOS = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
|
||||
|
||||
function getCookies() {
|
||||
var cookieRegex = /([\w\.]+)\s*=\s*(?:"((?:\\"|[^"])*)"|(.*?))\s*(?:[;,]|$)/g
|
||||
var cookies = {}
|
||||
var match
|
||||
while( (match = cookieRegex.exec(document.cookie)) !== null ) {
|
||||
var value = match[2] || match[3]
|
||||
cookies[match[1]] = decodeURIComponent(value)
|
||||
try {
|
||||
cookies[match[1]] = JSON.parse(cookies[match[1]])
|
||||
} catch (err) {}
|
||||
}
|
||||
return cookies
|
||||
}
|
||||
// function deleteCookie(name) {
|
||||
// document.cookie = name + "= ; expires = Thu, 01 Jan 1970 00:00:00 GMT"
|
||||
// }
|
||||
@@ -4,7 +4,8 @@
|
||||
<title>Send to Kobo/Kindle</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css?o"/>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?s"/>
|
||||
<script src="./common.js?a"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -21,13 +22,15 @@
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
<div class="center" id="downloads">
|
||||
<div style="font-size: 1.3em;"><em>Downloads</em></div>
|
||||
<br/>
|
||||
<div><a id="downloadlink"></a></div>
|
||||
<div class="center">
|
||||
<div id="downloads">
|
||||
<br/>
|
||||
<div style="font-size: 1.3em;"><em>Downloads</em></div>
|
||||
<a id="downloadlink" class="downloadlink"></a>
|
||||
</div>
|
||||
<div id="urls"></div>
|
||||
<br/>
|
||||
</div>
|
||||
<hr/>
|
||||
@@ -39,35 +42,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logs"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var keyOutput = document.getElementById('keyoutput')
|
||||
var keyGenBtn = document.getElementById('keygen')
|
||||
var downloads = document.getElementById('downloads')
|
||||
var downloadlink = document.getElementById('downloadlink')
|
||||
var urlsnode = document.getElementById('urls')
|
||||
var siteurl = document.getElementById('siteurl')
|
||||
var key = null
|
||||
var pollTimer = null
|
||||
|
||||
function xhr(method, url, cb) {
|
||||
var x = new XMLHttpRequest()
|
||||
x.onload = function () {
|
||||
cb(x)
|
||||
}
|
||||
x.onerror = function () {
|
||||
cb(x)
|
||||
}
|
||||
x.open(method, url, true)
|
||||
x.send(null)
|
||||
}
|
||||
|
||||
function pollFile () {
|
||||
if (!key) {
|
||||
keyOutput.textContent = '––––'
|
||||
downloads.style.display = 'none'
|
||||
return
|
||||
}
|
||||
xhr('GET', '/status/' + key, function (x) {
|
||||
xhr('GET', './status/' + key, function (x) {
|
||||
var data
|
||||
try {
|
||||
data = JSON.parse(x.responseText)
|
||||
@@ -83,12 +77,29 @@ function pollFile () {
|
||||
keyOutput.textContent = '––––'
|
||||
downloads.style.display = 'none'
|
||||
}
|
||||
var urls = data.urls && data.urls.length > 0 ? data.urls : null
|
||||
if (data.file || urls) {
|
||||
} else {
|
||||
}
|
||||
if (data.file) {
|
||||
downloadlink.textContent = data.file.name
|
||||
downloads.style.display = 'block'
|
||||
downloadlink.textContent = data.file.name
|
||||
} else {
|
||||
downloads.style.display = 'none'
|
||||
}
|
||||
if (urls) {
|
||||
urlsnode.innerHTML = '<br/><div style="font-size: 1.3em;"><em>Urls</em></div>'
|
||||
urls.forEach(function (url) {
|
||||
var urllink = document.createElement("a")
|
||||
urllink.href = url
|
||||
urllink.target = '_blank'
|
||||
urllink.textContent = url
|
||||
urllink.className = "downloadlink"
|
||||
var div = document.createElement('div')
|
||||
div.appendChild(urllink)
|
||||
urlsnode.appendChild(div)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,11 +107,11 @@ function generateKey () {
|
||||
keyOutput.textContent = '––––'
|
||||
if (pollTimer) clearInterval(pollTimer)
|
||||
downloads.style.display = 'none'
|
||||
xhr('POST', '/generate', function (x) {
|
||||
xhr('POST', './generate', function (x) {
|
||||
if (x.responseText !== 'error' && x.status === 200) {
|
||||
key = x.responseText
|
||||
keyOutput.textContent = key
|
||||
downloadlink.href = '/download/' + key
|
||||
downloadlink.href = './download/' + key
|
||||
if (pollTimer) clearInterval(pollTimer)
|
||||
pollTimer = setInterval(pollFile, 5 * 1000)
|
||||
} else {
|
||||
@@ -117,7 +128,7 @@ window.onload = function () {
|
||||
generateKey()
|
||||
}
|
||||
|
||||
siteurl.textContent = window.location.origin
|
||||
siteurl.textContent = window.location.href
|
||||
siteurl.href = siteurl.textContent
|
||||
siteurl.target = '_self'
|
||||
|
||||
@@ -30,7 +30,7 @@ h1 {
|
||||
.right {
|
||||
text-align: right;
|
||||
}
|
||||
#keygen, #downloadlink, #choosebtn, input[type="submit"] {
|
||||
#keygen, .downloadlink, #choosebtn, input[type="submit"] {
|
||||
background: #CCC;
|
||||
border: none;
|
||||
color: black;
|
||||
@@ -60,6 +60,9 @@ h1 {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
}
|
||||
.downloadlink {
|
||||
margin: 0.5em;
|
||||
}
|
||||
#downloads {
|
||||
display: none;
|
||||
}
|
||||
@@ -75,6 +78,13 @@ h1 {
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
input[type="url"], input[type="text"] {
|
||||
background: white;
|
||||
border: 1px solid #AAA;
|
||||
padding: 5px;
|
||||
font-family: serif;
|
||||
}
|
||||
|
||||
#uploadstatus {
|
||||
opacity: 0;
|
||||
transition: opacity .5s ease-in-out;
|
||||
@@ -110,5 +120,5 @@ td.aligntop {
|
||||
#fileinfo {
|
||||
font-size: 0.9em;
|
||||
font-style: italic;
|
||||
width: 17em;
|
||||
width: 18em;
|
||||
}
|
||||
@@ -4,17 +4,19 @@
|
||||
<title>Send to Kobo/Kindle</title>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css?o"/>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?o"/>
|
||||
<script src="./common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="wrapper">
|
||||
<h1 class="center">Send to Kobo/Kindle</h1>
|
||||
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<form action="./upload" method="post" enctype="multipart/form-data">
|
||||
<table style="margin: 0 auto;" cellpadding=0 cellspacing=0>
|
||||
<tr><td class="right"><label for="keyinput"><strong>Unique key</strong></label></td><td><input type="text" name="key" id="keyinput" autocomplete="off" pattern="...." placeholder="––––" required style="text-transform: uppercase;" maxlength=4/></td></tr>
|
||||
<tr><td class="right aligntop"><label for="fileinput"><strong>Ebook file</strong></label><br/><em>EPUB, MOBI, PDF,<br/>TXT, CBZ, CBR</em></td><td class="aligntop"><label for="fileinput" id="choosebtn">Choose file</label><input type="file" name="file" id="fileinput" accept=".txt,.epub,.mobi,.pdf,.cbz,.cbr,application/epub+zip,application/x-mobipocket-ebook,application/pdf,application/vnd.comicbook+zip,application/vnd.comicbook-rar" required /><br/><br/><div id="fileinfo"></div></td></tr>
|
||||
<tr><td class="right aligntop"><label for="fileinput"><strong>Ebook file</strong></label><br/><em>EPUB, MOBI, PDF,<br/>TXT, CBZ, CBR</em></td><td class="aligntop"><label for="fileinput" id="choosebtn">Choose file</label><input type="file" name="file" id="fileinput" accept=".txt,.epub,.mobi,.pdf,.cbz,.cbr,application/epub+zip,application/x-mobipocket-ebook,application/pdf,application/vnd.comicbook+zip,application/vnd.comicbook-rar"/><br/><br/><div id="fileinfo"></div></td></tr>
|
||||
<tr><td class="right"><label for="urlinput"><strong>Send url</strong></label></td><td><input type="url" name="url" id="urlinput" autocomplete="off" style="width: 100%"></td></tr>
|
||||
<tr><td class="right"><label for="kepubify"><strong>Kepubify</strong><br/><em>Kobo only</em></label></td><td><input type="checkbox" name="kepubify" id="kepubify" checked /></td></tr>
|
||||
<tr class="center"><td colspan="2"><input type="submit" value="Upload and send" /></td></tr>
|
||||
</table>
|
||||
@@ -33,37 +35,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logs"></div>
|
||||
|
||||
<script>
|
||||
function getCookies() {
|
||||
var cookieRegex = /([\w\.]+)\s*=\s*(?:"((?:\\"|[^"])*)"|(.*?))\s*(?:[;,]|$)/g
|
||||
var cookies = {}
|
||||
var match
|
||||
while( (match = cookieRegex.exec(document.cookie)) !== null ) {
|
||||
var value = match[2] || match[3]
|
||||
cookies[match[1]] = decodeURIComponent(value)
|
||||
try {
|
||||
cookies[match[1]] = JSON.parse(cookies[match[1]])
|
||||
} catch (err) {}
|
||||
}
|
||||
return cookies
|
||||
}
|
||||
function deleteCookie(name) {
|
||||
document.cookie = name + "= ; expires = Thu, 01 Jan 1970 00:00:00 GMT"
|
||||
}
|
||||
|
||||
|
||||
var uploadstatus = document.getElementById('uploadstatus')
|
||||
var keyinput = document.getElementById('keyinput')
|
||||
var fileinput = document.getElementById('fileinput')
|
||||
var fileinputAccept = fileinput.accept.split(',') // cache it
|
||||
var fileinfo = document.getElementById('fileinfo')
|
||||
var urlinput = document.getElementById('urlinput')
|
||||
var siteurl = document.getElementById('siteurl')
|
||||
|
||||
|
||||
var isIOS = /iPad|iPhone|iPod/.test(navigator.platform) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)
|
||||
|
||||
var flash = getCookies().flash
|
||||
deleteCookie('flash')
|
||||
// deleteCookie('flash')
|
||||
|
||||
if (flash) {
|
||||
if (flash.message) {
|
||||
@@ -77,6 +61,7 @@ if (flash) {
|
||||
uploadstatus.style.opacity = 1
|
||||
}
|
||||
keyinput.value = flash.key || ''
|
||||
urlinput.value = flash.url || ''
|
||||
}
|
||||
uploadstatus.addEventListener('click', function () {
|
||||
uploadstatus.style.opacity = 0
|
||||
@@ -86,6 +71,10 @@ uploadstatus.addEventListener('click', function () {
|
||||
}, 500)
|
||||
}, false)
|
||||
|
||||
document.body.addEventListener("drop", function () {
|
||||
log("file dropped")
|
||||
}, false)
|
||||
|
||||
function fileinputChange () {
|
||||
if (!fileinput.files[0] || fileinput.files.length === 0) {
|
||||
fileinfo.textContent = ''
|
||||
@@ -117,6 +106,7 @@ function fileinputChange () {
|
||||
|
||||
fileinfo.innerHTML = filename + "<br/>Filesize: " + Math.ceil(fileinput.files[0].size / 1024) + ' kB'
|
||||
}
|
||||
|
||||
fileinput.addEventListener('change', fileinputChange, false)
|
||||
fileinputChange()
|
||||
|
||||
@@ -125,11 +115,10 @@ if (isIOS) {
|
||||
fileinput.accept = ''
|
||||
}
|
||||
|
||||
siteurl.textContent = window.location.origin
|
||||
siteurl.textContent = window.location.href
|
||||
siteurl.href = siteurl.textContent
|
||||
siteurl.target = '_self'
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user