fix filename encoding on kobo, add checkbox for kindlegen and transliteration

This commit is contained in:
daniel-j
2024-07-21 15:11:45 +02:00
parent 235308f5f3
commit c1b6f9d3ea
3 changed files with 48 additions and 23 deletions

View File

@@ -109,7 +109,7 @@ const upload = multer({
fileFilter: (req, file, cb) => {
// Fixes charset
// https://github.com/expressjs/multer/issues/1104#issuecomment-1152987772
file.originalname = doTransliterate(Buffer.from(file.originalname, 'latin1').toString('utf8'))
file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8')
console.log('Incoming file:', file)
const key = req.body.key.toUpperCase()
@@ -159,13 +159,22 @@ router.post('/generate', async ctx => {
if(ctx.keys.get(key) === info) removeKey(key)
}, maxExpireDuration * 1000)
ctx.cookies.set('key', key, {overwrite: true, httpOnly: false, sameSite: 'strict', maxAge: expireDelay * 1000})
ctx.body = key
})
router.get('/download/:key', async ctx => {
const key = ctx.params.key.toUpperCase()
async function downloadFile (ctx, next) {
const key = ctx.cookies.get('key')
if (!key) {
await next()
return
}
const filename = decodeURIComponent(ctx.params.filename)
const info = ctx.keys.get(key)
if (!info || !info.file) {
if (!info || !info.file || info.file.name !== filename) {
await next()
return
}
if (info.agent !== ctx.get('user-agent')) {
@@ -173,18 +182,13 @@ router.get('/download/:key', async ctx => {
return
}
expireKey(key)
// const fallback = basename(info.file.path)
const sanename = info.file.name.replace(/[^\.\w\-"'\(\)]/g, '_')
console.log('Sending file', [info.file.path, info.file.name, sanename])
await sendfile(ctx, info.file.path)
console.log('Sending file', [info.file.path, info.file.name])
if (info.agent.includes('Kindle')) {
// Kindle needs a safe name or it thinks it's an invalid file
ctx.attachment(sanename)
} else {
// Kobo always uses fallback
ctx.attachment(info.file.name, {fallback: sanename})
ctx.attachment(info.file.name)
}
})
await sendfile(ctx, info.file.path)
}
router.post('/upload', async (ctx, next) => {
@@ -282,8 +286,14 @@ router.post('/upload', async (ctx, next) => {
let data = null
filename = ctx.request.file.originalname
if (ctx.request.body.transliteration) {
filename = doTransliterate(filename)
}
if (info.agent.includes('Kindle')) {
filename = filename.replace(/[^\.\w\-"'\(\)]/g, '_')
}
if (mimetype === TYPE_EPUB && info.agent.includes('Kindle')) {
if (mimetype === TYPE_EPUB && info.agent.includes('Kindle') && ctx.request.body.kindlegen) {
// convert to .mobi
conversion = 'kindlegen'
const outname = ctx.request.file.path.replace(/\.epub$/i, '.mobi')
@@ -411,6 +421,7 @@ router.get('/status/:key', async ctx => {
return
}
expireKey(key)
ctx.cookies.set('key', key, {overwrite: true, httpOnly: false, sameSite: 'strict', maxAge: expireDelay * 1000})
ctx.body = {
alive: info.alive,
file: info.file ? {
@@ -431,10 +442,13 @@ router.get('/', async ctx => {
await sendfile(ctx, agent.includes('Kobo') || agent.includes('Kindle') || agent.toLowerCase().includes('tolino') ? 'static/download.html' : 'static/upload.html')
})
router.get('/:filename', downloadFile)
app.use(serve("static"))
app.use(router.routes())
app.use(router.allowedMethods())
app.use(serve("static"))
fs.rm('uploads', {recursive: true}, (err) => {
if (err) throw err

View File

@@ -84,6 +84,7 @@ function pollFile () {
if (data.file) {
downloads.style.display = 'block'
downloadlink.textContent = data.file.name
downloadlink.href = '/' + encodeURIComponent(data.file.name)
} else {
downloads.style.display = 'none'
}
@@ -111,7 +112,7 @@ function generateKey () {
if (x.responseText !== 'error' && x.status === 200) {
key = x.responseText
keyOutput.textContent = key
downloadlink.href = './download/' + key
downloadlink.href = ''
if (pollTimer) clearInterval(pollTimer)
pollTimer = setInterval(pollFile, 5 * 1000)
} else {

View File

@@ -16,14 +16,16 @@
<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/epub,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><td class="right"><input type="checkbox" name="kepubify" id="kepubify" checked /></td><td><label for="kepubify"><strong>Kepubify</strong> <em>Kobo only</em></label></td></tr>
<tr><td class="right"><input type="checkbox" name="kindlegen" id="kindlegen" checked /></td><td><label for="kindlegen"><strong>KindleGen</strong> <em>Kindle only</em></label></td></tr>
<tr><td class="right"><input type="checkbox" name="transliteration" id="transliteration" /></td><td><label for="transliteration"><strong>Transliteration of filename</strong></label></td></tr>
<tr class="center"><td colspan="2"><input type="submit" value="Upload and send" /></td></tr>
</table>
<div id="uploadstatus"></div>
</form>
<div style="padding: 15px; padding-top: 0; text-align: justify;">
<p>Go this this page on your Kobo/Kindle ereader and you see a unique key. Enter it in this form and upload an ebook and it will appear as a download link on the ereader.</p>
<p>If you send an EPUB file to to a Kindle it will be converted to MOBI with KindleGen. If you send a MOBI file to a Kindle it will be sent unprocessed. If you send an EPUB file and tick the Kepubify checkbox, it will be converted into a Kobo EPUB using Kepubify. If you send a MOBI file to a Kobo, it will not be converted.</p>
<p>If you send an EPUB file to to a Kindle it will be converted to MOBI with KindleGen. If you send a MOBI file to a Kindle it will be sent unprocessed. Files sent to Kindle eReaders will have their names stripped of special characters, a limitation of the Kindle browser. If you send an EPUB file and tick the Kepubify checkbox, it will be converted into a Kobo EPUB using Kepubify. If you send a MOBI file to a Kobo, it will not be converted.</p>
<p>Your ebook will be stored on the server as long as your Kobo/Kindle is viewing the unique key and is connected to wifi. It will be deleted irrevocably when the key expires about 30 seconds after you close the browser, generate a new key or disable wifi on your ereader.</p>
<p>By using this tool you agree that the ebook you upload is processed on the server and stored for a short time.</p>
</div>
@@ -48,8 +50,9 @@ var siteurl = document.getElementById('siteurl')
var flashtimer = null
function handleFlash(flash) {
if (!flash) flash = getCookies().flash
function handleFlash(flashFallback) {
var flash = getCookies().flash
if (!flash) flash = flashFallback
console.log(flash)
clearTimeout(flashtimer)
if (flash) {
@@ -63,8 +66,12 @@ function handleFlash(flash) {
}
uploadstatus.style.opacity = 1
}
keyinput.value = flash.key || ''
urlinput.value = flash.url || ''
if (flash.key) {
keyinput.value = flash.key
}
if (flash.url) {
urlinput.value = flash.url
}
} else {
uploadstatus.style.opacity = 0
@@ -146,7 +153,10 @@ uploadform.addEventListener('submit', function (e) {
}
req.onerror = function () {
console.log('upload error', req.status)
handleFlash()
handleFlash({
success: false,
message: "Upload error - is the key correct?"
})
}
req.onabort = function () {
console.log('aborted', req.status)