Compare commits

...

5 commits

Author SHA1 Message Date
advplyr
2592467d09 Fix: Always re-load libraries when changing users #4694
Some checks are pending
CodeQL / Analyze (push) Waiting to run
Run Component Tests / Run Component Tests (push) Waiting to run
Build and Push Docker Image / build (push) Waiting to run
Integration Test / build and test (push) Waiting to run
Run Unit Tests / Run Unit Tests (push) Waiting to run
2025-10-08 15:32:37 -05:00
advplyr
37beb7b37c Disable chapter editor chapter play button when time is invalid #4691 2025-10-08 15:03:33 -05:00
advplyr
cafd92e206 Fix item edit modal show next/prev arrows when opening from Files or Match context menu item #4718 2025-10-08 14:52:14 -05:00
advplyr
3e876e3383 Add Turkish to the language option 2025-10-08 14:24:50 -05:00
advplyr
29752798f3 Version bump v2.30.0 2025-10-08 10:34:34 -05:00
13 changed files with 37 additions and 24 deletions

View file

@ -93,10 +93,10 @@ export default {
editAuthor(author) { editAuthor(author) {
this.$store.commit('globals/showEditAuthorModal', author) this.$store.commit('globals/showEditAuthorModal', author)
}, },
editItem(libraryItem) { editItem(libraryItem, tab = 'details') {
var itemIds = this.shelf.entities.map((e) => e.id) var itemIds = this.shelf.entities.map((e) => e.id)
this.$store.commit('setBookshelfBookIds', itemIds) this.$store.commit('setBookshelfBookIds', itemIds)
this.$store.commit('showEditModal', libraryItem) this.$store.commit('showEditModalOnTab', { libraryItem, tab: tab || 'details' })
}, },
editEpisode({ libraryItem, episode }) { editEpisode({ libraryItem, episode }) {
this.$store.commit('setEpisodeTableEpisodeIds', [episode.id]) this.$store.commit('setEpisodeTableEpisodeIds', [episode.id])

View file

@ -232,11 +232,11 @@ export default {
clearFilter() { clearFilter() {
this.$store.dispatch('user/updateUserSettings', { filterBy: 'all' }) this.$store.dispatch('user/updateUserSettings', { filterBy: 'all' })
}, },
editEntity(entity) { editEntity(entity, tab = 'details') {
if (this.entityName === 'items' || this.entityName === 'series-books') { if (this.entityName === 'items' || this.entityName === 'series-books') {
const bookIds = this.entities.map((e) => e.id) const bookIds = this.entities.map((e) => e.id)
this.$store.commit('setBookshelfBookIds', bookIds) this.$store.commit('setBookshelfBookIds', bookIds)
this.$store.commit('showEditModal', entity) this.$store.commit('showEditModalOnTab', { libraryItem: entity, tab: tab || 'details' })
} else if (this.entityName === 'collections') { } else if (this.entityName === 'collections') {
this.$store.commit('globals/setEditCollection', entity) this.$store.commit('globals/setEditCollection', entity)
} else if (this.entityName === 'playlists') { } else if (this.entityName === 'playlists') {

View file

@ -788,11 +788,11 @@ export default {
}, },
showEditModalFiles() { showEditModalFiles() {
// More menu func // More menu func
this.store.commit('showEditModalOnTab', { libraryItem: this.libraryItem, tab: 'files' }) this.$emit('edit', this.libraryItem, 'files')
}, },
showEditModalMatch() { showEditModalMatch() {
// More menu func // More menu func
this.store.commit('showEditModalOnTab', { libraryItem: this.libraryItem, tab: 'match' }) this.$emit('edit', this.libraryItem, 'match')
}, },
sendToDevice(deviceName) { sendToDevice(deviceName) {
// More menu func // More menu func

View file

@ -132,10 +132,10 @@ export default {
editAuthor(author) { editAuthor(author) {
this.$store.commit('globals/showEditAuthorModal', author) this.$store.commit('globals/showEditAuthorModal', author)
}, },
editItem(libraryItem) { editItem(libraryItem, tab = 'details') {
var itemIds = this.items.map((e) => e.id) var itemIds = this.items.map((e) => e.id)
this.$store.commit('setBookshelfBookIds', itemIds) this.$store.commit('setBookshelfBookIds', itemIds)
this.$store.commit('showEditModal', libraryItem) this.$store.commit('showEditModalOnTab', { libraryItem, tab: tab || 'details' })
}, },
selectItem(payload) { selectItem(payload) {
this.$emit('selectEntity', payload) this.$emit('selectEntity', payload)

View file

@ -118,8 +118,8 @@ export default {
propsData: props, propsData: props,
parent: this, parent: this,
created() { created() {
this.$on('edit', (entity) => { this.$on('edit', (entity, tab) => {
if (_this.editEntity) _this.editEntity(entity) if (_this.editEntity) _this.editEntity(entity, tab)
}) })
this.$on('select', ({ entity, shiftKey }) => { this.$on('select', ({ entity, shiftKey }) => {
if (_this.selectEntity) _this.selectEntity(entity, shiftKey) if (_this.selectEntity) _this.selectEntity(entity, shiftKey)

View file

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.29.0", "version": "2.30.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.29.0", "version": "2.30.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",

View file

@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.29.0", "version": "2.30.0",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast client", "description": "Self-hosted audiobook and podcast client",
"main": "index.js", "main": "index.js",

View file

@ -117,10 +117,10 @@
</button> </button>
</ui-tooltip> </ui-tooltip>
<ui-tooltip :text="selectedChapterId === chapter.id && isPlayingChapter ? $strings.MessagePauseChapter : $strings.MessagePlayChapter" direction="bottom"> <ui-tooltip :text="selectedChapterId === chapter.id && isPlayingChapter ? $strings.MessagePauseChapter : $strings.MessagePlayChapter" direction="bottom">
<button class="w-7 h-7 rounded-full flex items-center justify-center text-gray-300 hover:text-white transform hover:scale-110 duration-150" @click="playChapter(chapter)"> <button :disabled="!getAudioTrackForTime(chapter.start)" class="w-7 h-7 rounded-full flex items-center justify-center text-gray-300 hover:text-white transform hover:scale-110 duration-150 disabled:opacity-50 disabled:cursor-not-allowed" @click="playChapter(chapter)">
<widgets-loading-spinner v-if="selectedChapterId === chapter.id && isLoadingChapter" /> <widgets-loading-spinner v-if="selectedChapterId === chapter.id && isLoadingChapter" />
<span v-else-if="selectedChapterId === chapter.id && isPlayingChapter" class="material-symbols text-base">pause</span> <span v-else-if="selectedChapterId === chapter.id && isPlayingChapter" class="material-symbols text-base">pause</span>
<span v-else class="material-symbols text-base">play_arrow</span> <span v-else class="material-symbols text-xl">play_arrow</span>
</button> </button>
</ui-tooltip> </ui-tooltip>
<ui-tooltip v-if="selectedChapterId === chapter.id && (isPlayingChapter || isLoadingChapter)" :text="$strings.TooltipAdjustChapterStart" direction="bottom"> <ui-tooltip v-if="selectedChapterId === chapter.id && (isPlayingChapter || isLoadingChapter)" :text="$strings.TooltipAdjustChapterStart" direction="bottom">
@ -594,6 +594,14 @@ export default {
this.hasChanges = hasChanges this.hasChanges = hasChanges
}, },
getAudioTrackForTime(time) {
if (typeof time !== 'number') {
return null
}
return this.tracks.find((at) => {
return time >= at.startOffset && time < at.startOffset + at.duration
})
},
playChapter(chapter) { playChapter(chapter) {
console.log('Play Chapter', chapter.id) console.log('Play Chapter', chapter.id)
if (this.selectedChapterId === chapter.id) { if (this.selectedChapterId === chapter.id) {
@ -608,9 +616,12 @@ export default {
this.destroyAudioEl() this.destroyAudioEl()
} }
const audioTrack = this.tracks.find((at) => { const audioTrack = this.getAudioTrackForTime(chapter.start)
return chapter.start >= at.startOffset && chapter.start < at.startOffset + at.duration if (!audioTrack) {
}) console.error('No audio track found for chapter', chapter)
return
}
this.selectedChapter = chapter this.selectedChapter = chapter
this.isLoadingChapter = true this.isLoadingChapter = true

View file

@ -189,6 +189,7 @@ export default {
require('@/plugins/chromecast.js').default(this) require('@/plugins/chromecast.js').default(this)
} }
this.$store.commit('libraries/setLastLoad', 0) // Ensure libraries get loaded again when switching users
this.$store.commit('libraries/setCurrentLibrary', { id: userDefaultLibraryId }) this.$store.commit('libraries/setCurrentLibrary', { id: userDefaultLibraryId })
this.$store.commit('user/setUser', user) this.$store.commit('user/setUser', user)
// Access token only returned from login, not authorize // Access token only returned from login, not authorize

View file

@ -29,6 +29,7 @@ const languageCodeMap = {
ru: { label: 'Русский', dateFnsLocale: 'ru' }, ru: { label: 'Русский', dateFnsLocale: 'ru' },
sl: { label: 'Slovenščina', dateFnsLocale: 'sl' }, sl: { label: 'Slovenščina', dateFnsLocale: 'sl' },
sv: { label: 'Svenska', dateFnsLocale: 'sv' }, sv: { label: 'Svenska', dateFnsLocale: 'sv' },
tr: { label: 'Türkçe', dateFnsLocale: 'tr' },
uk: { label: 'Українська', dateFnsLocale: 'uk' }, uk: { label: 'Українська', dateFnsLocale: 'uk' },
'vi-vn': { label: 'Tiếng Việt', dateFnsLocale: 'vi' }, 'vi-vn': { label: 'Tiếng Việt', dateFnsLocale: 'vi' },
'zh-cn': { label: '简体中文 (Simplified Chinese)', dateFnsLocale: 'zhCN' }, 'zh-cn': { label: '简体中文 (Simplified Chinese)', dateFnsLocale: 'zhCN' },

View file

@ -159,7 +159,7 @@ export const actions = {
.$get(`/api/libraries`) .$get(`/api/libraries`)
.then((data) => { .then((data) => {
commit('set', data.libraries) commit('set', data.libraries)
commit('setLastLoad') commit('setLastLoad', new Date())
}) })
.catch((error) => { .catch((error) => {
console.error('Failed', error) console.error('Failed', error)
@ -176,8 +176,8 @@ export const mutations = {
setFoldersLastUpdate(state) { setFoldersLastUpdate(state) {
state.folderLastUpdate = Date.now() state.folderLastUpdate = Date.now()
}, },
setLastLoad(state) { setLastLoad(state, date) {
state.lastLoad = Date.now() state.lastLoad = date
}, },
setLibraryIssues(state, val) { setLibraryIssues(state, val) {
state.issues = val state.issues = val

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.29.0", "version": "2.30.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.29.0", "version": "2.30.0",
"license": "GPL-3.0", "license": "GPL-3.0",
"dependencies": { "dependencies": {
"axios": "^0.27.2", "axios": "^0.27.2",

View file

@ -1,6 +1,6 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.29.0", "version": "2.30.0",
"buildNumber": 1, "buildNumber": 1,
"description": "Self-hosted audiobook and podcast server", "description": "Self-hosted audiobook and podcast server",
"main": "index.js", "main": "index.js",