Add:Language and ASIN id3 tag parse, language filter, asin search, asin audible match, add fields to details #305

This commit is contained in:
advplyr 2022-01-09 18:37:16 -06:00
parent afd2b8c98f
commit b284a9bd57
13 changed files with 128 additions and 27 deletions

View File

@ -18,6 +18,9 @@
</div>
<div v-else-if="!totalShelves && initialized" class="w-full py-16">
<p class="text-xl text-center">{{ emptyMessage }}</p>
<div class="flex justify-center mt-2">
<ui-btn v-if="hasFilter" color="primary" @click="clearFilter">Clear Filter</ui-btn>
</div>
</div>
<widgets-cover-size-widget class="fixed bottom-4 right-4 z-30" />
@ -86,6 +89,7 @@ export default {
emptyMessage() {
if (this.page === 'series') return `You have no series`
if (this.page === 'collections') return "You haven't made any collections yet"
if (this.hasFilter) return `No Results for filter "${this.filterValue}"`
return 'No results'
},
entityName() {
@ -120,6 +124,17 @@ export default {
hasFilter() {
return this.filterBy && this.filterBy !== 'all'
},
filterName() {
if (!this.filterBy) return ''
var filter = this.filterBy.split('.')[0]
filter = filter.substr(0, 1).toUpperCase() + filter.substr(1)
return filter
},
filterValue() {
if (!this.filterBy) return ''
if (!this.filterBy.includes('.')) return ''
return this.$decode(this.filterBy.split('.')[1])
},
currentLibraryId() {
return this.$store.state.libraries.currentLibraryId
},
@ -175,6 +190,9 @@ export default {
showBookshelfTextureModal() {
this.$store.commit('globals/setShowBookshelfTextureModal', true)
},
clearFilter() {
this.$store.dispatch('user/updateUserSettings', { filterBy: 'all' })
},
editEntity(entity) {
if (this.entityName === 'books' || this.entityName === 'series-books') {
var bookIds = this.entities.map((e) => e.id)

View File

@ -10,7 +10,7 @@
<p v-if="matchKey !== 'authorFL'" class="text-xs text-gray-200 truncate">by {{ authorFL }}</p>
<p v-else class="truncate text-xs text-gray-200" v-html="matchHtml" />
<div v-if="matchKey === 'series' || matchKey === 'tags' || matchKey === 'isbn'" class="m-0 p-0 truncate text-xs" v-html="matchHtml" />
<div v-if="matchKey === 'series' || matchKey === 'tags' || matchKey === 'isbn' || matchKey === 'asin'" class="m-0 p-0 truncate text-xs" v-html="matchHtml" />
</div>
</div>
</template>
@ -71,6 +71,7 @@ export default {
if (this.matchKey === 'tags') return `<p class="truncate">Tags: ${html}</p>`
if (this.matchKey === 'authorFL') return `by ${html}`
if (this.matchKey === 'isbn') return `<p class="truncate">ISBN: ${html}</p>`
if (this.matchKey === 'asin') return `<p class="truncate">ASIN: ${html}</p>`
if (this.matchKey === 'series') return `<p class="truncate">Series: ${html}</p>`
return `${html}`
}

View File

@ -14,7 +14,7 @@
</div>
</button>
<div v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-80 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
<div v-show="showMenu" class="absolute z-10 mt-1 w-full bg-bg border border-black-200 shadow-lg max-h-96 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
<ul v-show="!sublist" class="h-full w-full" role="listbox" aria-labelledby="listbox-label">
<template v-for="item in items">
<li :key="item.value" class="text-gray-50 select-none relative py-2 pr-9 cursor-pointer hover:bg-black-400" :class="item.value === selected ? 'bg-primary bg-opacity-50' : ''" role="option" @click="clickedOption(item)">
@ -97,6 +97,11 @@ export default {
value: 'narrators',
sublist: true
},
{
text: 'Language',
value: 'languages',
sublist: true
},
{
text: 'Progress',
value: 'progress',
@ -155,6 +160,9 @@ export default {
narrators() {
return this.filterData.narrators || []
},
languages() {
return this.filterData.languages || []
},
progress() {
return ['Read', 'Unread', 'In Progress']
},

View File

@ -2,9 +2,14 @@
<div class="w-full h-full relative">
<form class="w-full h-full" @submit.prevent="submitForm">
<div ref="formWrapper" class="px-4 py-6 details-form-wrapper w-full overflow-hidden overflow-y-auto">
<div class="flex -mx-1">
<div class="w-1/2 px-1">
<ui-text-input-with-label v-model="details.title" label="Title" />
<ui-text-input-with-label v-model="details.subtitle" label="Subtitle" class="mt-2" />
</div>
<div class="flex-grow px-1">
<ui-text-input-with-label v-model="details.subtitle" label="Subtitle" />
</div>
</div>
<div class="flex mt-2 -mx-1">
<div class="w-3/4 px-1">
@ -43,8 +48,17 @@
<ui-text-input-with-label v-model="details.publisher" label="Publisher" />
</div>
<div class="flex-grow px-1">
<ui-text-input-with-label v-model="details.language" label="Language" />
</div>
</div>
<div class="flex mt-2 -mx-1">
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="details.isbn" label="ISBN" />
</div>
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="details.asin" label="ASIN" />
</div>
</div>
</div>
@ -90,7 +104,9 @@ export default {
volumeNumber: null,
publishYear: null,
publisher: null,
language: null,
isbn: null,
asin: null,
genres: []
},
newTags: [],
@ -231,7 +247,9 @@ export default {
this.details.volumeNumber = this.book.volumeNumber
this.details.publishYear = this.book.publishYear
this.details.publisher = this.book.publisher || null
this.details.language = this.book.language || null
this.details.isbn = this.book.isbn || null
this.details.asin = this.book.asin || null
this.newTags = this.audiobook.tags || []
},

View File

@ -65,10 +65,7 @@
<ui-checkbox v-model="selectedMatchUsage.publishYear" />
<ui-text-input-with-label v-model="selectedMatch.publishYear" :disabled="!selectedMatchUsage.publishYear" label="Publish Year" class="flex-grow ml-4" />
</div>
<div v-if="selectedMatch.isbn" class="flex items-center py-2">
<ui-checkbox v-model="selectedMatchUsage.isbn" />
<ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" class="flex-grow ml-4" />
</div>
<div v-if="selectedMatch.series" class="flex items-center py-2">
<ui-checkbox v-model="selectedMatchUsage.series" />
<ui-text-input-with-label v-model="selectedMatch.series" :disabled="!selectedMatchUsage.series" label="Series" class="flex-grow ml-4" />
@ -77,10 +74,14 @@
<ui-checkbox v-model="selectedMatchUsage.volumeNumber" />
<ui-text-input-with-label v-model="selectedMatch.volumeNumber" :disabled="!selectedMatchUsage.volumeNumber" label="Volume Number" class="flex-grow ml-4" />
</div>
<!-- <div v-if="selectedMatch.asin" class="flex items-center py-2">
<div v-if="selectedMatch.isbn" class="flex items-center py-2">
<ui-checkbox v-model="selectedMatchUsage.isbn" />
<ui-text-input-with-label v-model="selectedMatch.isbn" :disabled="!selectedMatchUsage.isbn" label="ISBN" class="flex-grow ml-4" />
</div>
<div v-if="selectedMatch.asin" class="flex items-center py-2">
<ui-checkbox v-model="selectedMatchUsage.asin" />
<ui-text-input-with-label v-model="selectedMatch.asin" :disabled="!selectedMatchUsage.asin" label="ASIN" class="flex-grow ml-4" />
</div> -->
</div>
<div class="flex items-center justify-end py-2">
<ui-btn color="success" type="submit">Update</ui-btn>
</div>
@ -115,11 +116,12 @@ export default {
author: true,
narrator: true,
description: true,
isbn: true,
publisher: true,
publishYear: true,
series: true,
volumeNumber: true
volumeNumber: true,
asin: true,
isbn: true
}
}
},
@ -194,11 +196,12 @@ export default {
author: true,
narrator: true,
description: true,
isbn: true,
publisher: true,
publishYear: true,
series: true,
volumeNumber: true
volumeNumber: true,
asin: true,
isbn: true
}
if (this.audiobook.id !== this.audiobookId) {

View File

@ -9,7 +9,7 @@
<draggable :list="libraryCopies" v-bind="dragOptions" class="list-group" draggable=".item" tag="div" @start="startDrag" @end="endDrag">
<template v-for="library in libraryCopies">
<div :key="library.id" class="item">
<modals-libraries-library-item :library="library" :selected="currentLibraryId === library.id" :show-edit="true" :dragging="drag" @edit="editLibrary" @sort="draggableSort" @click="setLibrary" />
<modals-libraries-library-item :library="library" :selected="currentLibraryId === library.id" :show-edit="true" :dragging="drag" @edit="editLibrary" @click="setLibrary" />
</div>
</template>
</draggable>

View File

@ -67,10 +67,30 @@
</div>
</div>
<div class="flex mt-2 -mx-1">
<!-- <div class="flex mt-2 -mx-1">
<div class="w-1/2 px-1">
<ui-text-input-with-label v-model="audiobook.book.narrator" label="Narrator" />
</div>
</div> -->
<div class="flex mt-2 -mx-1">
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="audiobook.book.narrator" label="Narrator" />
</div>
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="audiobook.book.publisher" label="Publisher" />
</div>
<div class="flex-grow px-1">
<ui-text-input-with-label v-model="audiobook.book.language" label="Language" />
</div>
</div>
<div class="flex mt-2 -mx-1">
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="audiobook.book.isbn" label="ISBN" />
</div>
<div class="w-1/3 px-1">
<ui-text-input-with-label v-model="audiobook.book.asin" label="ASIN" />
</div>
</div>
</div>
</div>
@ -223,7 +243,7 @@ export default {
return arr1.join(',') !== arr2.join(',')
},
compareAudiobooks(newAb, origAb) {
const bookKeysToCheck = ['title', 'subtitle', 'narrator', 'author', 'publishYear', 'series', 'volumeNumber', 'description']
const bookKeysToCheck = ['title', 'subtitle', 'narrator', 'author', 'publishYear', 'series', 'volumeNumber', 'description', 'language', 'publisher', 'isbn', 'asin']
var newBook = newAb.book
var origBook = origAb.book
var diffObj = {}

View File

@ -187,7 +187,8 @@ export const mutations = {
genres: [],
tags: [],
series: [],
narrators: []
narrators: [],
languages: []
}
*/
@ -218,5 +219,8 @@ export const mutations = {
if (genre && !state.filterData.genres.includes(genre)) state.filterData.genres.push(genre)
})
}
if (audiobook.book.language && !state.filterData.languages.includes(audiobook.book.language)) {
state.filterData.languages.push(audiobook.book.language)
}
}
}

View File

@ -18,6 +18,8 @@ class AudioFileMetadata {
this.tagEncoder = null
this.tagEncodedBy = null
this.tagIsbn = null
this.tagLanguage = null
this.tagASIN = null
if (metadata) {
this.construct(metadata)
@ -54,6 +56,8 @@ class AudioFileMetadata {
this.tagEncoder = metadata.tagEncoder || null
this.tagEncodedBy = metadata.tagEncodedBy || null
this.tagIsbn = metadata.tagIsbn || null
this.tagLanguage = metadata.tagLanguage || null
this.tagASIN = metadata.tagASIN || null
}
// Data parsed in prober.js
@ -76,6 +80,8 @@ class AudioFileMetadata {
this.tagEncoder = payload.file_tag_encoder || null
this.tagEncodedBy = payload.file_tag_encodedby || null
this.tagIsbn = payload.file_tag_isbn || null
this.tagLanguage = payload.file_tag_language || null
this.tagASIN = payload.file_tag_asin || null
}
updateData(payload) {
@ -97,7 +103,9 @@ class AudioFileMetadata {
tagDescription: payload.file_tag_description || null,
tagEncoder: payload.file_tag_encoder || null,
tagEncodedBy: payload.file_tag_encodedby || null,
tagIsbn: payload.file_tag_isbn || nulll
tagIsbn: payload.file_tag_isbn || null,
tagLanguage: payload.file_tag_language || null,
tagASIN: payload.file_tag_asin || null
}
var hasUpdates = false

View File

@ -18,7 +18,8 @@ class Book {
this.publisher = null
this.description = null
this.isbn = null
this.langauge = null
this.asin = null
this.language = null
this.cover = null
this.coverFullPath = null
this.genres = []
@ -43,7 +44,9 @@ class Book {
get _authorsList() { return this._author.split(', ') }
get _narratorsList() { return this._narrator.split(', ') }
get _genres() { return this.genres || [] }
get _isbn() { return this.isbn || '' }
get _language() { return this.language || '' }
get _isbn() { return this.isbn || '' }
get _asin() { return this.asin || '' }
get shouldSearchForCover() {
if (this.cover) return false
@ -67,6 +70,7 @@ class Book {
this.publisher = book.publisher
this.description = book.description
this.isbn = book.isbn || null
this.asin = book.asin || null
this.language = book.language || null
this.cover = book.cover
this.coverFullPath = book.coverFullPath || null
@ -98,6 +102,7 @@ class Book {
publisher: this.publisher,
description: this.description,
isbn: this.isbn,
asin: this.asin,
language: this.language,
cover: this.cover,
coverFullPath: this.coverFullPath,
@ -156,6 +161,7 @@ class Book {
this.publishYear = data.publishYear || null
this.description = data.description || null
this.isbn = data.isbn || null
this.asin = data.asin || null
this.language = data.language || null
this.cover = data.cover || null
this.coverFullPath = data.coverFullPath || null
@ -283,7 +289,9 @@ class Book {
// ISBN match has to be exact to prevent isbn matches to flood results. Remove dashes since isbn might have those
var isbnMatch = this._isbn.toLowerCase().replace(/-/g, '') === search.replace(/-/g, '')
var bookMatchKey = titleMatch ? 'title' : subtitleMatch ? 'subtitle' : authorsMatched.length ? 'authorFL' : seriesMatch ? 'series' : isbnMatch ? 'isbn' : false
var asinMatch = this._asin.toLowerCase() === search
var bookMatchKey = titleMatch ? 'title' : subtitleMatch ? 'subtitle' : authorsMatched.length ? 'authorFL' : seriesMatch ? 'series' : isbnMatch ? 'isbn' : asinMatch ? 'asin' : false
var bookMatchText = bookMatchKey ? this[bookMatchKey] : ''
return {
@ -352,6 +360,14 @@ class Book {
{
tag: 'tagIsbn',
key: 'isbn'
},
{
tag: 'tagLanguage',
key: 'language'
},
{
tag: 'tagASIN',
key: 'asin'
}
]

View File

@ -127,8 +127,6 @@ class AudioFileScanner {
discsFromMeta.sort((a, b) => a - b)
tracksFromFilename.sort((a, b) => a - b)
tracksFromMeta.sort((a, b) => a - b)
console.log('AB DISCS', audiobook.title, discsFromFilename, discsFromMeta)
console.log('AB TRACKS', audiobook.title, tracksFromFilename, tracksFromMeta)
var discKey = null
if (discsFromMeta.length === audioFiles.length && this.isSequential(discsFromMeta)) {

View File

@ -11,7 +11,7 @@ module.exports = {
getFiltered(audiobooks, filterBy, user) {
var filtered = audiobooks
var searchGroups = ['genres', 'tags', 'series', 'authors', 'progress', 'narrators']
var searchGroups = ['genres', 'tags', 'series', 'authors', 'progress', 'narrators', 'languages']
var group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
if (group) {
var filterVal = filterBy.replace(`${group}.`, '')
@ -33,6 +33,8 @@ module.exports = {
if (filter === 'In Progress' && (userAudiobook && !userAudiobook.isRead && userAudiobook.progress > 0)) return true
return false
})
} else if (group === 'languages') {
filtered = filtered.filter(ab => ab.book && ab.book.language === filter)
}
} else if (filterBy === 'issues') {
filtered = filtered.filter(ab => {
@ -49,7 +51,8 @@ module.exports = {
genres: [],
tags: [],
series: [],
narrators: []
narrators: [],
languages: []
}
audiobooks.forEach((ab) => {
if (ab.book._authorsList.length) {
@ -73,12 +76,14 @@ module.exports = {
if (narrator && !data.narrators.includes(narrator)) data.narrators.push(narrator)
})
}
if (ab.book._language && !data.languages.includes(ab.book._language)) data.languages.push(ab.book._language)
})
data.authors = naturalSort(data.authors).asc()
data.genres = naturalSort(data.genres).asc()
data.tags = naturalSort(data.tags).asc()
data.series = naturalSort(data.series).asc()
data.narrators = naturalSort(data.narrators).asc()
data.languages = naturalSort(data.languages).asc()
return data
},

View File

@ -165,6 +165,8 @@ function parseTags(format, verbose) {
file_tag_series: tryGrabTag(format, 'series'),
file_tag_seriespart: tryGrabTag(format, 'series-part'),
file_tag_isbn: tryGrabTag(format, 'isbn'),
file_tag_language: tryGrabTab(format, 'language', 'lang'),
file_tag_asin: tryGrabTag(format, 'asin'),
// Not sure if these are actually used yet or not
file_tag_creation_time: tryGrabTag(format, 'creation_time'),