export const state = () => ({ user: null, settings: { orderBy: 'media.metadata.title', orderDesc: false, filterBy: 'all', playbackRate: 1, bookshelfCoverSize: 120, collapseSeries: false, collapseBookSeries: false, showSubtitles: false, useChapterTrack: false, seriesSortBy: 'name', seriesSortDesc: false, seriesFilterBy: 'all', authorSortBy: 'name', authorSortDesc: false, jumpForwardAmount: 10, jumpBackwardAmount: 10 } }) export const getters = { getIsRoot: (state) => state.user && state.user.type === 'root', getIsAdminOrUp: (state) => state.user && (state.user.type === 'admin' || state.user.type === 'root'), getToken: (state) => { return state.user?.token || null }, getUserMediaProgress: (state) => (libraryItemId, episodeId = null) => { if (!state.user.mediaProgress) return null return state.user.mediaProgress.find((li) => { if (episodeId && li.episodeId !== episodeId) return false return li.libraryItemId == libraryItemId }) }, getUserBookmarksForItem: (state) => (libraryItemId) => { if (!state.user.bookmarks) return [] return state.user.bookmarks.filter((bm) => bm.libraryItemId === libraryItemId) }, getUserSetting: (state) => (key) => { return state.settings?.[key] || null }, getUserCanUpdate: (state) => { return !!state.user?.permissions?.update }, getUserCanDelete: (state) => { return !!state.user?.permissions?.delete }, getUserCanDownload: (state) => { return !!state.user?.permissions?.download }, getUserCanUpload: (state) => { return !!state.user?.permissions?.upload }, getUserCanAccessAllLibraries: (state) => { return !!state.user?.permissions?.accessAllLibraries }, getLibrariesAccessible: (state, getters) => { if (!state.user) return [] if (getters.getUserCanAccessAllLibraries) return [] return state.user.librariesAccessible || [] }, getCanAccessLibrary: (state, getters) => (libraryId) => { if (!state.user) return false if (getters.getUserCanAccessAllLibraries) return true return getters.getLibrariesAccessible.includes(libraryId) }, getIsSeriesRemovedFromContinueListening: (state) => (seriesId) => { if (!state.user || !state.user.seriesHideFromContinueListening || !state.user.seriesHideFromContinueListening.length) return false return state.user.seriesHideFromContinueListening.includes(seriesId) }, getSizeMultiplier: (state) => { return state.settings.bookshelfCoverSize / 120 } } export const actions = { // When changing libraries make sure sort and filter is still valid checkUpdateLibrarySortFilter({ state, dispatch, commit }, mediaType) { const settingsUpdate = {} if (mediaType == 'podcast') { if (state.settings.orderBy == 'media.metadata.authorName' || state.settings.orderBy == 'media.metadata.authorNameLF') { settingsUpdate.orderBy = 'media.metadata.author' } if (state.settings.orderBy == 'media.duration') { settingsUpdate.orderBy = 'media.numTracks' } if (state.settings.orderBy == 'media.metadata.publishedYear') { settingsUpdate.orderBy = 'media.metadata.title' } const invalidFilters = ['series', 'authors', 'narrators', 'publishers', 'languages', 'progress', 'issues', 'ebooks', 'abridged'] const filterByFirstPart = (state.settings.filterBy || '').split('.').shift() if (invalidFilters.includes(filterByFirstPart)) { settingsUpdate.filterBy = 'all' } } else { if (state.settings.orderBy == 'media.metadata.author') { settingsUpdate.orderBy = 'media.metadata.authorName' } if (state.settings.orderBy == 'media.numTracks') { settingsUpdate.orderBy = 'media.duration' } } if (Object.keys(settingsUpdate).length) { dispatch('updateUserSettings', settingsUpdate) } }, updateUserSettings({ state, commit }, payload) { if (!payload) return false let hasChanges = false const existingSettings = { ...state.settings } for (const key in existingSettings) { if (payload[key] !== undefined && existingSettings[key] !== payload[key]) { hasChanges = true existingSettings[key] = payload[key] } } if (hasChanges) { commit('setSettings', existingSettings) this.$eventBus.$emit('user-settings', state.settings) } }, loadUserSettings({ state, commit }) { // Load settings from local storage try { let userSettingsFromLocal = localStorage.getItem('userSettings') if (userSettingsFromLocal) { userSettingsFromLocal = JSON.parse(userSettingsFromLocal) const userSettings = { ...state.settings } for (const key in userSettings) { if (userSettingsFromLocal[key] !== undefined) { userSettings[key] = userSettingsFromLocal[key] } } commit('setSettings', userSettings) this.$eventBus.$emit('user-settings', state.settings) } } catch (error) { console.error('Failed to load userSettings from local storage', error) } } } export const mutations = { setUser(state, user) { state.user = user if (user) { if (user.token) localStorage.setItem('token', user.token) } else { localStorage.removeItem('token') } }, setUserToken(state, token) { state.user.token = token localStorage.setItem('token', token) }, updateMediaProgress(state, { id, data }) { if (!state.user) return if (!data) { state.user.mediaProgress = state.user.mediaProgress.filter((lip) => lip.id != id) } else { var indexOf = state.user.mediaProgress.findIndex((lip) => lip.id == id) if (indexOf >= 0) { state.user.mediaProgress.splice(indexOf, 1, data) } else { state.user.mediaProgress.push(data) } } }, setSettings(state, settings) { if (!settings) return localStorage.setItem('userSettings', JSON.stringify(settings)) state.settings = settings } }