-
+
-
{{ text }}
+
{{ text }}
diff --git a/client/components/ui/TextInputWithLabel.vue b/client/components/ui/TextInputWithLabel.vue
index 21134272..a77c45a6 100644
--- a/client/components/ui/TextInputWithLabel.vue
+++ b/client/components/ui/TextInputWithLabel.vue
@@ -1,6 +1,8 @@
-
{{ label }}
+
+ {{ label }}{{ note }}
+
@@ -10,6 +12,7 @@ export default {
props: {
value: [String, Number],
label: String,
+ note: String,
type: {
type: String,
default: 'text'
diff --git a/client/package.json b/client/package.json
index f344fa22..27789fc2 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-client",
- "version": "1.1.6",
+ "version": "1.1.7",
"description": "Audiobook manager and player",
"main": "index.js",
"scripts": {
diff --git a/client/pages/upload/index.vue b/client/pages/upload/index.vue
new file mode 100644
index 00000000..012dd129
--- /dev/null
+++ b/client/pages/upload/index.vue
@@ -0,0 +1,258 @@
+
+
+
+
+ (Experimental)Audiobook Uploader
+
+
+
+
+
+
+ Drop em'
+ Drop your audio and image files or
+
+
+ Select files
+ {{ inputAccept.join(', ') }}
+
+
+
+ * No valid audio tracks
+
+
+
Cover Image(s)
+
+
+
+
+
+
+
+
+
+
+
Audio Tracks
+
+
+
+ Filename |
+ Type |
+ Size |
+
+
+
+
+ {{ file.name }}
+ |
+
+ {{ file.type }}
+ |
+
+ {{ $bytesPretty(file.size) }}
+ |
+
+
+
+
+
+
+
Invalid Files
+
+
+ Filename |
+ Type |
+ Size |
+
+
+
+
+ {{ file.name }}
+ |
+
+ {{ file.type }}
+ |
+
+ {{ $bytesPretty(file.size) }}
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index cb88dd9d..f85613e3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf",
- "version": "0.9.76-beta",
+ "version": "1.1.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -165,6 +165,14 @@
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
+ "busboy": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.3.1.tgz",
+ "integrity": "sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==",
+ "requires": {
+ "dicer": "0.3.0"
+ }
+ },
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
@@ -291,6 +299,14 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
+ "dicer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.3.0.tgz",
+ "integrity": "sha512-MdceRRWqltEG2dZqO769g27N/3PXfcKl04VhYnBlo2YhH7zPi88VebsjTKclaOyiuMaGU72hTfw3VkUitGcVCA==",
+ "requires": {
+ "streamsearch": "0.1.2"
+ }
+ },
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -406,6 +422,14 @@
"vary": "~1.1.2"
}
},
+ "express-fileupload": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.2.1.tgz",
+ "integrity": "sha512-fWPNAkBj+Azt9Itmcz/Reqdg3LeBfaXptDEev2JM8bCC0yDptglCnlizhf0YZauyU5X/g6v7v4Xxqhg8tmEfEA==",
+ "requires": {
+ "busboy": "^0.3.1"
+ }
+ },
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -1017,6 +1041,11 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
+ "streamsearch": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
+ "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
+ },
"string-indexes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/string-indexes/-/string-indexes-1.0.0.tgz",
diff --git a/package.json b/package.json
index 8a88e279..6b5f70ca 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "audiobookshelf",
- "version": "1.1.6",
+ "version": "1.1.7",
"description": "Self-hosted audiobook server for managing and playing audiobooks.",
"main": "index.js",
"scripts": {
@@ -14,6 +14,7 @@
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
+ "express-fileupload": "^1.2.1",
"fluent-ffmpeg": "^2.1.2",
"fs-extra": "^10.0.0",
"ip": "^1.1.5",
diff --git a/server/Server.js b/server/Server.js
index baee4945..1522def9 100644
--- a/server/Server.js
+++ b/server/Server.js
@@ -3,6 +3,7 @@ const express = require('express')
const http = require('http')
const SocketIO = require('socket.io')
const fs = require('fs-extra')
+const fileUpload = require('express-fileupload')
const Auth = require('./Auth')
const Watcher = require('./Watcher')
@@ -132,6 +133,7 @@ class Server {
this.server = http.createServer(app)
app.use(this.auth.cors)
+ app.use(fileUpload())
// Static path to generated nuxt
const distPath = Path.join(global.appRoot, '/client/dist')
@@ -155,6 +157,39 @@ class Server {
// app.use('/hls', this.hlsController.router)
app.use('/feeds', this.rssFeeds.router)
+ app.post('/upload', this.authMiddleware.bind(this), async (req, res) => {
+ var files = Object.values(req.files)
+ var title = req.body.title
+ var author = req.body.author
+ var series = req.body.series
+
+ if (!files.length || !title || !author) {
+ return res.json({
+ error: 'Invalid post data received'
+ })
+ }
+
+ var outputDirectory = ''
+ if (series && series.length && series !== 'null') {
+ outputDirectory = Path.join(this.AudiobookPath, author, series, title)
+ } else {
+ outputDirectory = Path.join(this.AudiobookPath, author, title)
+ }
+
+ await fs.ensureDir(outputDirectory)
+ Logger.info(`Uploading ${files.length} files to`, outputDirectory)
+
+ for (let i = 0; i < files.length; i++) {
+ var file = files[i]
+
+ var path = Path.join(outputDirectory, file.name)
+ await file.mv(path).catch((error) => {
+ Logger.error('Failed to move file', path, error)
+ })
+ }
+ res.sendStatus(200)
+ })
+
app.post('/login', (req, res) => this.auth.login(req, res))
app.post('/logout', this.logout.bind(this))
app.get('/ping', (req, res) => {