Merge branch 'master' into sqlite

This commit is contained in:
advplyr 2023-03-19 09:21:00 -05:00
commit 2131a65299
15 changed files with 75 additions and 12 deletions

View File

@ -6,9 +6,14 @@
</div> </div>
</template> </template>
<div ref="wrapper" id="podcast-wrapper" class="p-4 w-full text-sm py-2 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden"> <div ref="wrapper" id="podcast-wrapper" class="p-4 w-full text-sm py-2 rounded-lg bg-bg shadow-lg border border-black-300 relative overflow-hidden">
<div v-if="episodes.length" class="w-full py-3 mx-auto flex">
<form @submit.prevent="submit" class="flex flex-grow">
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="flex-grow mr-2 text-sm md:text-base" />
</form>
</div>
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto"> <div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
<div <div
v-for="(episode, index) in episodes" v-for="(episode, index) in episodesList"
:key="index" :key="index"
class="relative" class="relative"
:class="itemEpisodeMap[episode.enclosure.url] ? 'bg-primary bg-opacity-40' : selectedEpisodes[String(index)] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'" :class="itemEpisodeMap[episode.enclosure.url] ? 'bg-primary bg-opacity-40' : selectedEpisodes[String(index)] ? 'cursor-pointer bg-success bg-opacity-10' : index % 2 == 0 ? 'cursor-pointer bg-primary bg-opacity-25 hover:bg-opacity-40' : 'cursor-pointer bg-primary bg-opacity-5 hover:bg-opacity-25'"
@ -59,7 +64,10 @@ export default {
return { return {
processing: false, processing: false,
selectedEpisodes: {}, selectedEpisodes: {},
selectAll: false selectAll: false,
search: null,
searchTimeout: null,
searchText: null,
} }
}, },
watch: { watch: {
@ -103,9 +111,28 @@ export default {
if (item.enclosure) map[item.enclosure.url] = true if (item.enclosure) map[item.enclosure.url] = true
}) })
return map return map
},
episodesList() {
return this.episodes.filter((episode) => {
if (!this.searchText) return true
return (
(episode.title && episode.title.toLowerCase().includes(this.searchText)) ||
(episode.subtitle && episode.subtitle.toLowerCase().includes(this.searchText))
)
})
} }
}, },
methods: { methods: {
inputUpdate() {
clearTimeout(this.searchTimeout)
this.searchTimeout = setTimeout(() => {
if (!this.search || !this.search.trim()) {
this.searchText = ''
return
}
this.searchText = this.search.toLowerCase().trim()
}, 500)
},
toggleSelectAll(val) { toggleSelectAll(val) {
for (let i = 0; i < this.episodes.length; i++) { for (let i = 0; i < this.episodes.length; i++) {
const episode = this.episodes[i] const episode = this.episodes[i]

View File

@ -19,7 +19,12 @@
</template> </template>
</div> </div>
<p v-if="!episodes.length" class="py-4 text-center text-lg">{{ $strings.MessageNoEpisodes }}</p> <p v-if="!episodes.length" class="py-4 text-center text-lg">{{ $strings.MessageNoEpisodes }}</p>
<template v-for="episode in episodesSorted"> <div v-if="episodes.length" class="w-full py-3 mx-auto flex">
<form @submit.prevent="submit" class="flex flex-grow">
<ui-text-input v-model="search" @input="inputUpdate" type="search" :placeholder="$strings.PlaceholderSearchEpisode" class="flex-grow mr-2 text-sm md:text-base" />
</form>
</div>
<template v-for="episode in episodesList">
<tables-podcast-episode-table-row ref="episodeRow" :key="episode.id" :episode="episode" :library-item-id="libraryItem.id" :selection-mode="isSelectionMode" class="item" @play="playEpisode" @remove="removeEpisode" @edit="editEpisode" @view="viewEpisode" @selected="episodeSelected" @addToQueue="addEpisodeToQueue" @addToPlaylist="addToPlaylist" /> <tables-podcast-episode-table-row ref="episodeRow" :key="episode.id" :episode="episode" :library-item-id="libraryItem.id" :selection-mode="isSelectionMode" class="item" @play="playEpisode" @remove="removeEpisode" @edit="editEpisode" @view="viewEpisode" @selected="episodeSelected" @addToQueue="addEpisodeToQueue" @addToPlaylist="addToPlaylist" />
</template> </template>
@ -46,7 +51,10 @@ export default {
selectedEpisodes: [], selectedEpisodes: [],
episodesToRemove: [], episodesToRemove: [],
processing: false, processing: false,
quickMatchingEpisodes: false quickMatchingEpisodes: false,
search: null,
searchTimeout: null,
searchText: null,
} }
}, },
watch: { watch: {
@ -137,6 +145,15 @@ export default {
return String(a[this.sortKey]).localeCompare(String(b[this.sortKey]), undefined, { numeric: true, sensitivity: 'base' }) return String(a[this.sortKey]).localeCompare(String(b[this.sortKey]), undefined, { numeric: true, sensitivity: 'base' })
}) })
}, },
episodesList() {
return this.episodesSorted.filter((episode) => {
if (!this.searchText) return true
return (
(episode.title && episode.title.toLowerCase().includes(this.searchText)) ||
(episode.subtitle && episode.subtitle.toLowerCase().includes(this.searchText))
)
})
},
selectedIsFinished() { selectedIsFinished() {
// Find an item that is not finished, if none then all items finished // Find an item that is not finished, if none then all items finished
return !this.selectedEpisodes.find((episode) => { return !this.selectedEpisodes.find((episode) => {
@ -152,6 +169,16 @@ export default {
} }
}, },
methods: { methods: {
inputUpdate() {
clearTimeout(this.searchTimeout)
this.searchTimeout = setTimeout(() => {
if (!this.search || !this.search.trim()) {
this.searchText = ''
return
}
this.searchText = this.search.toLowerCase().trim()
}, 500)
},
contextMenuAction(action) { contextMenuAction(action) {
if (action === 'quick-match-episodes') { if (action === 'quick-match-episodes') {
if (this.quickMatchingEpisodes) return if (this.quickMatchingEpisodes) return

View File

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.2.16", "version": "2.2.17",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.2.16", "version": "2.2.17",
"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.2.16", "version": "2.2.17",
"description": "Self-hosted audiobook and podcast client", "description": "Self-hosted audiobook and podcast client",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Neuer Ordnerpfad", "PlaceholderNewFolderPath": "Neuer Ordnerpfad",
"PlaceholderNewPlaylist": "Neuer Wiedergabelistenname", "PlaceholderNewPlaylist": "Neuer Wiedergabelistenname",
"PlaceholderSearch": "Suche...", "PlaceholderSearch": "Suche...",
"PlaceholderSearchEpisode": "Search episode...",
"ToastAccountUpdateFailed": "Aktualisierung des Kontos fehlgeschlagen", "ToastAccountUpdateFailed": "Aktualisierung des Kontos fehlgeschlagen",
"ToastAccountUpdateSuccess": "Konto aktualisiert", "ToastAccountUpdateSuccess": "Konto aktualisiert",
"ToastAuthorImageRemoveFailed": "Bild konnte nicht entfernt werden", "ToastAuthorImageRemoveFailed": "Bild konnte nicht entfernt werden",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "New folder path", "PlaceholderNewFolderPath": "New folder path",
"PlaceholderNewPlaylist": "New playlist name", "PlaceholderNewPlaylist": "New playlist name",
"PlaceholderSearch": "Search..", "PlaceholderSearch": "Search..",
"PlaceholderSearchEpisode": "Search episode..",
"ToastAccountUpdateFailed": "Failed to update account", "ToastAccountUpdateFailed": "Failed to update account",
"ToastAccountUpdateSuccess": "Account updated", "ToastAccountUpdateSuccess": "Account updated",
"ToastAuthorImageRemoveFailed": "Failed to remove image", "ToastAuthorImageRemoveFailed": "Failed to remove image",
@ -635,4 +636,4 @@
"ToastSocketFailedToConnect": "Socket failed to connect", "ToastSocketFailedToConnect": "Socket failed to connect",
"ToastUserDeleteFailed": "Failed to delete user", "ToastUserDeleteFailed": "Failed to delete user",
"ToastUserDeleteSuccess": "User deleted" "ToastUserDeleteSuccess": "User deleted"
} }

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Nueva ruta de carpeta", "PlaceholderNewFolderPath": "Nueva ruta de carpeta",
"PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción", "PlaceholderNewPlaylist": "Nuevo nombre de la lista de reproducción",
"PlaceholderSearch": "Buscando..", "PlaceholderSearch": "Buscando..",
"PlaceholderSearchEpisode": "Search episode..",
"ToastAccountUpdateFailed": "Error al actualizar cuenta", "ToastAccountUpdateFailed": "Error al actualizar cuenta",
"ToastAccountUpdateSuccess": "Cuenta actualizada", "ToastAccountUpdateSuccess": "Cuenta actualizada",
"ToastAuthorImageRemoveFailed": "Error al eliminar la imagen", "ToastAuthorImageRemoveFailed": "Error al eliminar la imagen",

View File

@ -565,7 +565,8 @@
"PlaceholderNewCollection": "Nom de la nouvelle collection", "PlaceholderNewCollection": "Nom de la nouvelle collection",
"PlaceholderNewFolderPath": "Nouveau chemin de dossier", "PlaceholderNewFolderPath": "Nouveau chemin de dossier",
"PlaceholderNewPlaylist": "Nouveau nom de liste de lecture", "PlaceholderNewPlaylist": "Nouveau nom de liste de lecture",
"PlaceholderSearch": "Recherche…", "PlaceholderSearch": "Recherche...",
"PlaceholderSearchEpisode": "Search episode...",
"ToastAccountUpdateFailed": "Échec de la mise à jour du compte", "ToastAccountUpdateFailed": "Échec de la mise à jour du compte",
"ToastAccountUpdateSuccess": "Compte mis à jour", "ToastAccountUpdateSuccess": "Compte mis à jour",
"ToastAuthorImageRemoveFailed": "Échec de la suppression de limage", "ToastAuthorImageRemoveFailed": "Échec de la suppression de limage",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Nova folder putanja", "PlaceholderNewFolderPath": "Nova folder putanja",
"PlaceholderNewPlaylist": "New playlist name", "PlaceholderNewPlaylist": "New playlist name",
"PlaceholderSearch": "Traži...", "PlaceholderSearch": "Traži...",
"PlaceholderSearchEpisode": "Search episode...",
"ToastAccountUpdateFailed": "Neuspješno aktualiziranje korisničkog računa", "ToastAccountUpdateFailed": "Neuspješno aktualiziranje korisničkog računa",
"ToastAccountUpdateSuccess": "Korisnički račun aktualiziran", "ToastAccountUpdateSuccess": "Korisnički račun aktualiziran",
"ToastAuthorImageRemoveFailed": "Neuspješno uklanjanje slike", "ToastAuthorImageRemoveFailed": "Neuspješno uklanjanje slike",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Nuovo percorso Cartella", "PlaceholderNewFolderPath": "Nuovo percorso Cartella",
"PlaceholderNewPlaylist": "Nome nuova playlist", "PlaceholderNewPlaylist": "Nome nuova playlist",
"PlaceholderSearch": "Cerca..", "PlaceholderSearch": "Cerca..",
"PlaceholderSearchEpisode": "Search episode..",
"ToastAccountUpdateFailed": "Aggiornamento Account Fallito", "ToastAccountUpdateFailed": "Aggiornamento Account Fallito",
"ToastAccountUpdateSuccess": "Account Aggiornato", "ToastAccountUpdateSuccess": "Account Aggiornato",
"ToastAuthorImageRemoveFailed": "Rimozione immagine autore Fallita", "ToastAuthorImageRemoveFailed": "Rimozione immagine autore Fallita",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Nowa ścieżka folderu", "PlaceholderNewFolderPath": "Nowa ścieżka folderu",
"PlaceholderNewPlaylist": "New playlist name", "PlaceholderNewPlaylist": "New playlist name",
"PlaceholderSearch": "Szukanie..", "PlaceholderSearch": "Szukanie..",
"PlaceholderSearchEpisode": "Search episode..",
"ToastAccountUpdateFailed": "Nie udało się zaktualizować konta", "ToastAccountUpdateFailed": "Nie udało się zaktualizować konta",
"ToastAccountUpdateSuccess": "Zaktualizowano konto", "ToastAccountUpdateSuccess": "Zaktualizowano konto",
"ToastAuthorImageRemoveFailed": "Nie udało się usunąć obrazu", "ToastAuthorImageRemoveFailed": "Nie udało się usunąć obrazu",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "Путь к новой папке", "PlaceholderNewFolderPath": "Путь к новой папке",
"PlaceholderNewPlaylist": "Новое название плейлиста", "PlaceholderNewPlaylist": "Новое название плейлиста",
"PlaceholderSearch": "Поиск...", "PlaceholderSearch": "Поиск...",
"PlaceholderSearchEpisode": "Search episode...",
"ToastAccountUpdateFailed": "Не удалось обновить учетную запись", "ToastAccountUpdateFailed": "Не удалось обновить учетную запись",
"ToastAccountUpdateSuccess": "Учетная запись обновлена", "ToastAccountUpdateSuccess": "Учетная запись обновлена",
"ToastAuthorImageRemoveFailed": "Не удалось удалить изображение", "ToastAuthorImageRemoveFailed": "Не удалось удалить изображение",

View File

@ -566,6 +566,7 @@
"PlaceholderNewFolderPath": "输入文件夹路径", "PlaceholderNewFolderPath": "输入文件夹路径",
"PlaceholderNewPlaylist": "输入播放列表名称", "PlaceholderNewPlaylist": "输入播放列表名称",
"PlaceholderSearch": "查找..", "PlaceholderSearch": "查找..",
"PlaceholderSearchEpisode": "Search episode..",
"ToastAccountUpdateFailed": "账户更新失败", "ToastAccountUpdateFailed": "账户更新失败",
"ToastAccountUpdateSuccess": "帐户已更新", "ToastAccountUpdateSuccess": "帐户已更新",
"ToastAuthorImageRemoveFailed": "作者图像删除失败", "ToastAuthorImageRemoveFailed": "作者图像删除失败",

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.2.16", "version": "2.2.17",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.2.16", "version": "2.2.17",
"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.2.16", "version": "2.2.17",
"description": "Self-hosted audiobook and podcast server", "description": "Self-hosted audiobook and podcast server",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {