Fix update tracklist and invalid parts alert, update readme screenshots
@ -51,11 +51,9 @@
|
|||||||
<div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-60 overflow-y-scroll mt-2 max-w-full">
|
<div v-if="hasSearched" class="flex items-center flex-wrap justify-center max-h-60 overflow-y-scroll mt-2 max-w-full">
|
||||||
<p v-if="!coversFound.length">No Covers Found</p>
|
<p v-if="!coversFound.length">No Covers Found</p>
|
||||||
<template v-for="cover in coversFound">
|
<template v-for="cover in coversFound">
|
||||||
<ui-tooltip :key="cover" direction="bottom" :text="cover">
|
<div :key="cover" class="m-0.5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === imageUrl ? 'border-yellow-300' : ''" @click="setCover(cover)">
|
||||||
<div class="m-0.5 border-2 border-transparent hover:border-yellow-300 cursor-pointer" :class="cover === imageUrl ? 'border-yellow-300' : ''" @click="setCover(cover)">
|
<img :src="cover" class="h-24 object-cover" style="width: 60px" />
|
||||||
<img :src="cover" class="h-24 object-cover" style="width: 60px" />
|
</div>
|
||||||
</div>
|
|
||||||
</ui-tooltip>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -163,7 +161,7 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
getSearchQuery() {
|
getSearchQuery() {
|
||||||
var searchQuery = `provider=best&title=${this.searchTitle}`
|
var searchQuery = `provider=openlibrary&title=${this.searchTitle}`
|
||||||
if (this.searchAuthor) searchQuery += `&author=${this.searchAuthor}`
|
if (this.searchAuthor) searchQuery += `&author=${this.searchAuthor}`
|
||||||
return searchQuery
|
return searchQuery
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "0.9.78-beta",
|
"version": "0.9.79-beta",
|
||||||
"description": "Audiobook manager and player",
|
"description": "Audiobook manager and player",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -52,7 +52,9 @@
|
|||||||
<p class="text-sm mb-2">
|
<p class="text-sm mb-2">
|
||||||
Invalid Parts <span class="text-sm">({{ invalidParts.length }})</span>
|
Invalid Parts <span class="text-sm">({{ invalidParts.length }})</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm font-mono">{{ invalidParts.join(', ') }}</p>
|
<div>
|
||||||
|
<p v-for="part in invalidParts" :key="part" class="text-sm font-mono">{{ part.filename }}: {{ part.error }}</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<tables-tracks-table :tracks="tracks" :audiobook-id="audiobook.id" class="mt-6" />
|
<tables-tracks-table :tracks="tracks" :audiobook-id="audiobook.id" class="mt-6" />
|
||||||
|
Before Width: | Height: | Size: 185 KiB After Width: | Height: | Size: 196 KiB |
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.1 MiB |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "0.9.78-beta",
|
"version": "0.9.79-beta",
|
||||||
"description": "Self-hosted audiobook server for managing and playing audiobooks.",
|
"description": "Self-hosted audiobook server for managing and playing audiobooks.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -4,7 +4,7 @@ AudioBookshelf is a self-hosted audiobook server for managing and playing your a
|
|||||||
|
|
||||||
**Currently in Beta** - **Free & open source Android/iOS app is in development**
|
**Currently in Beta** - **Free & open source Android/iOS app is in development**
|
||||||
|
|
||||||
<img alt="Screenshot1" src="https://github.com/advplyr/audiobookshelf/raw/master/images/ss_bookshelf.png" />
|
<img alt="Screenshot1" src="https://github.com/advplyr/audiobookshelf/raw/master/images/ss_streaming.png" />
|
||||||
|
|
||||||
|
|
||||||
#### Folder Structures Supported:
|
#### Folder Structures Supported:
|
||||||
@ -27,7 +27,7 @@ Title can start with the publish year like so:
|
|||||||
* Add ability to add/manage additional accounts with varying access levels
|
* Add ability to add/manage additional accounts with varying access levels
|
||||||
* Then comes the mobile app..
|
* Then comes the mobile app..
|
||||||
|
|
||||||
<img alt="Screenshot2" src="https://github.com/advplyr/audiobookshelf/raw/master/images/ss_streaming.png" />
|
<img alt="Screenshot2" src="https://github.com/advplyr/audiobookshelf/raw/master/images/ss_audiobook.png" />
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -37,8 +37,6 @@ Built to run in Docker for now (also on Unraid server Community Apps)
|
|||||||
docker run -d -p 1337:80 -v /audiobooks:/audiobooks -v /config:/config -v /metadata:/metadata --name audiobookshelf --rm advplyr/audiobookshelf
|
docker run -d -p 1337:80 -v /audiobooks:/audiobooks -v /config:/config -v /metadata:/metadata --name audiobookshelf --rm advplyr/audiobookshelf
|
||||||
```
|
```
|
||||||
|
|
||||||
<img alt="Screenshot3" src="https://github.com/advplyr/audiobookshelf/raw/master/images/ss_audiobook.png" />
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Feel free to help out
|
Feel free to help out
|
@ -8,6 +8,9 @@ class AudioFile {
|
|||||||
this.fullPath = null
|
this.fullPath = null
|
||||||
this.addedAt = null
|
this.addedAt = null
|
||||||
|
|
||||||
|
this.trackNumFromMeta = null
|
||||||
|
this.trackNumFromFilename = null
|
||||||
|
|
||||||
this.format = null
|
this.format = null
|
||||||
this.duration = null
|
this.duration = null
|
||||||
this.size = null
|
this.size = null
|
||||||
@ -42,6 +45,8 @@ class AudioFile {
|
|||||||
path: this.path,
|
path: this.path,
|
||||||
fullPath: this.fullPath,
|
fullPath: this.fullPath,
|
||||||
addedAt: this.addedAt,
|
addedAt: this.addedAt,
|
||||||
|
trackNumFromMeta: this.trackNumFromMeta,
|
||||||
|
trackNumFromFilename: this.trackNumFromFilename,
|
||||||
manuallyVerified: !!this.manuallyVerified,
|
manuallyVerified: !!this.manuallyVerified,
|
||||||
invalid: !!this.invalid,
|
invalid: !!this.invalid,
|
||||||
error: this.error || null,
|
error: this.error || null,
|
||||||
@ -73,6 +78,9 @@ class AudioFile {
|
|||||||
this.invalid = !!data.invalid
|
this.invalid = !!data.invalid
|
||||||
this.error = data.error || null
|
this.error = data.error || null
|
||||||
|
|
||||||
|
this.trackNumFromMeta = data.trackNumFromMeta || null
|
||||||
|
this.trackNumFromFilename = data.trackNumFromFilename || null
|
||||||
|
|
||||||
this.format = data.format
|
this.format = data.format
|
||||||
this.duration = data.duration
|
this.duration = data.duration
|
||||||
this.size = data.size
|
this.size = data.size
|
||||||
@ -92,13 +100,16 @@ class AudioFile {
|
|||||||
|
|
||||||
setData(data) {
|
setData(data) {
|
||||||
this.index = data.index || null
|
this.index = data.index || null
|
||||||
this.ino = data.ino
|
this.ino = data.ino || null
|
||||||
this.filename = data.filename
|
this.filename = data.filename
|
||||||
this.ext = data.ext
|
this.ext = data.ext
|
||||||
this.path = data.path
|
this.path = data.path
|
||||||
this.fullPath = data.fullPath
|
this.fullPath = data.fullPath
|
||||||
this.addedAt = Date.now()
|
this.addedAt = Date.now()
|
||||||
|
|
||||||
|
this.trackNumFromMeta = data.trackNumFromMeta || null
|
||||||
|
this.trackNumFromFilename = data.trackNumFromFilename || null
|
||||||
|
|
||||||
this.manuallyVerified = !!data.manuallyVerified
|
this.manuallyVerified = !!data.manuallyVerified
|
||||||
this.invalid = !!data.invalid
|
this.invalid = !!data.invalid
|
||||||
this.error = data.error || null
|
this.error = data.error || null
|
||||||
|
@ -20,7 +20,6 @@ class Audiobook {
|
|||||||
|
|
||||||
this.tracks = []
|
this.tracks = []
|
||||||
this.missingParts = []
|
this.missingParts = []
|
||||||
this.invalidParts = []
|
|
||||||
|
|
||||||
this.audioFiles = []
|
this.audioFiles = []
|
||||||
this.otherFiles = []
|
this.otherFiles = []
|
||||||
@ -94,6 +93,10 @@ class Audiobook {
|
|||||||
return elapsedPretty(this.totalDuration)
|
return elapsedPretty(this.totalDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get invalidParts() {
|
||||||
|
return (this.audioFiles || []).filter(af => af.invalid).map(af => ({ filename: af.filename, error: af.error || 'Unknown Error' }))
|
||||||
|
}
|
||||||
|
|
||||||
bookToJSON() {
|
bookToJSON() {
|
||||||
return this.book ? this.book.toJSON() : null
|
return this.book ? this.book.toJSON() : null
|
||||||
}
|
}
|
||||||
@ -115,7 +118,6 @@ class Audiobook {
|
|||||||
addedAt: this.addedAt,
|
addedAt: this.addedAt,
|
||||||
lastUpdate: this.lastUpdate,
|
lastUpdate: this.lastUpdate,
|
||||||
missingParts: this.missingParts,
|
missingParts: this.missingParts,
|
||||||
invalidParts: this.invalidParts,
|
|
||||||
tags: this.tags,
|
tags: this.tags,
|
||||||
book: this.bookToJSON(),
|
book: this.bookToJSON(),
|
||||||
tracks: this.tracksToJSON(),
|
tracks: this.tracksToJSON(),
|
||||||
@ -278,10 +280,9 @@ class Audiobook {
|
|||||||
file.invalid = false
|
file.invalid = false
|
||||||
file.error = null
|
file.error = null
|
||||||
file.index = index++
|
file.index = index++
|
||||||
return file
|
return new AudioFile(file)
|
||||||
})
|
})
|
||||||
this.tracks = []
|
this.tracks = []
|
||||||
this.invalidParts = []
|
|
||||||
this.missingParts = []
|
this.missingParts = []
|
||||||
this.audioFiles.forEach((file) => {
|
this.audioFiles.forEach((file) => {
|
||||||
this.addTrack(file)
|
this.addTrack(file)
|
||||||
|
@ -106,28 +106,28 @@ async function scanAudioFiles(audiobook, newAudioFiles) {
|
|||||||
trackNumFromMeta,
|
trackNumFromMeta,
|
||||||
trackNumFromFilename
|
trackNumFromFilename
|
||||||
}
|
}
|
||||||
audiobook.addAudioFile(audioFileObj)
|
var audioFile = audiobook.addAudioFile(audioFileObj)
|
||||||
|
|
||||||
var trackNumber = 1
|
var trackNumber = 1
|
||||||
if (newAudioFiles.length > 1) {
|
if (newAudioFiles.length > 1) {
|
||||||
trackNumber = isNumber(trackNumFromMeta) ? trackNumFromMeta : trackNumFromFilename
|
trackNumber = isNumber(trackNumFromMeta) ? trackNumFromMeta : trackNumFromFilename
|
||||||
if (trackNumber === null) {
|
if (trackNumber === null) {
|
||||||
Logger.error('[AudioFileScanner] Invalid track number for', audioFile.filename)
|
Logger.error('[AudioFileScanner] Invalid track number for', audioFile.filename)
|
||||||
audioFileObj.invalid = true
|
audioFile.invalid = true
|
||||||
audioFileObj.error = 'Failed to get track number'
|
audioFile.error = 'Failed to get track number'
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracks.find(t => t.index === trackNumber)) {
|
if (tracks.find(t => t.index === trackNumber)) {
|
||||||
Logger.error('[AudioFileScanner] Duplicate track number for', audioFile.filename)
|
Logger.error('[AudioFileScanner] Duplicate track number for', audioFile.filename)
|
||||||
audioFileObj.invalid = true
|
audioFile.invalid = true
|
||||||
audioFileObj.error = 'Duplicate track number'
|
audioFile.error = 'Duplicate track number'
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
audioFileObj.index = trackNumber
|
audioFile.index = trackNumber
|
||||||
tracks.push(audioFileObj)
|
tracks.push(audioFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tracks.length) {
|
if (!tracks.length) {
|
||||||
|