mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-08-09 13:28:43 +02:00
Add:Lazy bookshelf
This commit is contained in:
@@ -1,14 +1,8 @@
|
||||
import { sort } from '@/assets/fastSort'
|
||||
import { decode } from '@/plugins/init.client'
|
||||
|
||||
const STANDARD_GENRES = ['adventure', 'autobiography', 'biography', 'childrens', 'comedy', 'crime', 'dystopian', 'fantasy', 'fiction', 'health', 'history', 'horror', 'mystery', 'new_adult', 'nonfiction', 'philosophy', 'politics', 'religion', 'romance', 'sci-fi', 'self-help', 'short_story', 'technology', 'thriller', 'true_crime', 'western', 'young_adult']
|
||||
|
||||
export const state = () => ({
|
||||
audiobooks: [],
|
||||
listeners: [],
|
||||
genres: [...STANDARD_GENRES],
|
||||
tags: [],
|
||||
series: [],
|
||||
loadedLibraryId: 'main',
|
||||
lastLoad: 0,
|
||||
isLoading: false
|
||||
@@ -18,97 +12,6 @@ export const getters = {
|
||||
getAudiobook: state => id => {
|
||||
return state.audiobooks.find(ab => ab.id === id)
|
||||
},
|
||||
getFiltered: (state, getters, rootState, rootGetters) => () => {
|
||||
var filtered = state.audiobooks
|
||||
var settings = rootState.user.settings || {}
|
||||
var filterBy = settings.mobileFilterBy || ''
|
||||
|
||||
var searchGroups = ['genres', 'tags', 'series', 'authors', 'progress']
|
||||
var group = searchGroups.find(_group => filterBy.startsWith(_group + '.'))
|
||||
if (group) {
|
||||
var filter = decode(filterBy.replace(`${group}.`, ''))
|
||||
if (group === 'genres') filtered = filtered.filter(ab => ab.book && ab.book.genres.includes(filter))
|
||||
else if (group === 'tags') filtered = filtered.filter(ab => ab.tags.includes(filter))
|
||||
else if (group === 'series') {
|
||||
if (filter === 'No Series') filtered = filtered.filter(ab => ab.book && !ab.book.series)
|
||||
else filtered = filtered.filter(ab => ab.book && ab.book.series === filter)
|
||||
}
|
||||
// else if (group === 'series') filtered = filtered.filter(ab => ab.book && ab.book.series === filter)
|
||||
else if (group === 'authors') filtered = filtered.filter(ab => ab.book && ab.book.author === filter)
|
||||
else if (group === 'progress') {
|
||||
filtered = filtered.filter(ab => {
|
||||
var userAudiobook = rootGetters['user/getUserAudiobookData'](ab.id)
|
||||
var isRead = userAudiobook && userAudiobook.isRead
|
||||
if (filter === 'Read' && isRead) return true
|
||||
if (filter === 'Unread' && !isRead) return true
|
||||
if (filter === 'In Progress' && (userAudiobook && !userAudiobook.isRead && userAudiobook.progress > 0)) return true
|
||||
return false
|
||||
})
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
},
|
||||
getFilteredAndSorted: (state, getters, rootState, rootGetters) => () => {
|
||||
var settings = rootState.user.settings
|
||||
var direction = settings.mobileOrderDesc ? 'desc' : 'asc'
|
||||
|
||||
var filtered = getters.getFiltered()
|
||||
|
||||
if (settings.mobileOrderBy === 'recent') {
|
||||
return sort(filtered)[direction]((ab) => {
|
||||
var abprogress = rootGetters['user/getUserAudiobookData'](ab.id)
|
||||
if (!abprogress) return 0
|
||||
return abprogress.lastUpdate
|
||||
})
|
||||
} else {
|
||||
var orderByNumber = settings.mobileOrderBy === 'book.volumeNumber'
|
||||
return sort(filtered)[direction]((ab) => {
|
||||
// Supports dot notation strings i.e. "book.title"
|
||||
var value = settings.mobileOrderBy.split('.').reduce((a, b) => a[b], ab)
|
||||
if (orderByNumber && !isNaN(value)) return Number(value)
|
||||
return value
|
||||
})
|
||||
}
|
||||
},
|
||||
getSeriesGroups: (state, getters, rootState) => () => {
|
||||
var series = {}
|
||||
state.audiobooks.forEach((audiobook) => {
|
||||
if (audiobook.book && audiobook.book.series) {
|
||||
if (series[audiobook.book.series]) {
|
||||
var bookLastUpdate = audiobook.book.lastUpdate
|
||||
if (bookLastUpdate > series[audiobook.book.series].lastUpdate) series[audiobook.book.series].lastUpdate = bookLastUpdate
|
||||
series[audiobook.book.series].books.push(audiobook)
|
||||
} else {
|
||||
series[audiobook.book.series] = {
|
||||
type: 'series',
|
||||
name: audiobook.book.series || '',
|
||||
books: [audiobook],
|
||||
lastUpdate: audiobook.book.lastUpdate
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
var seriesArray = Object.values(series).map((_series) => {
|
||||
_series.books = sort(_series.books)['asc']((ab) => {
|
||||
return ab.book && ab.book.volumeNumber && !isNaN(ab.book.volumeNumber) ? Number(ab.book.volumeNumber) : null
|
||||
})
|
||||
return _series
|
||||
})
|
||||
if (state.keywordFilter) {
|
||||
const keywordFilter = state.keywordFilter.toLowerCase()
|
||||
return seriesArray.filter((_series) => _series.name.toLowerCase().includes(keywordFilter))
|
||||
}
|
||||
return seriesArray
|
||||
},
|
||||
getUniqueAuthors: (state) => {
|
||||
var _authors = state.audiobooks.filter(ab => !!(ab.book && ab.book.author)).map(ab => ab.book.author)
|
||||
return [...new Set(_authors)]
|
||||
},
|
||||
getGenresUsed: (state) => {
|
||||
var _genres = []
|
||||
state.audiobooks.filter(ab => !!(ab.book && ab.book.genres)).forEach(ab => _genres = _genres.concat(ab.book.genres))
|
||||
return [...new Set(_genres)].sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
||||
},
|
||||
getBookCoverSrc: (state, getters, rootState, rootGetters) => (bookItem, placeholder = '/book_placeholder.jpg') => {
|
||||
var book = bookItem.book
|
||||
if (!book || !book.cover || book.cover === placeholder) return placeholder
|
||||
@@ -141,43 +44,6 @@ export const getters = {
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
load({ state, commit, dispatch, rootState }) {
|
||||
if (!rootState.user || !rootState.user.user) {
|
||||
console.error('audiobooks/load - User not set')
|
||||
return false
|
||||
}
|
||||
|
||||
var currentLibraryId = rootState.libraries.currentLibraryId
|
||||
|
||||
if (currentLibraryId === state.loadedLibraryId) {
|
||||
// Don't load again if already loaded in the last 5 minutes
|
||||
var lastLoadDiff = Date.now() - state.lastLoad
|
||||
if (lastLoadDiff < 5 * 60 * 1000) {
|
||||
// Already up to date
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
commit('reset')
|
||||
commit('setLoading', true)
|
||||
}
|
||||
commit('setLoadedLibrary', currentLibraryId)
|
||||
|
||||
this.$axios
|
||||
.$get(`/api/library/${currentLibraryId}/audiobooks`)
|
||||
.then((data) => {
|
||||
commit('set', data)
|
||||
commit('setLastLoad')
|
||||
commit('setLoading', false)
|
||||
|
||||
dispatch('downloads/linkOrphanDownloads', data, { root: true })
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Failed', error)
|
||||
commit('set', [])
|
||||
commit('setLoading', false)
|
||||
})
|
||||
return true
|
||||
},
|
||||
useDownloaded({ commit, rootGetters }) {
|
||||
commit('set', rootGetters['downloads/getAudiobooks'])
|
||||
}
|
||||
@@ -199,46 +65,6 @@ export const mutations = {
|
||||
state.tags = []
|
||||
state.series = []
|
||||
},
|
||||
set(state, audiobooks) {
|
||||
// GENRES
|
||||
var genres = [...state.genres]
|
||||
audiobooks.forEach((ab) => {
|
||||
if (!ab.book) return
|
||||
genres = genres.concat(ab.book.genres)
|
||||
})
|
||||
state.genres = [...new Set(genres)] // Remove Duplicates
|
||||
state.genres.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
||||
|
||||
// TAGS
|
||||
var tags = []
|
||||
audiobooks.forEach((ab) => {
|
||||
tags = tags.concat(ab.tags)
|
||||
})
|
||||
state.tags = [...new Set(tags)] // Remove Duplicates
|
||||
state.tags.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
||||
|
||||
// SERIES
|
||||
var series = []
|
||||
audiobooks.forEach((ab) => {
|
||||
if (!ab.book || !ab.book.series || series.includes(ab.book.series)) return
|
||||
series.push(ab.book.series)
|
||||
})
|
||||
state.series = series
|
||||
state.series.sort((a, b) => a.toLowerCase() < b.toLowerCase() ? -1 : 1)
|
||||
|
||||
audiobooks.forEach((ab) => {
|
||||
var indexOf = state.audiobooks.findIndex(_ab => _ab.id === ab.id)
|
||||
if (indexOf >= 0) {
|
||||
state.audiobooks.splice(indexOf, 1, ab)
|
||||
} else {
|
||||
state.audiobooks.push(ab)
|
||||
}
|
||||
})
|
||||
// state.audiobooks = audiobooks
|
||||
state.listeners.forEach((listener) => {
|
||||
listener.meth()
|
||||
})
|
||||
},
|
||||
addUpdate(state, audiobook) {
|
||||
var index = state.audiobooks.findIndex(a => a.id === audiobook.id)
|
||||
var origAudiobook = null
|
||||
|
||||
+18
-6
@@ -20,7 +20,7 @@ export const getters = {
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
async loadFromStorage({ commit }) {
|
||||
async loadFromStorage({ commit, state }) {
|
||||
var downloads = await this.$sqlStore.getAllDownloads()
|
||||
|
||||
downloads.forEach(ab => {
|
||||
@@ -31,20 +31,32 @@ export const actions = {
|
||||
ab.isPreparing = false
|
||||
commit('setDownload', ab)
|
||||
})
|
||||
return state.downloads
|
||||
},
|
||||
linkOrphanDownloads({ state, commit }, audiobooks) {
|
||||
async linkOrphanDownloads({ state, commit, rootState }) {
|
||||
if (!state.mediaScanResults || !state.mediaScanResults.folders) {
|
||||
return
|
||||
}
|
||||
console.log('Link orphan downloads', JSON.stringify(state.mediaScanResults.folders))
|
||||
state.mediaScanResults.folders.forEach((folder) => {
|
||||
// state.mediaScanResults.folders.forEach((folder) => {
|
||||
for (let i = 0; i < state.mediaScanResults.folders.length; i++) {
|
||||
var folder = state.mediaScanResults.folders[i]
|
||||
if (!folder.files || !folder.files.length) return
|
||||
|
||||
console.log('Link orphan downloads check folder', folder.name)
|
||||
|
||||
var download = state.downloads.find(dl => dl.folderName === folder.name)
|
||||
if (!download) {
|
||||
var matchingAb = audiobooks.find(ab => ab.book.title === folder.name)
|
||||
// var matchingAb = audiobooks.find(ab => ab.book.title === folder.name)
|
||||
var results = await this.$axios.$get(`/libraries/${rootState.libraries.currentLibraryId}/search?q=${folder.name}`)
|
||||
var matchingAb = null
|
||||
if (results && results.audiobooks) {
|
||||
console.log('has ab results', JSON.stringify(results.audiobooks))
|
||||
matchingAb = results.audiobooks.find(ab => ab.audiobook.book.title === folder.name)
|
||||
if (matchingAb) console.log('Found matching ab for ' + folder.name, matchingAb)
|
||||
else console.warn('did not find mathcing ab for ' + folder.name)
|
||||
} else {
|
||||
console.error('Invalid results payload', JSON.stringify(results))
|
||||
}
|
||||
if (matchingAb) {
|
||||
// Found matching download for ab
|
||||
var audioFile = folder.files.find(f => f.isAudio)
|
||||
@@ -72,7 +84,7 @@ export const actions = {
|
||||
commit('addUpdateDownload', downloadObj)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -19,7 +19,8 @@ export const state = () => ({
|
||||
|
||||
showSideDrawer: false,
|
||||
bookshelfView: 'grid',
|
||||
isNetworkListenerInit: false
|
||||
isNetworkListenerInit: false,
|
||||
serverSettings: null
|
||||
})
|
||||
|
||||
export const getters = {
|
||||
@@ -34,7 +35,15 @@ export const getters = {
|
||||
},
|
||||
getAudiobookIdStreaming: state => {
|
||||
return state.streamAudiobook ? state.streamAudiobook.id : null
|
||||
}
|
||||
},
|
||||
getServerSetting: state => key => {
|
||||
if (!state.serverSettings) return null
|
||||
return state.serverSettings[key]
|
||||
},
|
||||
getBookCoverAspectRatio: state => {
|
||||
if (!state.serverSettings || !state.serverSettings.coverAspectRatio) return 1.6
|
||||
return state.serverSettings.coverAspectRatio === 0 ? 1.6 : 1
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
@@ -123,5 +132,8 @@ export const mutations = {
|
||||
},
|
||||
setBookshelfView(state, val) {
|
||||
state.bookshelfView = val
|
||||
},
|
||||
setServerSettings(state, val) {
|
||||
state.serverSettings = val
|
||||
}
|
||||
}
|
||||
+27
-9
@@ -5,12 +5,18 @@ export const state = () => ({
|
||||
currentLibraryId: 'main',
|
||||
showModal: false,
|
||||
folders: [],
|
||||
folderLastUpdate: 0
|
||||
folderLastUpdate: 0,
|
||||
issues: 0,
|
||||
filterData: null
|
||||
})
|
||||
|
||||
export const getters = {
|
||||
getCurrentLibrary: state => {
|
||||
return state.libraries.find(lib => lib.id === state.currentLibraryId)
|
||||
},
|
||||
getCurrentLibraryName: (state, getters) => {
|
||||
var currLib = getters.getCurrentLibrary
|
||||
return currLib ? currLib.name : null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,16 +27,22 @@ export const actions = {
|
||||
return false
|
||||
}
|
||||
|
||||
var library = state.libraries.find(lib => lib.id === libraryId)
|
||||
if (library) {
|
||||
commit('setCurrentLibrary', libraryId)
|
||||
return library
|
||||
}
|
||||
// var library = state.libraries.find(lib => lib.id === libraryId)
|
||||
// if (library) {
|
||||
// commit('setCurrentLibrary', libraryId)
|
||||
// return library
|
||||
// }
|
||||
|
||||
return this.$axios
|
||||
.$get(`/api/libraries/${libraryId}`)
|
||||
.$get(`/api/libraries/${libraryId}?include=filterdata`)
|
||||
.then((data) => {
|
||||
commit('addUpdate', data)
|
||||
var library = data.library
|
||||
var filterData = data.filterdata
|
||||
var issues = data.issues || 0
|
||||
|
||||
commit('addUpdate', library)
|
||||
commit('setLibraryIssues', issues)
|
||||
commit('setLibraryFilterData', filterData)
|
||||
commit('setCurrentLibrary', libraryId)
|
||||
return data
|
||||
})
|
||||
@@ -117,5 +129,11 @@ export const mutations = {
|
||||
},
|
||||
removeListener(state, listenerId) {
|
||||
state.listeners = state.listeners.filter(l => l.id !== listenerId)
|
||||
}
|
||||
},
|
||||
setLibraryIssues(state, val) {
|
||||
state.issues = val
|
||||
},
|
||||
setLibraryFilterData(state, filterData) {
|
||||
state.filterData = filterData
|
||||
},
|
||||
}
|
||||
+7
-1
@@ -2,7 +2,7 @@ export const state = () => ({
|
||||
user: null,
|
||||
userAudiobookData: [],
|
||||
settings: {
|
||||
mobileOrderBy: 'recent',
|
||||
mobileOrderBy: 'addedAt',
|
||||
mobileOrderDesc: true,
|
||||
mobileFilterBy: 'all',
|
||||
orderBy: 'book.title',
|
||||
@@ -23,6 +23,9 @@ export const getters = {
|
||||
return state.user ? state.user.token : null
|
||||
},
|
||||
getUserAudiobookData: (state, getters) => (audiobookId) => {
|
||||
return getters.getUserAudiobook(audiobookId)
|
||||
},
|
||||
getUserAudiobook: (state, getters) => (audiobookId) => {
|
||||
return state.userAudiobookData.find(uabd => uabd.audiobookId === audiobookId)
|
||||
},
|
||||
getUserSetting: (state) => (key) => {
|
||||
@@ -135,6 +138,9 @@ export const mutations = {
|
||||
var hasChanges = false
|
||||
for (const key in settings) {
|
||||
if (state.settings[key] !== settings[key]) {
|
||||
if (key === 'mobileOrderBy' && settings[key] === 'recent') {
|
||||
settings[key] = 'addedAt'
|
||||
}
|
||||
hasChanges = true
|
||||
state.settings[key] = settings[key]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user