Merge remote-tracking branch 'remotes/upstream/master'

This commit is contained in:
Toni Barth 2024-10-09 15:54:16 +02:00
commit 446345761c
108 changed files with 1963 additions and 996 deletions

View file

@ -70,6 +70,7 @@ jobs:
uses: docker/build-push-action@v3 uses: docker/build-push-action@v3
with: with:
tags: ${{ github.event.inputs.tags || steps.meta.outputs.tags }} tags: ${{ github.event.inputs.tags || steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64
push: true push: true

1
.gitignore vendored
View file

@ -16,6 +16,7 @@
/ffmpeg* /ffmpeg*
/ffprobe* /ffprobe*
/unicode* /unicode*
/libnusqlite3*
sw.* sw.*
.DS_STORE .DS_STORE

View file

@ -11,20 +11,35 @@ FROM node:20-alpine
ENV NODE_ENV=production ENV NODE_ENV=production
RUN apk update && \ RUN apk update && \
apk add --no-cache --update \ apk add --no-cache --update \
curl \ curl \
tzdata \ tzdata \
ffmpeg \ ffmpeg \
make \ make \
gcompat \ python3 \
python3 \ g++ \
g++ \ tini \
tini unzip
COPY --from=build /client/dist /client/dist COPY --from=build /client/dist /client/dist
COPY index.js package* / COPY index.js package* /
COPY server server COPY server server
ARG TARGETPLATFORM
ENV NUSQLITE3_DIR="/usr/local/lib/nusqlite3"
ENV NUSQLITE3_PATH="${NUSQLITE3_DIR}/libnusqlite3.so"
RUN case "$TARGETPLATFORM" in \
"linux/amd64") \
curl -L -o /tmp/library.zip "https://github.com/mikiher/nunicode-sqlite/releases/download/v1.2/libnusqlite3-linux-musl-x64.zip" ;; \
"linux/arm64") \
curl -L -o /tmp/library.zip "https://github.com/mikiher/nunicode-sqlite/releases/download/v1.2/libnusqlite3-linux-musl-arm64.zip" ;; \
*) echo "Unsupported platform: $TARGETPLATFORM" && exit 1 ;; \
esac && \
unzip /tmp/library.zip -d $NUSQLITE3_DIR && \
rm /tmp/library.zip
RUN npm ci --only=production RUN npm ci --only=production
RUN apk del make python3 g++ RUN apk del make python3 g++

View file

@ -24,7 +24,7 @@
</div> </div>
<div v-if="shelf.type === 'authors'" class="flex items-center"> <div v-if="shelf.type === 'authors'" class="flex items-center">
<template v-for="entity in shelf.entities"> <template v-for="entity in shelf.entities">
<cards-author-card :key="entity.id" :author="entity" @hook:updated="updatedBookCard" class="mx-2e" @edit="editAuthor" /> <cards-author-card :key="entity.id" :authorMount="entity" @hook:updated="updatedBookCard" class="mx-2e" @edit="editAuthor" />
</template> </template>
</div> </div>
<div v-if="shelf.type === 'narrators'" class="flex items-center"> <div v-if="shelf.type === 'narrators'" class="flex items-center">

View file

@ -30,7 +30,7 @@
<p v-if="isCollectionsPage" class="text-sm">{{ $strings.ButtonCollections }}</p> <p v-if="isCollectionsPage" class="text-sm">{{ $strings.ButtonCollections }}</p>
<span v-else class="material-symbols text-lg">&#xe431;</span> <span v-else class="material-symbols text-lg">&#xe431;</span>
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="flex-grow h-full flex justify-center items-center" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/authors`" class="flex-grow h-full flex justify-center items-center" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-primary bg-opacity-40'">
<p v-if="isAuthorsPage" class="text-sm">{{ $strings.ButtonAuthors }}</p> <p v-if="isAuthorsPage" class="text-sm">{{ $strings.ButtonAuthors }}</p>
<svg v-else class="w-5 h-5" viewBox="0 0 24 24"> <svg v-else class="w-5 h-5" viewBox="0 0 24 24">
<path <path
@ -62,7 +62,7 @@
<ui-context-menu-dropdown v-if="!isBatchSelecting && seriesContextMenuItems.length" :items="seriesContextMenuItems" class="mx-px" @action="seriesContextMenuAction" /> <ui-context-menu-dropdown v-if="!isBatchSelecting && seriesContextMenuItems.length" :items="seriesContextMenuItems" class="mx-px" @action="seriesContextMenuAction" />
</template> </template>
<!-- library & collections page --> <!-- library & collections page -->
<template v-else-if="page !== 'search' && page !== 'podcast-search' && page !== 'recent-episodes' && !isHome"> <template v-else-if="page !== 'search' && page !== 'podcast-search' && page !== 'recent-episodes' && !isHome && !isAuthorsPage">
<p class="hidden md:block">{{ $formatNumber(numShowing) }} {{ entityName }}</p> <p class="hidden md:block">{{ $formatNumber(numShowing) }} {{ entityName }}</p>
<div class="flex-grow hidden sm:inline-block" /> <div class="flex-grow hidden sm:inline-block" />
@ -92,12 +92,14 @@
<ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" /> <ui-context-menu-dropdown v-if="contextMenuItems.length" :items="contextMenuItems" :menu-width="110" class="ml-2" @action="contextMenuAction" />
</template> </template>
<!-- authors page --> <!-- authors page -->
<template v-else-if="page === 'authors'"> <template v-else-if="isAuthorsPage">
<div class="flex-grow" /> <p class="hidden md:block">{{ $formatNumber(numShowing) }} {{ entityName }}</p>
<ui-btn v-if="userCanUpdate && authors?.length && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn>
<div class="flex-grow hidden sm:inline-block" />
<ui-btn v-if="userCanUpdate && !isBatchSelecting" :loading="processingAuthors" color="primary" small @click="matchAllAuthors">{{ $strings.ButtonMatchAllAuthors }}</ui-btn>
<!-- author sort select --> <!-- author sort select -->
<controls-sort-select v-if="authors?.length" v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" /> <controls-sort-select v-model="settings.authorSortBy" :descending.sync="settings.authorSortDesc" :items="authorSortItems" class="w-36 sm:w-44 md:w-48 h-7.5 ml-1 sm:ml-4" @change="updateAuthorSort" />
</template> </template>
<!-- home page --> <!-- home page -->
<template v-else-if="isHome"> <template v-else-if="isHome">
@ -117,11 +119,7 @@ export default {
type: Object, type: Object,
default: () => null default: () => null
}, },
searchQuery: String, searchQuery: String
authors: {
type: Array,
default: () => []
}
}, },
data() { data() {
return { return {
@ -268,7 +266,7 @@ export default {
return this.$route.name === 'library-library-podcast-latest' return this.$route.name === 'library-library-podcast-latest'
}, },
isAuthorsPage() { isAuthorsPage() {
return this.$route.name === 'library-library-authors' return this.page === 'authors'
}, },
isAlbumsPage() { isAlbumsPage() {
return this.page === 'albums' return this.page === 'albums'
@ -284,6 +282,7 @@ export default {
if (this.isSeriesPage) return this.$strings.LabelSeries if (this.isSeriesPage) return this.$strings.LabelSeries
if (this.isCollectionsPage) return this.$strings.LabelCollections if (this.isCollectionsPage) return this.$strings.LabelCollections
if (this.isPlaylistsPage) return this.$strings.LabelPlaylists if (this.isPlaylistsPage) return this.$strings.LabelPlaylists
if (this.isAuthorsPage) return this.$strings.LabelAuthors
return '' return ''
}, },
seriesId() { seriesId() {
@ -473,42 +472,54 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to re-add series to continue listening', error) console.error('Failed to re-add series to continue listening', error)
this.$toast.error(this.$strings.ToastItemUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processingSeries = false this.processingSeries = false
}) })
}, },
async fetchAllAuthors() {
// fetch all authors from the server, in the order that they are currently displayed
const response = await this.$axios.$get(`/api/libraries/${this.currentLibraryId}/authors?sort=${this.settings.authorSortBy}&desc=${this.settings.authorSortDesc}`)
return response.authors
},
async matchAllAuthors() { async matchAllAuthors() {
this.processingAuthors = true this.processingAuthors = true
for (const author of this.authors) { try {
const payload = {} const authors = await this.fetchAllAuthors()
if (author.asin) payload.asin = author.asin
else payload.q = author.name
payload.region = 'us' for (const author of authors) {
if (this.libraryProvider.startsWith('audible.')) { const payload = {}
payload.region = this.libraryProvider.split('.').pop() || 'us' if (author.asin) payload.asin = author.asin
else payload.q = author.name
payload.region = 'us'
if (this.libraryProvider.startsWith('audible.')) {
payload.region = this.libraryProvider.split('.').pop() || 'us'
}
this.$eventBus.$emit(`searching-author-${author.id}`, true)
var response = await this.$axios.$post(`/api/authors/${author.id}/match`, payload).catch((error) => {
console.error('Failed', error)
return null
})
if (!response) {
console.error(`Author ${author.name} not found`)
this.$toast.error(this.$getString('ToastAuthorNotFound', [author.name]))
} else if (response.updated) {
if (response.author.imagePath) console.log(`Author ${response.author.name} was updated`)
else console.log(`Author ${response.author.name} was updated (no image found)`)
} else {
console.log(`No updates were made for Author ${response.author.name}`)
}
this.$eventBus.$emit(`searching-author-${author.id}`, false)
} }
} catch (error) {
this.$eventBus.$emit(`searching-author-${author.id}`, true) console.error('Failed to match all authors', error)
this.$toast.error(this.$strings.ToastMatchAllAuthorsFailed)
var response = await this.$axios.$post(`/api/authors/${author.id}/match`, payload).catch((error) => {
console.error('Failed', error)
return null
})
if (!response) {
console.error(`Author ${author.name} not found`)
this.$toast.error(this.$getString('ToastAuthorNotFound', [author.name]))
} else if (response.updated) {
if (response.author.imagePath) console.log(`Author ${response.author.name} was updated`)
else console.log(`Author ${response.author.name} was updated (no image found)`)
} else {
console.log(`No updates were made for Author ${response.author.name}`)
}
this.$eventBus.$emit(`searching-author-${author.id}`, false)
} }
this.processingAuthors = false this.processingAuthors = false
}, },

View file

@ -91,6 +91,7 @@ export default {
if (this.page === 'series') return this.$strings.MessageBookshelfNoSeries if (this.page === 'series') return this.$strings.MessageBookshelfNoSeries
if (this.page === 'collections') return this.$strings.MessageBookshelfNoCollections if (this.page === 'collections') return this.$strings.MessageBookshelfNoCollections
if (this.page === 'playlists') return this.$strings.MessageNoUserPlaylists if (this.page === 'playlists') return this.$strings.MessageNoUserPlaylists
if (this.page === 'authors') return this.$strings.MessageNoAuthors
if (this.hasFilter) { if (this.hasFilter) {
if (this.filterName === 'Issues') return this.$strings.MessageNoIssues if (this.filterName === 'Issues') return this.$strings.MessageNoIssues
else if (this.filterName === 'Feed-open') return this.$strings.MessageBookshelfNoRSSFeeds else if (this.filterName === 'Feed-open') return this.$strings.MessageBookshelfNoRSSFeeds
@ -111,6 +112,12 @@ export default {
seriesFilterBy() { seriesFilterBy() {
return this.$store.getters['user/getUserSetting']('seriesFilterBy') return this.$store.getters['user/getUserSetting']('seriesFilterBy')
}, },
authorSortBy() {
return this.$store.getters['user/getUserSetting']('authorSortBy')
},
authorSortDesc() {
return !!this.$store.getters['user/getUserSetting']('authorSortDesc')
},
orderBy() { orderBy() {
return this.$store.getters['user/getUserSetting']('orderBy') return this.$store.getters['user/getUserSetting']('orderBy')
}, },
@ -217,6 +224,8 @@ export default {
this.$store.commit('globals/setEditCollection', entity) this.$store.commit('globals/setEditCollection', entity)
} else if (this.entityName === 'playlists') { } else if (this.entityName === 'playlists') {
this.$store.commit('globals/setEditPlaylist', entity) this.$store.commit('globals/setEditPlaylist', entity)
} else if (this.entityName === 'authors') {
this.$store.commit('globals/showEditAuthorModal', entity)
} }
}, },
clearSelectedEntities() { clearSelectedEntities() {
@ -457,6 +466,9 @@ export default {
if (this.collapseBookSeries) { if (this.collapseBookSeries) {
searchParams.set('collapseseries', 1) searchParams.set('collapseseries', 1)
} }
} else if (this.page === 'authors') {
searchParams.set('sort', this.authorSortBy)
searchParams.set('desc', this.authorSortDesc ? 1 : 0)
} else { } else {
if (this.filterBy && this.filterBy !== 'all') { if (this.filterBy && this.filterBy !== 'all') {
searchParams.set('filter', this.filterBy) searchParams.set('filter', this.filterBy)
@ -601,6 +613,34 @@ export default {
this.executeRebuild() this.executeRebuild()
} }
}, },
authorAdded(author) {
if (this.entityName !== 'authors') return
console.log(`[LazyBookshelf] authorAdded ${author.id}`, author)
this.resetEntities()
},
authorUpdated(author) {
if (this.entityName !== 'authors') return
console.log(`[LazyBookshelf] authorUpdated ${author.id}`, author)
const indexOf = this.entities.findIndex((ent) => ent && ent.id === author.id)
if (indexOf >= 0) {
this.entities[indexOf] = author
if (this.entityComponentRefs[indexOf]) {
this.entityComponentRefs[indexOf].setEntity(author)
}
}
},
authorRemoved(author) {
if (this.entityName !== 'authors') return
console.log(`[LazyBookshelf] authorRemoved ${author.id}`, author)
const indexOf = this.entities.findIndex((ent) => ent && ent.id === author.id)
if (indexOf >= 0) {
this.entities = this.entities.filter((ent) => ent.id !== author.id)
this.totalEntities--
this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities)
this.executeRebuild()
}
},
shareOpen(mediaItemShare) { shareOpen(mediaItemShare) {
if (this.entityName === 'items' || this.entityName === 'series-books') { if (this.entityName === 'items' || this.entityName === 'series-books') {
var indexOf = this.entities.findIndex((ent) => ent?.media?.id === mediaItemShare.mediaItemId) var indexOf = this.entities.findIndex((ent) => ent?.media?.id === mediaItemShare.mediaItemId)
@ -727,6 +767,9 @@ export default {
this.$root.socket.on('playlist_added', this.playlistAdded) this.$root.socket.on('playlist_added', this.playlistAdded)
this.$root.socket.on('playlist_updated', this.playlistUpdated) this.$root.socket.on('playlist_updated', this.playlistUpdated)
this.$root.socket.on('playlist_removed', this.playlistRemoved) this.$root.socket.on('playlist_removed', this.playlistRemoved)
this.$root.socket.on('author_added', this.authorAdded)
this.$root.socket.on('author_updated', this.authorUpdated)
this.$root.socket.on('author_removed', this.authorRemoved)
this.$root.socket.on('share_open', this.shareOpen) this.$root.socket.on('share_open', this.shareOpen)
this.$root.socket.on('share_closed', this.shareClosed) this.$root.socket.on('share_closed', this.shareClosed)
} else { } else {
@ -756,6 +799,9 @@ export default {
this.$root.socket.off('playlist_added', this.playlistAdded) this.$root.socket.off('playlist_added', this.playlistAdded)
this.$root.socket.off('playlist_updated', this.playlistUpdated) this.$root.socket.off('playlist_updated', this.playlistUpdated)
this.$root.socket.off('playlist_removed', this.playlistRemoved) this.$root.socket.off('playlist_removed', this.playlistRemoved)
this.$root.socket.off('author_added', this.authorAdded)
this.$root.socket.off('author_updated', this.authorUpdated)
this.$root.socket.off('author_removed', this.authorRemoved)
this.$root.socket.off('share_open', this.shareOpen) this.$root.socket.off('share_open', this.shareOpen)
this.$root.socket.off('share_closed', this.shareClosed) this.$root.socket.off('share_closed', this.shareClosed)
} else { } else {

View file

@ -58,7 +58,7 @@
<div v-show="isPlaylistsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" /> <div v-show="isPlaylistsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link> </nuxt-link>
<nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'"> <nuxt-link v-if="isBookLibrary" :to="`/library/${currentLibraryId}/bookshelf/authors`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isAuthorsPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<svg class="w-6 h-6" viewBox="0 0 24 24"> <svg class="w-6 h-6" viewBox="0 0 24 24">
<path <path
fill="currentColor" fill="currentColor"
@ -180,7 +180,7 @@ export default {
return this.$route.name === 'library-library-series-id' || this.paramId === 'series' return this.$route.name === 'library-library-series-id' || this.paramId === 'series'
}, },
isAuthorsPage() { isAuthorsPage() {
return this.$route.name === 'library-library-authors' return this.libraryBookshelfPage && this.paramId === 'authors'
}, },
isNarratorsPage() { isNarratorsPage() {
return this.$route.name === 'library-library-narrators' return this.$route.name === 'library-library-narrators'

View file

@ -1,6 +1,6 @@
<template> <template>
<div :style="{ minWidth: cardWidth + 'px', maxWidth: cardWidth + 'px' }"> <div class="pb-3e" :style="{ minWidth: cardWidth + 'px', maxWidth: cardWidth + 'px' }">
<nuxt-link :to="`/author/${author.id}`"> <nuxt-link :to="`/author/${author?.id}`">
<div cy-id="card" @mouseover="mouseover" @mouseleave="mouseleave"> <div cy-id="card" @mouseover="mouseover" @mouseleave="mouseleave">
<div cy-id="imageArea" :style="{ height: cardHeight + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden"> <div cy-id="imageArea" :style="{ height: cardHeight + 'px' }" class="bg-primary box-shadow-book rounded-md relative overflow-hidden">
<!-- Image or placeholder --> <!-- Image or placeholder -->
@ -40,7 +40,7 @@
<script> <script>
export default { export default {
props: { props: {
author: { authorMount: {
type: Object, type: Object,
default: () => {} default: () => {}
}, },
@ -57,7 +57,8 @@ export default {
data() { data() {
return { return {
searching: false, searching: false,
isHovering: false isHovering: false,
author: null
} }
}, },
computed: { computed: {
@ -68,34 +69,37 @@ export default {
return this.height * this.sizeMultiplier return this.height * this.sizeMultiplier
}, },
userToken() { userToken() {
return this.$store.getters['user/getToken'] return this.store.getters['user/getToken']
}, },
_author() { _author() {
return this.author || {} return this.author || {}
}, },
authorId() { authorId() {
return this._author.id return this._author?.id || ''
}, },
name() { name() {
return this._author.name || '' return this._author?.name || ''
}, },
asin() { asin() {
return this._author.asin || '' return this._author?.asin || ''
}, },
numBooks() { numBooks() {
return this._author.numBooks || 0 return this._author?.numBooks || 0
},
store() {
return this.$store || this.$nuxt.$store
}, },
userCanUpdate() { userCanUpdate() {
return this.$store.getters['user/getUserCanUpdate'] return this.store.getters['user/getUserCanUpdate']
}, },
currentLibraryId() { currentLibraryId() {
return this.$store.state.libraries.currentLibraryId return this.store.state.libraries.currentLibraryId
}, },
libraryProvider() { libraryProvider() {
return this.$store.getters['libraries/getLibraryProvider'](this.currentLibraryId) || 'google' return this.store.getters['libraries/getLibraryProvider'](this.currentLibraryId) || 'google'
}, },
sizeMultiplier() { sizeMultiplier() {
return this.$store.getters['user/getSizeMultiplier'] return this.store.getters['user/getSizeMultiplier']
} }
}, },
methods: { methods: {
@ -132,13 +136,40 @@ export default {
}, },
setSearching(isSearching) { setSearching(isSearching) {
this.searching = isSearching this.searching = isSearching
} },
setEntity(author) {
this.removeListeners()
this.author = author
this.addListeners()
},
addListeners() {
if (this.author) {
this.$eventBus.$on(`searching-author-${this.authorId}`, this.setSearching)
}
},
removeListeners() {
if (this.author) {
this.$eventBus.$off(`searching-author-${this.authorId}`, this.setSearching)
}
},
destroy() {
// destroy the vue listeners, etc
this.$destroy()
// remove the element from the DOM
if (this.$el && this.$el.parentNode) {
this.$el.parentNode.removeChild(this.$el)
} else if (this.$el && this.$el.remove) {
this.$el.remove()
}
},
setSelectionMode(val) {}
}, },
mounted() { mounted() {
this.$eventBus.$on(`searching-author-${this.authorId}`, this.setSearching) if (this.authorMount) this.setEntity(this.authorMount)
}, },
beforeDestroy() { beforeDestroy() {
this.$eventBus.$off(`searching-author-${this.authorId}`, this.setSearching) this.removeListeners()
} }
} }
</script> </script>

View file

@ -8,6 +8,7 @@
<p class="truncate text-sm">{{ title }}</p> <p class="truncate text-sm">{{ title }}</p>
<p class="truncate text-xs text-gray-300">{{ description }}</p> <p class="truncate text-xs text-gray-300">{{ description }}</p>
<p v-if="specialMessage" class="truncate text-xs text-gray-300">{{ specialMessage }}</p>
<p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p> <p v-if="isFailed && failedMessage" class="text-xs truncate text-red-500">{{ failedMessage }}</p>
<p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p> <p v-else-if="!isFinished && cancelingScan" class="text-xs truncate">Canceling...</p>
@ -26,7 +27,16 @@ export default {
}, },
data() { data() {
return { return {
cancelingScan: false cancelingScan: false,
specialMessage: ''
}
},
watch: {
task: {
immediate: true,
handler() {
this.initTask()
}
} }
}, },
computed: { computed: {
@ -34,14 +44,17 @@ export default {
return this.$store.getters['user/getIsAdminOrUp'] return this.$store.getters['user/getIsAdminOrUp']
}, },
title() { title() {
if (this.task.titleKey && this.$strings[this.task.titleKey]) {
return this.$getString(this.task.titleKey, this.task.titleSubs)
}
return this.task.title || 'No Title' return this.task.title || 'No Title'
}, },
description() { description() {
if (this.task.descriptionKey && this.$strings[this.task.descriptionKey]) {
return this.$getString(this.task.descriptionKey, this.task.descriptionSubs)
}
return this.task.description || '' return this.task.description || ''
}, },
details() {
return this.task.details || 'Unknown'
},
isFinished() { isFinished() {
return !!this.task.isFinished return !!this.task.isFinished
}, },
@ -52,6 +65,9 @@ export default {
return this.isFinished && !this.isFailed return this.isFinished && !this.isFailed
}, },
failedMessage() { failedMessage() {
if (this.task.errorKey && this.$strings[this.task.errorKey]) {
return this.$getString(this.task.errorKey, this.task.errorSubs)
}
return this.task.error || '' return this.task.error || ''
}, },
action() { action() {
@ -87,6 +103,21 @@ export default {
} }
}, },
methods: { methods: {
initTask() {
// special message for library scan tasks
if (this.task?.data?.scanResults) {
const scanResults = this.task.data.scanResults
const strs = []
if (scanResults.added) strs.push(this.$getString('MessageTaskScanItemsAdded', [scanResults.added]))
if (scanResults.updated) strs.push(this.$getString('MessageTaskScanItemsUpdated', [scanResults.updated]))
if (scanResults.missing) strs.push(this.$getString('MessageTaskScanItemsMissing', [scanResults.missing]))
const changesDetected = strs.length > 0 ? strs.join(', ') : this.$strings.MessageTaskScanNoChangesNeeded
const timeElapsed = scanResults.elapsed ? ` (${this.$elapsedPretty(scanResults.elapsed / 1000, false, true)})` : ''
this.specialMessage = `${changesDetected}${timeElapsed}`
} else {
this.specialMessage = ''
}
},
cancelScan() { cancelScan() {
const libraryId = this.task?.data?.libraryId const libraryId = this.task?.data?.libraryId
if (!libraryId) { if (!libraryId) {

View file

@ -816,7 +816,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to remove series from home', error) console.error('Failed to remove series from home', error)
this.$toast.error(this.$strings.ToastFailedToUpdateUser) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processing = false this.processing = false
@ -834,7 +834,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to hide item from home', error) console.error('Failed to hide item from home', error)
this.$toast.error(this.$strings.ToastFailedToUpdateUser) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processing = false this.processing = false

View file

@ -130,7 +130,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update notification', error) console.error('Failed to update notification', error)
this.$toast.error(this.$strings.ToastNotificationUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.enabling = false this.enabling = false

View file

@ -189,6 +189,12 @@ export default {
value: 'publishers', value: 'publishers',
sublist: true sublist: true
}, },
{
text: this.$strings.LabelPublishedDecade,
textPlural: this.$strings.LabelPublishedDecades,
value: 'publishedDecades',
sublist: true
},
{ {
text: this.$strings.LabelLanguage, text: this.$strings.LabelLanguage,
textPlural: this.$strings.LabelLanguages, textPlural: this.$strings.LabelLanguages,
@ -338,6 +344,9 @@ export default {
publishers() { publishers() {
return this.filterData.publishers || [] return this.filterData.publishers || []
}, },
publishedDecades() {
return this.filterData.publishedDecades || []
},
progress() { progress() {
return [ return [
{ {

View file

@ -1,9 +1,9 @@
<template> <template>
<div ref="wrapper" class="relative ml-4 sm:ml-8" v-click-outside="clickOutside"> <div ref="wrapper" class="relative ml-4 sm:ml-8" v-click-outside="clickOutside">
<div class="flex items-center justify-center text-gray-300 cursor-pointer h-full" @mousedown.prevent @mouseup.prevent @click="setShowMenu(true)"> <div class="flex items-center justify-center text-gray-300 cursor-pointer h-full" @mousedown.prevent @mouseup.prevent @click="setShowMenu(true)">
<span class="font-mono uppercase text-gray-200 text-sm sm:text-base">{{ playbackRate.toFixed(1) }}<span class="text-base">x</span></span> <span class="text-gray-200 text-sm sm:text-base">{{ playbackRate.toFixed(1) }}<span class="text-base">x</span></span>
</div> </div>
<div v-show="showMenu" class="absolute -top-20 z-20 bg-bg border-black-200 border shadow-xl rounded-lg" :style="{ left: menuLeft + 'px' }"> <div v-show="showMenu" class="absolute -top-[5.5rem] z-20 bg-bg border-black-200 border shadow-xl rounded-lg" :style="{ left: menuLeft + 'px' }">
<div class="absolute -bottom-1.5 right-0 w-full flex justify-center" :style="{ left: arrowLeft + 'px' }"> <div class="absolute -bottom-1.5 right-0 w-full flex justify-center" :style="{ left: arrowLeft + 'px' }">
<div class="arrow-down" /> <div class="arrow-down" />
</div> </div>
@ -11,12 +11,12 @@
<template v-for="rate in rates"> <template v-for="rate in rates">
<div :key="rate" class="h-full border-black-300 w-11 cursor-pointer border rounded-sm" :class="value === rate ? 'bg-black-100' : 'hover:bg-black hover:bg-opacity-10'" style="min-width: 44px; max-width: 44px" @click="set(rate)"> <div :key="rate" class="h-full border-black-300 w-11 cursor-pointer border rounded-sm" :class="value === rate ? 'bg-black-100' : 'hover:bg-black hover:bg-opacity-10'" style="min-width: 44px; max-width: 44px" @click="set(rate)">
<div class="w-full h-full flex justify-center items-center"> <div class="w-full h-full flex justify-center items-center">
<p class="text-xs text-center font-mono">{{ rate }}<span class="text-sm">x</span></p> <p class="text-xs text-center">{{ rate }}<span class="text-sm">x</span></p>
</div> </div>
</div> </div>
</template> </template>
</div> </div>
<div class="w-full py-1 px-4"> <div class="w-full py-1 px-1">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<ui-icon-btn :disabled="!canDecrement" icon="remove" @click="decrement" /> <ui-icon-btn :disabled="!canDecrement" icon="remove" @click="decrement" />
<p class="px-2 text-2xl sm:text-3xl">{{ playbackRate }}<span class="text-2xl">x</span></p> <p class="px-2 text-2xl sm:text-3xl">{{ playbackRate }}<span class="text-2xl">x</span></p>
@ -41,7 +41,7 @@ export default {
currentPlaybackRate: 0, currentPlaybackRate: 0,
MIN_SPEED: 0.5, MIN_SPEED: 0.5,
MAX_SPEED: 10, MAX_SPEED: 10,
menuLeft: -92, menuLeft: -96,
arrowLeft: 0 arrowLeft: 0
} }
}, },
@ -89,9 +89,9 @@ export default {
if (boundingBox.left + 110 > window.innerWidth - 10) { if (boundingBox.left + 110 > window.innerWidth - 10) {
this.menuLeft = window.innerWidth - 230 - boundingBox.left this.menuLeft = window.innerWidth - 230 - boundingBox.left
this.arrowLeft = Math.abs(this.menuLeft) - 92 this.arrowLeft = Math.abs(this.menuLeft) - 96
} else { } else {
this.menuLeft = -92 this.menuLeft = -96
this.arrowLeft = 0 this.arrowLeft = 0
} }
}, },
@ -109,4 +109,4 @@ export default {
this.currentPlaybackRate = this.playbackRate this.currentPlaybackRate = this.playbackRate
} }
} }
</script> </script>

View file

@ -4,10 +4,10 @@
<span class="material-symbols text-2xl sm:text-3xl">{{ volumeIcon }}</span> <span class="material-symbols text-2xl sm:text-3xl">{{ volumeIcon }}</span>
</button> </button>
<transition name="menux"> <transition name="menux">
<div v-show="isOpen" class="volumeMenu h-6 absolute bottom-2 w-28 px-2 bg-bg shadow-sm rounded-lg" style="left: -116px"> <div v-show="isOpen" class="volumeMenu h-28 absolute bottom-2 w-6 py-2 bg-bg shadow-sm rounded-lg" style="top: -116px">
<div ref="volumeTrack" class="h-1 w-full bg-gray-500 my-2.5 relative cursor-pointer rounded-full" @mousedown="mousedownTrack" @click="clickVolumeTrack"> <div ref="volumeTrack" class="w-1 h-full bg-gray-500 mx-2.5 relative cursor-pointer rounded-full" @mousedown="mousedownTrack" @click="clickVolumeTrack">
<div class="bg-gray-100 h-full absolute left-0 top-0 pointer-events-none rounded-full" :style="{ width: volume * trackWidth + 'px' }" /> <div class="bg-gray-100 w-full absolute left-0 bottom-0 pointer-events-none rounded-full" :style="{ height: volume * trackHeight + 'px' }" />
<div class="w-2.5 h-2.5 bg-white shadow-sm rounded-full absolute pointer-events-none" :class="isDragging ? 'transform scale-125 origin-center' : ''" :style="{ left: cursorLeft + 'px', top: '-3px' }" /> <div class="w-2.5 h-2.5 bg-white shadow-sm rounded-full absolute pointer-events-none" :class="isDragging ? 'transform scale-125 origin-center' : ''" :style="{ bottom: cursorBottom + 'px', left: '-3px' }" />
</div> </div>
</div> </div>
</transition> </transition>
@ -24,10 +24,10 @@ export default {
isOpen: false, isOpen: false,
isDragging: false, isDragging: false,
isHovering: false, isHovering: false,
posX: 0, posY: 0,
lastValue: 0.5, lastValue: 0.5,
isMute: false, isMute: false,
trackWidth: 112 - 20, trackHeight: 112 - 20,
openTimeout: null openTimeout: null
} }
}, },
@ -45,9 +45,9 @@ export default {
this.$emit('input', val) this.$emit('input', val)
} }
}, },
cursorLeft() { cursorBottom() {
var left = this.trackWidth * this.volume var bottom = this.trackHeight * this.volume
return left - 3 return bottom - 3
}, },
volumeIcon() { volumeIcon() {
if (this.volume <= 0) return 'volume_mute' if (this.volume <= 0) return 'volume_mute'
@ -89,17 +89,10 @@ export default {
}, 600) }, 600)
}, },
mousemove(e) { mousemove(e) {
var diff = this.posX - e.x var diff = this.posY - e.y
this.posX = e.x this.posY = e.y
var volShift = 0 var volShift = diff / this.trackHeight
if (diff < 0) { var newVol = this.volume + volShift
// Volume up
volShift = diff / this.trackWidth
} else {
// volume down
volShift = diff / this.trackWidth
}
var newVol = this.volume - volShift
newVol = Math.min(Math.max(0, newVol), 1) newVol = Math.min(Math.max(0, newVol), 1)
this.volume = newVol this.volume = newVol
e.preventDefault() e.preventDefault()
@ -113,8 +106,8 @@ export default {
}, },
mousedownTrack(e) { mousedownTrack(e) {
this.isDragging = true this.isDragging = true
this.posX = e.x this.posY = e.y
var vol = e.offsetX / this.trackWidth var vol = 1 - e.offsetY / this.trackHeight
vol = Math.min(Math.max(vol, 0), 1) vol = Math.min(Math.max(vol, 0), 1)
this.volume = vol this.volume = vol
document.body.addEventListener('mousemove', this.mousemove) document.body.addEventListener('mousemove', this.mousemove)
@ -137,7 +130,7 @@ export default {
this.clickVolumeIcon() this.clickVolumeIcon()
}, },
clickVolumeTrack(e) { clickVolumeTrack(e) {
var vol = e.offsetX / this.trackWidth var vol = 1 - e.offsetY / this.trackHeight
vol = Math.min(Math.max(vol, 0), 1) vol = Math.min(Math.max(vol, 0), 1)
this.volume = vol this.volume = vol
} }
@ -147,7 +140,7 @@ export default {
this.isMute = true this.isMute = true
} }
const storageVolume = localStorage.getItem('volume') const storageVolume = localStorage.getItem('volume')
if (storageVolume) { if (storageVolume && !isNaN(storageVolume)) {
this.volume = parseFloat(storageVolume) this.volume = parseFloat(storageVolume)
} }
}, },
@ -157,4 +150,4 @@ export default {
document.body.removeEventListener('mouseup', this.mouseup) document.body.removeEventListener('mouseup', this.mouseup)
} }
} }
</script> </script>

View file

@ -296,7 +296,7 @@ export default {
.then((data) => { .then((data) => {
this.processing = false this.processing = false
if (data.error) { if (data.error) {
this.$toast.error(`${this.$strings.ToastAccountUpdateFailed}: ${data.error}`) this.$toast.error(`${this.$strings.ToastFailedToUpdate}: ${data.error}`)
} else { } else {
console.log('Account updated', data.user) console.log('Account updated', data.user)
@ -313,7 +313,7 @@ export default {
this.processing = false this.processing = false
console.error('Failed to update account', error) console.error('Failed to update account', error)
var errMsg = error.response ? error.response.data || '' : '' var errMsg = error.response ? error.response.data || '' : ''
this.$toast.error(errMsg || this.$strings.ToastFailedToUpdateAccount) this.$toast.error(errMsg || this.$strings.ToastFailedToUpdate)
}) })
}, },
submitCreateAccount() { submitCreateAccount() {

View file

@ -110,7 +110,7 @@ export default {
this.$toast.success(this.$strings.ToastBookmarkUpdateSuccess) this.$toast.success(this.$strings.ToastBookmarkUpdateSuccess)
}) })
.catch((error) => { .catch((error) => {
this.$toast.error(this.$strings.ToastBookmarkUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
console.error(error) console.error(error)
}) })
this.show = false this.show = false

View file

@ -148,7 +148,7 @@ export default {
var result = await this.$axios.$patch(`/api/authors/${this.authorId}`, updatePayload).catch((error) => { var result = await this.$axios.$patch(`/api/authors/${this.authorId}`, updatePayload).catch((error) => {
console.error('Failed', error) console.error('Failed', error)
const errorMsg = error.response ? error.response.data : null const errorMsg = error.response ? error.response.data : null
this.$toast.error(errorMsg || this.$strings.ToastAuthorUpdateFailed) this.$toast.error(errorMsg || this.$strings.ToastFailedToUpdate)
return null return null
}) })
if (result) { if (result) {

View file

@ -135,7 +135,7 @@ export default {
.catch((error) => { .catch((error) => {
console.error('Failed to update collection', error) console.error('Failed to update collection', error)
this.processing = false this.processing = false
this.$toast.error(this.$strings.ToastCollectionUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
} }
}, },

View file

@ -178,7 +178,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update device', error) console.error('Failed to update device', error)
this.$toast.error(this.$strings.ToastDeviceUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processing = false this.processing = false

View file

@ -623,7 +623,7 @@ export default {
this.clearSelectedMatch() this.clearSelectedMatch()
this.$emit('selectTab', 'details') this.$emit('selectTab', 'details')
} else { } else {
this.$toast.error(this.$strings.ToastItemDetailsUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
} }
} else { } else {
this.clearSelectedMatch() this.clearSelectedMatch()

View file

@ -222,7 +222,7 @@ export default {
if (error.response && error.response.data) { if (error.response && error.response.data) {
this.$toast.error(error.response.data) this.$toast.error(error.response.data)
} else { } else {
this.$toast.error(this.$strings.ToastLibraryUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
} }
this.processing = false this.processing = false
}) })

View file

@ -132,7 +132,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update notification', error) console.error('Failed to update notification', error)
this.$toast.error(this.$strings.ToastNotificationUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processing = false this.processing = false

View file

@ -135,7 +135,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to remove items from playlist', error) console.error('Failed to remove items from playlist', error)
this.$toast.error(this.$strings.ToastPlaylistUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
this.processing = false this.processing = false
}) })
}, },
@ -153,7 +153,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to add items to playlist', error) console.error('Failed to add items to playlist', error)
this.$toast.error(this.$strings.ToastPlaylistUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
this.processing = false this.processing = false
}) })
}, },

View file

@ -115,7 +115,7 @@ export default {
.catch((error) => { .catch((error) => {
console.error('Failed to update playlist', error) console.error('Failed to update playlist', error)
this.processing = false this.processing = false
this.$toast.error(this.$strings.ToastPlaylistUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
} }
}, },

View file

@ -1,38 +1,37 @@
<template> <template>
<div class="flex items-center pt-4 pb-2 lg:pt-0 lg:pb-2"> <div class="flex justify-center pt-4 pb-2 lg:pt-0 lg:pb-2">
<div class="flex-grow" /> <div class="flex items-center justify-center flex-grow">
<template v-if="!loading"> <template v-if="!loading">
<ui-tooltip direction="top" :text="$strings.ButtonPreviousChapter" class="mr-4 lg:mr-8"> <ui-tooltip direction="top" :text="$strings.ButtonPreviousChapter" class="mr-4 lg:mr-8">
<button :aria-label="$strings.ButtonPreviousChapter" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="prevChapter"> <button :aria-label="$strings.ButtonPreviousChapter" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="prevChapter">
<span class="material-symbols text-2xl sm:text-3xl">first_page</span> <span class="material-symbols text-2xl sm:text-3xl">first_page</span>
</button>
</ui-tooltip>
<ui-tooltip direction="top" :text="jumpBackwardText">
<button :aria-label="jumpForwardText" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="jumpBackward">
<span class="material-symbols text-2xl sm:text-3xl">replay</span>
</button>
</ui-tooltip>
<button :aria-label="paused ? $strings.ButtonPlay : $strings.ButtonPause" class="p-2 shadow-sm bg-accent flex items-center justify-center rounded-full text-primary mx-4 lg:mx-8" :class="seekLoading ? 'animate-spin' : ''" @mousedown.prevent @mouseup.prevent @click.stop="playPause">
<span class="material-symbols fill text-2xl">{{ seekLoading ? 'autorenew' : paused ? 'play_arrow' : 'pause' }}</span>
</button> </button>
</ui-tooltip> <ui-tooltip direction="top" :text="jumpForwardText">
<ui-tooltip direction="top" :text="jumpBackwardText"> <button :aria-label="jumpForwardText" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="jumpForward">
<button :aria-label="jumpForwardText" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="jumpBackward"> <span class="material-symbols text-2xl sm:text-3xl">forward_media</span>
<span class="material-symbols text-2xl sm:text-3xl">replay</span> </button>
</button> </ui-tooltip>
</ui-tooltip> <ui-tooltip direction="top" :text="hasNextLabel" class="ml-4 lg:ml-8">
<button :aria-label="paused ? $strings.ButtonPlay : $strings.ButtonPause" class="p-2 shadow-sm bg-accent flex items-center justify-center rounded-full text-primary mx-4 lg:mx-8" :class="seekLoading ? 'animate-spin' : ''" @mousedown.prevent @mouseup.prevent @click.stop="playPause"> <button :aria-label="hasNextLabel" :disabled="!hasNext" class="text-gray-300 disabled:text-gray-500" @mousedown.prevent @mouseup.prevent @click.stop="next">
<span class="material-symbols fill text-2xl">{{ seekLoading ? 'autorenew' : paused ? 'play_arrow' : 'pause' }}</span> <span class="material-symbols text-2xl sm:text-3xl">last_page</span>
</button> </button>
<ui-tooltip direction="top" :text="jumpForwardText"> </ui-tooltip>
<button :aria-label="jumpForwardText" class="text-gray-300" @mousedown.prevent @mouseup.prevent @click.stop="jumpForward"> </template>
<span class="material-symbols text-2xl sm:text-3xl">forward_media</span> <template v-else>
</button> <div class="cursor-pointer p-2 shadow-sm bg-accent flex items-center justify-center rounded-full text-primary mx-8 animate-spin">
</ui-tooltip> <span class="material-symbols text-2xl">autorenew</span>
<ui-tooltip direction="top" :text="hasNextLabel" class="ml-4 lg:ml-8"> </div>
<button :aria-label="hasNextLabel" :disabled="!hasNext" class="text-gray-300 disabled:text-gray-500" @mousedown.prevent @mouseup.prevent @click.stop="next"> </template>
<span class="material-symbols text-2xl sm:text-3xl">last_page</span> </div>
</button>
</ui-tooltip>
<controls-playback-speed-control v-model="playbackRateInput" @input="playbackRateUpdated" @change="playbackRateChanged" />
</template>
<template v-else>
<div class="cursor-pointer p-2 shadow-sm bg-accent flex items-center justify-center rounded-full text-primary mx-8 animate-spin">
<span class="material-symbols text-2xl">autorenew</span>
</div>
</template>
<div class="flex-grow" />
</div> </div>
</template> </template>
@ -41,7 +40,6 @@ export default {
props: { props: {
loading: Boolean, loading: Boolean,
seekLoading: Boolean, seekLoading: Boolean,
playbackRate: Number,
paused: Boolean, paused: Boolean,
hasNextChapter: Boolean, hasNextChapter: Boolean,
hasNextItemInQueue: Boolean hasNextItemInQueue: Boolean
@ -50,14 +48,6 @@ export default {
return {} return {}
}, },
computed: { computed: {
playbackRateInput: {
get() {
return this.playbackRate
},
set(val) {
this.$emit('update:playbackRate', val)
}
},
jumpForwardText() { jumpForwardText() {
return this.getJumpText('jumpForwardAmount', this.$strings.ButtonJumpForward) return this.getJumpText('jumpForwardAmount', this.$strings.ButtonJumpForward)
}, },
@ -89,15 +79,6 @@ export default {
jumpForward() { jumpForward() {
this.$emit('jumpForward') this.$emit('jumpForward')
}, },
playbackRateUpdated(playbackRate) {
this.$emit('setPlaybackRate', playbackRate)
},
playbackRateChanged(playbackRate) {
this.$emit('setPlaybackRate', playbackRate)
this.$store.dispatch('user/updateUserSettings', { playbackRate }).catch((err) => {
console.error('Failed to update settings', err)
})
},
getJumpText(setting, prefix) { getJumpText(setting, prefix) {
const amount = this.$store.getters['user/getUserSetting'](setting) const amount = this.$store.getters['user/getUserSetting'](setting)
if (!amount) return prefix if (!amount) return prefix

View file

@ -2,9 +2,9 @@
<div class="w-full -mt-6"> <div class="w-full -mt-6">
<div class="w-full relative mb-1"> <div class="w-full relative mb-1">
<div class="absolute -top-10 lg:top-0 right-0 lg:right-2 flex items-center h-full"> <div class="absolute -top-10 lg:top-0 right-0 lg:right-2 flex items-center h-full">
<!-- <span class="material-symbols text-2xl cursor-pointer" @click="toggleFullscreen(true)">expand_less</span> --> <controls-playback-speed-control v-model="playbackRate" @input="setPlaybackRate" @change="playbackRateChanged" class="mx-2 block" />
<ui-tooltip direction="top" :text="$strings.LabelVolume"> <ui-tooltip direction="left" :text="$strings.LabelVolume">
<controls-volume-control ref="volumeControl" v-model="volume" @input="setVolume" class="mx-2 hidden sm:block" /> <controls-volume-control ref="volumeControl" v-model="volume" @input="setVolume" class="mx-2 hidden sm:block" />
</ui-tooltip> </ui-tooltip>
@ -13,7 +13,7 @@
<span v-if="!sleepTimerSet" class="material-symbols text-2xl">snooze</span> <span v-if="!sleepTimerSet" class="material-symbols text-2xl">snooze</span>
<div v-else class="flex items-center"> <div v-else class="flex items-center">
<span class="material-symbols text-lg text-warning">snooze</span> <span class="material-symbols text-lg text-warning">snooze</span>
<p class="text-sm sm:text-lg text-warning font-mono font-semibold text-center px-0.5 sm:pb-0.5 sm:min-w-8">{{ sleepTimerRemainingString }}</p> <p class="text-sm sm:text-lg text-warning font-semibold text-center px-0.5 sm:pb-0.5 sm:min-w-8">{{ sleepTimerRemainingString }}</p>
</div> </div>
</button> </button>
</ui-tooltip> </ui-tooltip>
@ -48,15 +48,19 @@
<player-track-bar ref="trackbar" :loading="loading" :chapters="chapters" :duration="duration" :current-chapter="currentChapter" :playback-rate="playbackRate" @seek="seek" /> <player-track-bar ref="trackbar" :loading="loading" :chapters="chapters" :duration="duration" :current-chapter="currentChapter" :playback-rate="playbackRate" @seek="seek" />
<div class="flex"> <div class="relative flex items-center justify-between">
<p ref="currentTimestamp" class="font-mono text-xxs sm:text-sm text-gray-100 pointer-events-auto">00:00:00</p> <div class="flex-grow flex items-center">
<p class="font-mono text-sm hidden sm:block text-gray-100 pointer-events-auto">&nbsp;/&nbsp;{{ progressPercent }}%</p> <p ref="currentTimestamp" class="font-mono text-xxs sm:text-sm text-gray-100 pointer-events-auto">00:00:00</p>
<div class="flex-grow" /> <p class="font-mono text-sm hidden sm:block text-gray-100 pointer-events-auto">&nbsp;/&nbsp;{{ progressPercent }}%</p>
<p class="text-xs sm:text-sm text-gray-300 pt-0.5 px-2 truncate"> </div>
{{ currentChapterName }} <span v-if="useChapterTrack" class="text-xs text-gray-400">&nbsp;({{ $getString('LabelPlayerChapterNumberMarker', [currentChapterIndex + 1, chapters.length]) }})</span> <div class="absolute left-1/2 transform -translate-x-1/2">
</p> <p class="text-xs sm:text-sm text-gray-300 pt-0.5 px-2 truncate">
<div class="flex-grow" /> {{ currentChapterName }} <span v-if="useChapterTrack" class="text-xs text-gray-400">&nbsp;({{ $getString('LabelPlayerChapterNumberMarker', [currentChapterIndex + 1, chapters.length]) }})</span>
<p class="font-mono text-xxs sm:text-sm text-gray-100 pointer-events-auto">{{ timeRemainingPretty }}</p> </p>
</div>
<div class="flex-grow flex items-center justify-end">
<p class="font-mono text-xxs sm:text-sm text-gray-100 pointer-events-auto">{{ timeRemainingPretty }}</p>
</div>
</div> </div>
<modals-chapters-modal v-model="showChaptersModal" :current-chapter="currentChapter" :playback-rate="playbackRate" :chapters="chapters" @select="selectChapter" /> <modals-chapters-modal v-model="showChaptersModal" :current-chapter="currentChapter" :playback-rate="playbackRate" :chapters="chapters" @select="selectChapter" />
@ -224,6 +228,12 @@ export default {
this.playbackRate = Number((this.playbackRate - 0.1).toFixed(1)) this.playbackRate = Number((this.playbackRate - 0.1).toFixed(1))
this.setPlaybackRate(this.playbackRate) this.setPlaybackRate(this.playbackRate)
}, },
playbackRateChanged(playbackRate) {
this.setPlaybackRate(playbackRate)
this.$store.dispatch('user/updateUserSettings', { playbackRate }).catch((err) => {
console.error('Failed to update settings', err)
})
},
setPlaybackRate(playbackRate) { setPlaybackRate(playbackRate) {
this.$emit('setPlaybackRate', playbackRate) this.$emit('setPlaybackRate', playbackRate)
}, },

View file

@ -35,22 +35,22 @@
<div class="flex justify-between pt-12"> <div class="flex justify-between pt-12">
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsWeekListening }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ totalMinutesListeningThisWeek }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(totalMinutesListeningThisWeek) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsDailyAverage }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ averageMinutesPerDay }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(averageMinutesPerDay) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsBestDay }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ mostListenedDay }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(mostListenedDay) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsMinutes }}</p>
</div> </div>
<div> <div>
<p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsDays }}</p>
<p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ daysInARow }}</p> <p class="text-5xl font-semibold text-center" style="line-height: 0.85">{{ $formatNumber(daysInARow) }}</p>
<p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p> <p class="text-sm text-center">{{ $strings.LabelStatsInARow }}</p>
</div> </div>
</div> </div>

View file

@ -78,7 +78,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update collection', error) console.error('Failed to update collection', error)
this.$toast.error(this.$strings.ToastCollectionUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
}, },
editBook(book) { editBook(book) {

View file

@ -92,7 +92,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update playlist', error) console.error('Failed to update playlist', error)
this.$toast.error(this.$strings.ToastPlaylistUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
}, },
init() { init() {

View file

@ -223,7 +223,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to remove item from playlist', error) console.error('Failed to remove item from playlist', error)
this.$toast.error(this.$strings.ToastPlaylistUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.processingRemove = false this.processingRemove = false

View file

@ -65,7 +65,7 @@ export default {
}, },
authors: { authors: {
component: 'cards-author-card', component: 'cards-author-card',
itemPropName: 'author', itemPropName: 'author-mount',
itemIdFunc: (item) => item.id itemIdFunc: (item) => item.id
}, },
narrators: { narrators: {

View file

@ -5,14 +5,14 @@ import Tooltip from '@/components/ui/Tooltip.vue'
import LoadingSpinner from '@/components/widgets/LoadingSpinner.vue' import LoadingSpinner from '@/components/widgets/LoadingSpinner.vue'
describe('AuthorCard', () => { describe('AuthorCard', () => {
const author = { const authorMount = {
id: 1, id: 1,
name: 'John Doe', name: 'John Doe',
numBooks: 5 numBooks: 5
} }
const propsData = { const propsData = {
author, authorMount,
nameBelow: false nameBelow: false
} }

View file

@ -4,6 +4,7 @@ import LazySeriesCard from '@/components/cards/LazySeriesCard'
import LazyCollectionCard from '@/components/cards/LazyCollectionCard' import LazyCollectionCard from '@/components/cards/LazyCollectionCard'
import LazyPlaylistCard from '@/components/cards/LazyPlaylistCard' import LazyPlaylistCard from '@/components/cards/LazyPlaylistCard'
import LazyAlbumCard from '@/components/cards/LazyAlbumCard' import LazyAlbumCard from '@/components/cards/LazyAlbumCard'
import AuthorCard from '@/components/cards/AuthorCard'
export default { export default {
data() { data() {
@ -20,6 +21,7 @@ export default {
if (this.entityName === 'collections') return Vue.extend(LazyCollectionCard) if (this.entityName === 'collections') return Vue.extend(LazyCollectionCard)
if (this.entityName === 'playlists') return Vue.extend(LazyPlaylistCard) if (this.entityName === 'playlists') return Vue.extend(LazyPlaylistCard)
if (this.entityName === 'albums') return Vue.extend(LazyAlbumCard) if (this.entityName === 'albums') return Vue.extend(LazyAlbumCard)
if (this.entityName === 'authors') return Vue.extend(AuthorCard)
return Vue.extend(LazyBookCard) return Vue.extend(LazyBookCard)
}, },
getComponentName() { getComponentName() {
@ -27,6 +29,7 @@ export default {
if (this.entityName === 'collections') return 'cards-lazy-collection-card' if (this.entityName === 'collections') return 'cards-lazy-collection-card'
if (this.entityName === 'playlists') return 'cards-lazy-playlist-card' if (this.entityName === 'playlists') return 'cards-lazy-playlist-card'
if (this.entityName === 'albums') return 'cards-lazy-album-card' if (this.entityName === 'albums') return 'cards-lazy-album-card'
if (this.entityName === 'authors') return 'cards-author-card'
return 'cards-lazy-book-card' return 'cards-lazy-book-card'
}, },
async setCardSize() { async setCardSize() {
@ -46,13 +49,14 @@ export default {
props.orderBy = this.seriesSortBy props.orderBy = this.seriesSortBy
} }
const instance = new ComponentClass({ const instance = new ComponentClass({
propsData: props propsData: props,
parent: this
}) })
instance.$mount() instance.$mount()
this.resizeObserver = new ResizeObserver((entries) => { this.resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) { for (let entry of entries) {
this.cardWidth = entry.contentRect.width this.cardWidth = entry.borderBoxSize[0].inlineSize
this.cardHeight = entry.contentRect.height this.cardHeight = entry.borderBoxSize[0].blockSize
this.resizeObserver.disconnect() this.resizeObserver.disconnect()
this.$refs.bookshelf.removeChild(instance.$el) this.$refs.bookshelf.removeChild(instance.$el)
} }
@ -72,7 +76,7 @@ export default {
}) })
const timeAfter = performance.now() const timeAfter = performance.now()
}, },
async mountEntityCard(index) { mountEntityCard(index) {
var shelf = Math.floor(index / this.entitiesPerShelf) var shelf = Math.floor(index / this.entitiesPerShelf)
var shelfEl = document.getElementById(`shelf-${shelf}`) var shelfEl = document.getElementById(`shelf-${shelf}`)
if (!shelfEl) { if (!shelfEl) {
@ -114,6 +118,7 @@ export default {
const _this = this const _this = this
const instance = new ComponentClass({ const instance = new ComponentClass({
propsData: props, propsData: props,
parent: this,
created() { created() {
this.$on('edit', (entity) => { this.$on('edit', (entity) => {
if (_this.editEntity) _this.editEntity(entity) if (_this.editEntity) _this.editEntity(entity)

View file

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.13.4", "version": "2.14.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf-client", "name": "audiobookshelf-client",
"version": "2.13.4", "version": "2.14.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.13.4", "version": "2.14.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

@ -499,7 +499,7 @@ export default {
.catch((error) => { .catch((error) => {
this.saving = false this.saving = false
console.error('Failed to update chapters', error) console.error('Failed to update chapters', error)
this.$toast.error('Failed to update chapters') this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
}, },
applyChapterNamesOnly() { applyChapterNamesOnly() {

View file

@ -53,7 +53,7 @@ export default {
}) })
if (!author) { if (!author) {
return redirect(`/library/${store.state.libraries.currentLibraryId}/authors`) return redirect(`/library/${store.state.libraries.currentLibraryId}/bookshelf/authors`)
} }
if (store.state.libraries.currentLibraryId !== author.libraryId || !store.state.libraries.filterData) { if (store.state.libraries.currentLibraryId !== author.libraryId || !store.state.libraries.filterData) {
@ -109,7 +109,7 @@ export default {
authorRemoved(author) { authorRemoved(author) {
if (author.id === this.author.id) { if (author.id === this.author.id) {
console.warn('Author was removed') console.warn('Author was removed')
this.$router.replace(`/library/${this.currentLibraryId}/authors`) this.$router.replace(`/library/${this.currentLibraryId}/bookshelf/authors`)
} }
} }
}, },

View file

@ -317,7 +317,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update server settings', error) console.error('Failed to update server settings', error)
this.$toast.error(this.$strings.ToastServerSettingsUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.savingSettings = false this.savingSettings = false

View file

@ -162,7 +162,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to save backup path', error) console.error('Failed to save backup path', error)
const errorMsg = error.response?.data || this.$strings.ToastBackupPathUpdateFailed const errorMsg = error.response?.data || this.$strings.ToastFailedToUpdate
this.$toast.error(errorMsg) this.$toast.error(errorMsg)
}) })
.finally(() => { .finally(() => {

View file

@ -292,7 +292,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update email settings', error) console.error('Failed to update email settings', error)
this.$toast.error(this.$strings.ToastEmailSettingsUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.savingSettings = false this.savingSettings = false

View file

@ -290,7 +290,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update prefixes', error) console.error('Failed to update prefixes', error)
this.$toast.error(this.$strings.ToastSortingPrefixesUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.savingPrefixes = false this.savingPrefixes = false
@ -328,7 +328,6 @@ export default {
.dispatch('updateServerSettings', payload) .dispatch('updateServerSettings', payload)
.then(() => { .then(() => {
this.updatingServerSettings = false this.updatingServerSettings = false
this.$toast.success(this.$strings.ToastServerSettingsUpdateSuccess)
if (payload.language) { if (payload.language) {
// Updating language after save allows for re-rendering // Updating language after save allows for re-rendering
@ -338,7 +337,7 @@ export default {
.catch((error) => { .catch((error) => {
console.error('Failed to update server settings', error) console.error('Failed to update server settings', error)
this.updatingServerSettings = false this.updatingServerSettings = false
this.$toast.error(this.$strings.ToastServerSettingsUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
}, },
initServerSettings() { initServerSettings() {

View file

@ -132,7 +132,7 @@ export default {
}) })
.catch((error) => { .catch((error) => {
console.error('Failed to update notification settings', error) console.error('Failed to update notification settings', error)
this.$toast.error(this.$strings.ToastNotificationSettingsUpdateFailed) this.$toast.error(this.$strings.ToastFailedToUpdate)
}) })
.finally(() => { .finally(() => {
this.savingSettings = false this.savingSettings = false

View file

@ -1,115 +0,0 @@
<template>
<div class="page" :class="streamLibraryItem ? 'streaming' : ''">
<app-book-shelf-toolbar page="authors" is-home :authors="authors" />
<div id="bookshelf" class="w-full h-full p-8e overflow-y-auto" :style="{ fontSize: sizeMultiplier + 'rem' }">
<!-- Cover size widget -->
<widgets-cover-size-widget class="fixed right-4 z-50" :style="{ bottom: streamLibraryItem ? '181px' : '16px' }" />
<div class="flex flex-wrap justify-center">
<template v-for="author in authorsSorted">
<cards-author-card :key="author.id" :author="author" class="p-3e" @edit="editAuthor" />
</template>
</div>
</div>
</div>
</template>
<script>
export default {
async asyncData({ store, params, redirect, query, app }) {
var libraryId = params.library
var libraryData = await store.dispatch('libraries/fetch', libraryId)
if (!libraryData) {
return redirect('/oops?message=Library not found')
}
const library = libraryData.library
if (library.mediaType === 'podcast') {
return redirect(`/library/${libraryId}`)
}
return {
libraryId
}
},
data() {
return {
loading: true,
authors: []
}
},
computed: {
sizeMultiplier() {
return this.$store.getters['user/getSizeMultiplier']
},
streamLibraryItem() {
return this.$store.state.streamLibraryItem
},
currentLibraryId() {
return this.$store.state.libraries.currentLibraryId
},
selectedAuthor() {
return this.$store.state.globals.selectedAuthor
},
authorSortBy() {
return this.$store.getters['user/getUserSetting']('authorSortBy') || 'name'
},
authorSortDesc() {
return !!this.$store.getters['user/getUserSetting']('authorSortDesc')
},
authorsSorted() {
const sortProp = this.authorSortBy
const bDesc = this.authorSortDesc ? -1 : 1
return this.authors.sort((a, b) => {
if (typeof a[sortProp] === 'number' && typeof b[sortProp] === 'number') {
// Fallback to name sort if equal
if (a[sortProp] === b[sortProp]) return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }) * bDesc
return a[sortProp] > b[sortProp] ? bDesc : -bDesc
}
return a[sortProp]?.localeCompare(b[sortProp], undefined, { sensitivity: 'base' }) * bDesc
})
}
},
methods: {
async init() {
this.authors = await this.$axios
.$get(`/api/libraries/${this.currentLibraryId}/authors`)
.then((response) => response.authors)
.catch((error) => {
console.error('Failed to load authors', error)
return []
})
this.loading = false
},
authorAdded(author) {
if (!this.authors.some((au) => au.id === author.id)) {
this.authors.push(author)
}
},
authorUpdated(author) {
this.authors = this.authors.map((au) => {
if (au.id === author.id) {
return author
}
return au
})
},
authorRemoved(author) {
this.authors = this.authors.filter((au) => au.id !== author.id)
},
editAuthor(author) {
this.$store.commit('globals/showEditAuthorModal', author)
}
},
mounted() {
this.init()
this.$root.socket.on('author_added', this.authorAdded)
this.$root.socket.on('author_updated', this.authorUpdated)
this.$root.socket.on('author_removed', this.authorRemoved)
},
beforeDestroy() {
this.$root.socket.off('author_added', this.authorAdded)
this.$root.socket.off('author_updated', this.authorUpdated)
this.$root.socket.off('author_removed', this.authorRemoved)
}
}
</script>

View file

@ -27,7 +27,7 @@ export default {
// Redirect podcast libraries // Redirect podcast libraries
const library = libraryData.library const library = libraryData.library
if (library.mediaType === 'podcast' && (params.id === 'collections' || params.id === 'series')) { if (library.mediaType === 'podcast' && (params.id === 'collections' || params.id === 'series' || params.id === 'authors')) {
return redirect(`/library/${libraryId}`) return redirect(`/library/${libraryId}`)
} }

View file

@ -384,12 +384,6 @@ export default {
else itemsFailed++ else itemsFailed++
this.updateItemCardStatus(item.index, result ? 'success' : 'failed') this.updateItemCardStatus(item.index, result ? 'success' : 'failed')
} }
if (itemsUploaded) {
this.$toast.success(`Successfully uploaded ${itemsUploaded} item${itemsUploaded > 1 ? 's' : ''}`)
}
if (itemsFailed) {
this.$toast.success(`Failed to upload ${itemsFailed} item${itemsFailed > 1 ? 's' : ''}`)
}
this.processing = false this.processing = false
this.uploadFinished = true this.uploadFinished = true
} }

View file

@ -89,10 +89,10 @@ Vue.prototype.$strings = { ...enUsStrings }
* Get string and substitute * Get string and substitute
* *
* @param {string} key * @param {string} key
* @param {string[]} subs * @param {string[]} [subs=[]]
* @returns {string} * @returns {string}
*/ */
Vue.prototype.$getString = (key, subs) => { Vue.prototype.$getString = (key, subs = []) => {
if (!Vue.prototype.$strings[key]) return '' if (!Vue.prototype.$strings[key]) return ''
if (subs?.length && Array.isArray(subs)) { if (subs?.length && Array.isArray(subs)) {
return supplant(Vue.prototype.$strings[key], subs) return supplant(Vue.prototype.$strings[key], subs)

View file

@ -18,7 +18,10 @@ Vue.prototype.$bytesPretty = (bytes, decimals = 2) => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i] return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]
} }
Vue.prototype.$elapsedPretty = (seconds, useFullNames = false) => { Vue.prototype.$elapsedPretty = (seconds, useFullNames = false, useMilliseconds = false) => {
if (useMilliseconds && seconds > 0 && seconds < 1) {
return `${Math.floor(seconds * 1000)} ms`
}
if (seconds < 60) { if (seconds < 60) {
return `${Math.floor(seconds)} sec${useFullNames ? 'onds' : ''}` return `${Math.floor(seconds)} sec${useFullNames ? 'onds' : ''}`
} }

View file

@ -240,7 +240,8 @@ export const mutations = {
series: [], series: [],
narrators: [], narrators: [],
languages: [], languages: [],
publishers: [] publishers: [],
publishedDecades: []
} }
*/ */
const mediaMetadata = libraryItem.media.metadata const mediaMetadata = libraryItem.media.metadata
@ -307,6 +308,16 @@ export const mutations = {
state.filterData.publishers.sort((a, b) => a.localeCompare(b)) state.filterData.publishers.sort((a, b) => a.localeCompare(b))
} }
// Add publishedDecades
if (mediaMetadata.publishedYear) {
const publishedYear = parseInt(mediaMetadata.publishedYear, 10)
const decade = Math.floor(publishedYear / 10) * 10
if (!state.filterData.publishedDecades.includes(decade)) {
state.filterData.publishedDecades.push(decade)
state.filterData.publishedDecades.sort((a, b) => a - b)
}
}
// Add language // Add language
if (mediaMetadata.language && !state.filterData.languages.includes(mediaMetadata.language)) { if (mediaMetadata.language && !state.filterData.languages.includes(mediaMetadata.language)) {
state.filterData.languages.push(mediaMetadata.language) state.filterData.languages.push(mediaMetadata.language)

View file

@ -90,7 +90,7 @@ export const actions = {
if (state.settings.orderBy == 'media.metadata.publishedYear') { if (state.settings.orderBy == 'media.metadata.publishedYear') {
settingsUpdate.orderBy = 'media.metadata.title' settingsUpdate.orderBy = 'media.metadata.title'
} }
const invalidFilters = ['series', 'authors', 'narrators', 'publishers', 'languages', 'progress', 'issues', 'ebooks', 'abridged'] const invalidFilters = ['series', 'authors', 'narrators', 'publishers', 'publishedDecades', 'languages', 'progress', 'issues', 'ebooks', 'abridged']
const filterByFirstPart = (state.settings.filterBy || '').split('.').shift() const filterByFirstPart = (state.settings.filterBy || '').split('.').shift()
if (invalidFilters.includes(filterByFirstPart)) { if (invalidFilters.includes(filterByFirstPart)) {
settingsUpdate.filterBy = 'all' settingsUpdate.filterBy = 'all'

View file

@ -711,10 +711,8 @@
"PlaceholderNewPlaylist": "Ново име на плейлиста", "PlaceholderNewPlaylist": "Ново име на плейлиста",
"PlaceholderSearch": "Търсене...", "PlaceholderSearch": "Търсене...",
"PlaceholderSearchEpisode": "Търсене на Епизоди...", "PlaceholderSearchEpisode": "Търсене на Епизоди...",
"ToastAccountUpdateFailed": "Неуспешно обновяване на акаунта",
"ToastAccountUpdateSuccess": "Успешно обновяване на акаунта", "ToastAccountUpdateSuccess": "Успешно обновяване на акаунта",
"ToastAuthorImageRemoveSuccess": "Авторската снимка е премахната", "ToastAuthorImageRemoveSuccess": "Авторската снимка е премахната",
"ToastAuthorUpdateFailed": "Неуспешно обновяване на автора",
"ToastAuthorUpdateMerged": "Обновяване на автора сливано", "ToastAuthorUpdateMerged": "Обновяване на автора сливано",
"ToastAuthorUpdateSuccess": "Автора обновен", "ToastAuthorUpdateSuccess": "Автора обновен",
"ToastAuthorUpdateSuccessNoImageFound": "Автор обновен (не е намерена снимка)", "ToastAuthorUpdateSuccessNoImageFound": "Автор обновен (не е намерена снимка)",
@ -728,17 +726,13 @@
"ToastBookmarkCreateFailed": "Неуспешно създаване на отметка", "ToastBookmarkCreateFailed": "Неуспешно създаване на отметка",
"ToastBookmarkCreateSuccess": "Отметката е създадена", "ToastBookmarkCreateSuccess": "Отметката е създадена",
"ToastBookmarkRemoveSuccess": "Отметката е премахната", "ToastBookmarkRemoveSuccess": "Отметката е премахната",
"ToastBookmarkUpdateFailed": "Неуспешно обновяване на отметка",
"ToastBookmarkUpdateSuccess": "Отметката е обновена", "ToastBookmarkUpdateSuccess": "Отметката е обновена",
"ToastChaptersHaveErrors": "Главите имат грешки", "ToastChaptersHaveErrors": "Главите имат грешки",
"ToastChaptersMustHaveTitles": "Главите трябва да имат заглавия", "ToastChaptersMustHaveTitles": "Главите трябва да имат заглавия",
"ToastCollectionItemsRemoveSuccess": "Елемент(и) премахнати от колекция", "ToastCollectionItemsRemoveSuccess": "Елемент(и) премахнати от колекция",
"ToastCollectionRemoveSuccess": "Колекцията е премахната", "ToastCollectionRemoveSuccess": "Колекцията е премахната",
"ToastCollectionUpdateFailed": "Неуспешно обновяване на колекция",
"ToastCollectionUpdateSuccess": "Колекцията е обновена", "ToastCollectionUpdateSuccess": "Колекцията е обновена",
"ToastItemCoverUpdateFailed": "Неуспешно обновяване на корица на елемент",
"ToastItemCoverUpdateSuccess": "Корицата на елемента е обновена", "ToastItemCoverUpdateSuccess": "Корицата на елемента е обновена",
"ToastItemDetailsUpdateFailed": "Неуспешно обновяване на детайли на елемент",
"ToastItemDetailsUpdateSuccess": "Детайлите на елемента са обновени", "ToastItemDetailsUpdateSuccess": "Детайлите на елемента са обновени",
"ToastItemMarkedAsFinishedFailed": "Неуспешно маркиране като завършено", "ToastItemMarkedAsFinishedFailed": "Неуспешно маркиране като завършено",
"ToastItemMarkedAsFinishedSuccess": "Елементът е маркиран като завършен", "ToastItemMarkedAsFinishedSuccess": "Елементът е маркиран като завършен",
@ -750,12 +744,10 @@
"ToastLibraryDeleteSuccess": "Библиотеката е изтрита", "ToastLibraryDeleteSuccess": "Библиотеката е изтрита",
"ToastLibraryScanFailedToStart": "Неуспешно стартиране на сканиране", "ToastLibraryScanFailedToStart": "Неуспешно стартиране на сканиране",
"ToastLibraryScanStarted": "Сканирането на библиотеката е стартирано", "ToastLibraryScanStarted": "Сканирането на библиотеката е стартирано",
"ToastLibraryUpdateFailed": "Неуспешно обновяване на библиотека",
"ToastLibraryUpdateSuccess": "Библиотеката \"{0}\" е обновена", "ToastLibraryUpdateSuccess": "Библиотеката \"{0}\" е обновена",
"ToastPlaylistCreateFailed": "Неуспешно създаване на плейлист", "ToastPlaylistCreateFailed": "Неуспешно създаване на плейлист",
"ToastPlaylistCreateSuccess": "Плейлистът е създаден", "ToastPlaylistCreateSuccess": "Плейлистът е създаден",
"ToastPlaylistRemoveSuccess": "Плейлистът е премахнат", "ToastPlaylistRemoveSuccess": "Плейлистът е премахнат",
"ToastPlaylistUpdateFailed": "Неуспешно обновяване на плейлист",
"ToastPlaylistUpdateSuccess": "Плейлистът е обновен", "ToastPlaylistUpdateSuccess": "Плейлистът е обновен",
"ToastPodcastCreateFailed": "Неуспешно създаване на подкаст", "ToastPodcastCreateFailed": "Неуспешно създаване на подкаст",
"ToastPodcastCreateSuccess": "Подкастът е създаден", "ToastPodcastCreateSuccess": "Подкастът е създаден",

View file

@ -8,7 +8,7 @@
"ButtonAddYourFirstLibrary": "আপনার প্রথম লাইব্রেরি যোগ করুন", "ButtonAddYourFirstLibrary": "আপনার প্রথম লাইব্রেরি যোগ করুন",
"ButtonApply": "প্রয়োগ করুন", "ButtonApply": "প্রয়োগ করুন",
"ButtonApplyChapters": "অধ্যায় প্রয়োগ করুন", "ButtonApplyChapters": "অধ্যায় প্রয়োগ করুন",
"ButtonAuthors": "লেখক", "ButtonAuthors": "লেখকগণ",
"ButtonBack": "পেছনে যান", "ButtonBack": "পেছনে যান",
"ButtonBrowseForFolder": "ফোল্ডারের জন্য ব্রাউজ করুন", "ButtonBrowseForFolder": "ফোল্ডারের জন্য ব্রাউজ করুন",
"ButtonCancel": "বাতিল করুন", "ButtonCancel": "বাতিল করুন",
@ -56,6 +56,7 @@
"ButtonOpenManager": "ম্যানেজার খুলুন", "ButtonOpenManager": "ম্যানেজার খুলুন",
"ButtonPause": "বিরতি", "ButtonPause": "বিরতি",
"ButtonPlay": "বাজান", "ButtonPlay": "বাজান",
"ButtonPlayAll": "সব চালান",
"ButtonPlaying": "বাজছে", "ButtonPlaying": "বাজছে",
"ButtonPlaylists": "প্লেলিস্ট", "ButtonPlaylists": "প্লেলিস্ট",
"ButtonPrevious": "পূর্ববর্তী", "ButtonPrevious": "পূর্ববর্তী",
@ -702,7 +703,7 @@
"MessageEpisodesQueuedForDownload": "{0} পর্ব(গুলি) ডাউনলোডের জন্য সারিবদ্ধ", "MessageEpisodesQueuedForDownload": "{0} পর্ব(গুলি) ডাউনলোডের জন্য সারিবদ্ধ",
"MessageEreaderDevices": "ই-বুক সরবরাহ নিশ্চিত করতে, আপনাকে নীচে তালিকাভুক্ত প্রতিটি ডিভাইসের জন্য একটি বৈধ প্রেরক হিসাবে উপরের ইমেল ঠিকানাটি যুক্ত করতে হতে পারে।", "MessageEreaderDevices": "ই-বুক সরবরাহ নিশ্চিত করতে, আপনাকে নীচে তালিকাভুক্ত প্রতিটি ডিভাইসের জন্য একটি বৈধ প্রেরক হিসাবে উপরের ইমেল ঠিকানাটি যুক্ত করতে হতে পারে।",
"MessageFeedURLWillBe": "ফিড URL হবে {0}", "MessageFeedURLWillBe": "ফিড URL হবে {0}",
"MessageFetching": "আনয় হচ্ছে...", "MessageFetching": "আনয় হচ্ছে.",
"MessageForceReScanDescription": "সকল ফাইল আবার নতুন স্ক্যানের মত স্ক্যান করবে। অডিও ফাইল ID3 ট্যাগ, OPF ফাইল, এবং টেক্সট ফাইলগুলি নতুন হিসাবে স্ক্যান করা হবে।", "MessageForceReScanDescription": "সকল ফাইল আবার নতুন স্ক্যানের মত স্ক্যান করবে। অডিও ফাইল ID3 ট্যাগ, OPF ফাইল, এবং টেক্সট ফাইলগুলি নতুন হিসাবে স্ক্যান করা হবে।",
"MessageImportantNotice": "গুরুত্বপূর্ণ বিজ্ঞপ্তি!", "MessageImportantNotice": "গুরুত্বপূর্ণ বিজ্ঞপ্তি!",
"MessageInsertChapterBelow": "নীচে অধ্যায় ঢোকান", "MessageInsertChapterBelow": "নীচে অধ্যায় ঢোকান",
@ -710,7 +711,7 @@
"MessageItemsUpdated": "{0}টি আইটেম আপডেট করা হয়েছে", "MessageItemsUpdated": "{0}টি আইটেম আপডেট করা হয়েছে",
"MessageJoinUsOn": "আমাদের সাথে যোগ দিন", "MessageJoinUsOn": "আমাদের সাথে যোগ দিন",
"MessageListeningSessionsInTheLastYear": "গত বছরে {0}টি শোনার সেশন", "MessageListeningSessionsInTheLastYear": "গত বছরে {0}টি শোনার সেশন",
"MessageLoading": "লোড হচ্ছে...", "MessageLoading": "লোড হচ্ছে.",
"MessageLoadingFolders": "ফোল্ডার লোড হচ্ছে...", "MessageLoadingFolders": "ফোল্ডার লোড হচ্ছে...",
"MessageLogsDescription": "লগগুলি JSON ফাইল হিসাবে <code>/metadata/logs</code>-এ সংরক্ষণ করা হয়। ক্র্যাশ লগগুলি <code>/metadata/logs/crash_logs.txt</code>-এ সংরক্ষণ করা হয়।", "MessageLogsDescription": "লগগুলি JSON ফাইল হিসাবে <code>/metadata/logs</code>-এ সংরক্ষণ করা হয়। ক্র্যাশ লগগুলি <code>/metadata/logs/crash_logs.txt</code>-এ সংরক্ষণ করা হয়।",
"MessageM4BFailed": "M4B ব্যর্থ!", "MessageM4BFailed": "M4B ব্যর্থ!",
@ -776,6 +777,38 @@
"MessageShareExpiresIn": "মেয়াদ শেষ হবে {0}", "MessageShareExpiresIn": "মেয়াদ শেষ হবে {0}",
"MessageShareURLWillBe": "শেয়ার করা ইউআরএল হবে <strong>{0}</strong>", "MessageShareURLWillBe": "শেয়ার করা ইউআরএল হবে <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "\"{0}\" এর জন্য {1} এ প্লেব্যাক শুরু করবেন?", "MessageStartPlaybackAtTime": "\"{0}\" এর জন্য {1} এ প্লেব্যাক শুরু করবেন?",
"MessageTaskAudioFileNotWritable": "অডিও ফাইল \"{0}\" লেখার যোগ্য নয়",
"MessageTaskCanceledByUser": "ব্যবহারকারী দ্বারা টাস্ক বাতিল করা হয়েছে",
"MessageTaskDownloadingEpisodeDescription": "\"{0}\" পর্ব ডাউনলোড করা হচ্ছে",
"MessageTaskEmbeddingMetadata": "মেটাডেটা এম্বেড করা হচ্ছে",
"MessageTaskEmbeddingMetadataDescription": "অডিওবুক \"{0}\" এ মেটাডেটা এম্বেড করা হচ্ছে",
"MessageTaskEncodingM4b": "এনকোডিং M4B",
"MessageTaskEncodingM4bDescription": "একটি একক m4b ফাইলে অডিওবুক \"{0}\" এনকোড করা হচ্ছে",
"MessageTaskFailed": "ব্যর্থ হয়েছে",
"MessageTaskFailedToBackupAudioFile": "অডিও ফাইল \"{0}\" ব্যাকআপ করতে ব্যর্থ হয়েছে",
"MessageTaskFailedToCreateCacheDirectory": "ক্যাশে ডিরেক্টরি তৈরি করতে ব্যর্থ হয়েছে",
"MessageTaskFailedToEmbedMetadataInFile": "\"{0}\" ফাইলে মেটাডেটা এম্বেড করতে ব্যর্থ হয়েছে",
"MessageTaskFailedToMergeAudioFiles": "অডিও ফাইল মার্জ করতে ব্যর্থ হয়েছে",
"MessageTaskFailedToMoveM4bFile": "m4b ফাইল সরাতে ব্যর্থ হয়েছে",
"MessageTaskFailedToWriteMetadataFile": "মেটাডেটা ফাইল লিখতে ব্যর্থ হয়েছে",
"MessageTaskMatchingBooksInLibrary": "লাইব্রেরি \"{0}\"-এ বই মিলানো হচ্ছে",
"MessageTaskNoFilesToScan": "স্ক্যান করার জন্য কোন ফাইল নেই",
"MessageTaskOpmlImport": "OPML আমদানি",
"MessageTaskOpmlImportDescription": "{0} RSS ফিড থেকে পডকাস্ট তৈরি করা হচ্ছে",
"MessageTaskOpmlImportFeed": "OPML ফিড আমদানি",
"MessageTaskOpmlImportFeedDescription": "RSS ফিড \"{0}\" আমদানি করা হচ্ছে",
"MessageTaskOpmlImportFeedFailed": "পডকাস্ট ফিড পেতে ব্যর্থ হয়েছে",
"MessageTaskOpmlImportFeedPodcastDescription": "পডকাস্ট তৈরি করা হচ্ছে \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "পডকাস্ট আগে থেকেই পাথে বিদ্যমান",
"MessageTaskOpmlImportFeedPodcastFailed": "পডকাস্ট তৈরি করতে ব্যর্থ",
"MessageTaskOpmlImportFinished": "{0}টি পডকাস্ট যোগ করা হয়েছে",
"MessageTaskScanItemsAdded": "{0}টি করা হয়েছে",
"MessageTaskScanItemsMissing": "{0}টি অনুপস্থিত",
"MessageTaskScanItemsUpdated": "{0} টি আপডেট করা হয়েছে",
"MessageTaskScanNoChangesNeeded": "কোন পরিবর্তন প্রয়োজন নেই",
"MessageTaskScanningFileChanges": "\"{0}\" এ ফাইলের পরিবর্তন স্ক্যান করা হচ্ছে",
"MessageTaskScanningLibrary": "\"{0}\" লাইব্রেরি স্ক্যান করা হচ্ছে",
"MessageTaskTargetDirectoryNotWritable": "টার্গেট ডিরেক্টরি লেখার যোগ্য নয়",
"MessageThinking": "চিন্তা করছি...", "MessageThinking": "চিন্তা করছি...",
"MessageUploaderItemFailed": "আপলোড করতে ব্যর্থ", "MessageUploaderItemFailed": "আপলোড করতে ব্যর্থ",
"MessageUploaderItemSuccess": "সফলভাবে আপলোড হয়েছে!", "MessageUploaderItemSuccess": "সফলভাবে আপলোড হয়েছে!",
@ -816,14 +849,12 @@
"StatsTopNarrators": "শীর্ষ কথকগণ", "StatsTopNarrators": "শীর্ষ কথকগণ",
"StatsTotalDuration": "মোট সময়কাল…", "StatsTotalDuration": "মোট সময়কাল…",
"StatsYearInReview": "বাৎসরিক পর্যালোচনা", "StatsYearInReview": "বাৎসরিক পর্যালোচনা",
"ToastAccountUpdateFailed": "অ্যাকাউন্ট আপডেট করতে ব্যর্থ",
"ToastAccountUpdateSuccess": "অ্যাকাউন্ট আপডেট করা হয়েছে", "ToastAccountUpdateSuccess": "অ্যাকাউন্ট আপডেট করা হয়েছে",
"ToastAppriseUrlRequired": "একটি Apprise ইউআরএল লিখতে হবে", "ToastAppriseUrlRequired": "একটি Apprise ইউআরএল লিখতে হবে",
"ToastAuthorImageRemoveSuccess": "লেখকের ছবি সরানো হয়েছে", "ToastAuthorImageRemoveSuccess": "লেখকের ছবি সরানো হয়েছে",
"ToastAuthorNotFound": "লেখক \"{0}\" খুঁজে পাওয়া যায়নি", "ToastAuthorNotFound": "লেখক \"{0}\" খুঁজে পাওয়া যায়নি",
"ToastAuthorRemoveSuccess": "লেখক সরানো হয়েছে", "ToastAuthorRemoveSuccess": "লেখক সরানো হয়েছে",
"ToastAuthorSearchNotFound": "লেখক পাওয়া যায়নি", "ToastAuthorSearchNotFound": "লেখক পাওয়া যায়নি",
"ToastAuthorUpdateFailed": "লেখক আপডেট করতে ব্যর্থ",
"ToastAuthorUpdateMerged": "লেখক একত্রিত হয়েছে", "ToastAuthorUpdateMerged": "লেখক একত্রিত হয়েছে",
"ToastAuthorUpdateSuccess": "লেখক আপডেট করেছেন", "ToastAuthorUpdateSuccess": "লেখক আপডেট করেছেন",
"ToastAuthorUpdateSuccessNoImageFound": "লেখক আপডেট করেছেন (কোন ছবি পাওয়া যায়নি)", "ToastAuthorUpdateSuccessNoImageFound": "লেখক আপডেট করেছেন (কোন ছবি পাওয়া যায়নি)",
@ -834,7 +865,6 @@
"ToastBackupDeleteSuccess": "ব্যাকআপ মুছে ফেলা হয়েছে", "ToastBackupDeleteSuccess": "ব্যাকআপ মুছে ফেলা হয়েছে",
"ToastBackupInvalidMaxKeep": "রাখার জন্য অকার্যকর ব্যাকআপের সংখ্যা", "ToastBackupInvalidMaxKeep": "রাখার জন্য অকার্যকর ব্যাকআপের সংখ্যা",
"ToastBackupInvalidMaxSize": "অকার্যকর সর্বোচ্চ ব্যাকআপ আকার", "ToastBackupInvalidMaxSize": "অকার্যকর সর্বোচ্চ ব্যাকআপ আকার",
"ToastBackupPathUpdateFailed": "ব্যাকআপ পথ আপডেট করতে ব্যর্থ হয়েছে",
"ToastBackupRestoreFailed": "ব্যাকআপ পুনরুদ্ধার করতে ব্যর্থ", "ToastBackupRestoreFailed": "ব্যাকআপ পুনরুদ্ধার করতে ব্যর্থ",
"ToastBackupUploadFailed": "ব্যাকআপ আপলোড করতে ব্যর্থ", "ToastBackupUploadFailed": "ব্যাকআপ আপলোড করতে ব্যর্থ",
"ToastBackupUploadSuccess": "ব্যাকআপ আপলোড হয়েছে", "ToastBackupUploadSuccess": "ব্যাকআপ আপলোড হয়েছে",
@ -845,7 +875,6 @@
"ToastBookmarkCreateFailed": "বুকমার্ক তৈরি করতে ব্যর্থ", "ToastBookmarkCreateFailed": "বুকমার্ক তৈরি করতে ব্যর্থ",
"ToastBookmarkCreateSuccess": "বুকমার্ক যোগ করা হয়েছে", "ToastBookmarkCreateSuccess": "বুকমার্ক যোগ করা হয়েছে",
"ToastBookmarkRemoveSuccess": "বুকমার্ক সরানো হয়েছে", "ToastBookmarkRemoveSuccess": "বুকমার্ক সরানো হয়েছে",
"ToastBookmarkUpdateFailed": "বুকমার্ক আপডেট করতে ব্যর্থ",
"ToastBookmarkUpdateSuccess": "বুকমার্ক আপডেট করা হয়েছে", "ToastBookmarkUpdateSuccess": "বুকমার্ক আপডেট করা হয়েছে",
"ToastCachePurgeFailed": "ক্যাশে পরিষ্কার করতে ব্যর্থ হয়েছে", "ToastCachePurgeFailed": "ক্যাশে পরিষ্কার করতে ব্যর্থ হয়েছে",
"ToastCachePurgeSuccess": "ক্যাশে সফলভাবে পরিষ্কার করা হয়েছে", "ToastCachePurgeSuccess": "ক্যাশে সফলভাবে পরিষ্কার করা হয়েছে",
@ -856,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "আইটেম(গুলি) সংগ্রহে যোগ করা সফল হয়েছে", "ToastCollectionItemsAddSuccess": "আইটেম(গুলি) সংগ্রহে যোগ করা সফল হয়েছে",
"ToastCollectionItemsRemoveSuccess": "আইটেম(গুলি) সংগ্রহ থেকে সরানো হয়েছে", "ToastCollectionItemsRemoveSuccess": "আইটেম(গুলি) সংগ্রহ থেকে সরানো হয়েছে",
"ToastCollectionRemoveSuccess": "সংগ্রহ সরানো হয়েছে", "ToastCollectionRemoveSuccess": "সংগ্রহ সরানো হয়েছে",
"ToastCollectionUpdateFailed": "সংগ্রহ আপডেট করতে ব্যর্থ",
"ToastCollectionUpdateSuccess": "সংগ্রহ আপডেট করা হয়েছে", "ToastCollectionUpdateSuccess": "সংগ্রহ আপডেট করা হয়েছে",
"ToastCoverUpdateFailed": "কভার আপডেট ব্যর্থ হয়েছে", "ToastCoverUpdateFailed": "কভার আপডেট ব্যর্থ হয়েছে",
"ToastDeleteFileFailed": "ফাইল মুছে ফেলতে ব্যর্থ হয়েছে", "ToastDeleteFileFailed": "ফাইল মুছে ফেলতে ব্যর্থ হয়েছে",
@ -865,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "এই নামের ইরিডার ডিভাইস ইতিমধ্যেই বিদ্যমান", "ToastDeviceNameAlreadyExists": "এই নামের ইরিডার ডিভাইস ইতিমধ্যেই বিদ্যমান",
"ToastDeviceTestEmailFailed": "পরীক্ষামূলক ইমেল পাঠাতে ব্যর্থ হয়েছে", "ToastDeviceTestEmailFailed": "পরীক্ষামূলক ইমেল পাঠাতে ব্যর্থ হয়েছে",
"ToastDeviceTestEmailSuccess": "পরীক্ষামূলক ইমেল পাঠানো হয়েছে", "ToastDeviceTestEmailSuccess": "পরীক্ষামূলক ইমেল পাঠানো হয়েছে",
"ToastDeviceUpdateFailed": "ডিভাইস আপডেট করতে ব্যর্থ হয়েছে",
"ToastEmailSettingsUpdateFailed": "ইমেল সেটিংস আপডেট করতে ব্যর্থ হয়েছে",
"ToastEmailSettingsUpdateSuccess": "ইমেল সেটিংস আপডেট করা হয়েছে", "ToastEmailSettingsUpdateSuccess": "ইমেল সেটিংস আপডেট করা হয়েছে",
"ToastEncodeCancelFailed": "এনকোড বাতিল করতে ব্যর্থ হয়েছে", "ToastEncodeCancelFailed": "এনকোড বাতিল করতে ব্যর্থ হয়েছে",
"ToastEncodeCancelSucces": "এনকোড বাতিল করা হয়েছে", "ToastEncodeCancelSucces": "এনকোড বাতিল করা হয়েছে",
@ -875,21 +901,16 @@
"ToastErrorCannotShare": "এই ডিভাইসে স্থানীয়ভাবে শেয়ার করা যাবে না", "ToastErrorCannotShare": "এই ডিভাইসে স্থানীয়ভাবে শেয়ার করা যাবে না",
"ToastFailedToLoadData": "ডেটা লোড করা যায়নি", "ToastFailedToLoadData": "ডেটা লোড করা যায়নি",
"ToastFailedToShare": "শেয়ার করতে ব্যর্থ", "ToastFailedToShare": "শেয়ার করতে ব্যর্থ",
"ToastFailedToUpdateAccount": "অ্যাকাউন্ট আপডেট করতে ব্যর্থ",
"ToastFailedToUpdateUser": "ব্যবহারকারী আপডেট করতে ব্যর্থ",
"ToastInvalidImageUrl": "অকার্যকর ছবির ইউআরএল", "ToastInvalidImageUrl": "অকার্যকর ছবির ইউআরএল",
"ToastInvalidUrl": "অকার্যকর ইউআরএল", "ToastInvalidUrl": "অকার্যকর ইউআরএল",
"ToastItemCoverUpdateFailed": "আইটেম কভার আপডেট করতে ব্যর্থ হয়েছে",
"ToastItemCoverUpdateSuccess": "আইটেম কভার আপডেট করা হয়েছে", "ToastItemCoverUpdateSuccess": "আইটেম কভার আপডেট করা হয়েছে",
"ToastItemDeletedFailed": "আইটেম মুছে ফেলতে ব্যর্থ", "ToastItemDeletedFailed": "আইটেম মুছে ফেলতে ব্যর্থ",
"ToastItemDeletedSuccess": "মুছে ফেলা আইটেম", "ToastItemDeletedSuccess": "মুছে ফেলা আইটেম",
"ToastItemDetailsUpdateFailed": "আইটেমের বিবরণ আপডেট করতে ব্যর্থ",
"ToastItemDetailsUpdateSuccess": "আইটেমের বিবরণ আপডেট করা হয়েছে", "ToastItemDetailsUpdateSuccess": "আইটেমের বিবরণ আপডেট করা হয়েছে",
"ToastItemMarkedAsFinishedFailed": "সমাপ্ত হিসাবে চিহ্নিত করতে ব্যর্থ", "ToastItemMarkedAsFinishedFailed": "সমাপ্ত হিসাবে চিহ্নিত করতে ব্যর্থ",
"ToastItemMarkedAsFinishedSuccess": "আইটেম সমাপ্ত হিসাবে চিহ্নিত", "ToastItemMarkedAsFinishedSuccess": "আইটেম সমাপ্ত হিসাবে চিহ্নিত",
"ToastItemMarkedAsNotFinishedFailed": "সমাপ্ত হয়নি হিসাবে চিহ্নিত করতে ব্যর্থ", "ToastItemMarkedAsNotFinishedFailed": "সমাপ্ত হয়নি হিসাবে চিহ্নিত করতে ব্যর্থ",
"ToastItemMarkedAsNotFinishedSuccess": "আইটেম সমাপ্ত হয়নি বলে চিহ্নিত", "ToastItemMarkedAsNotFinishedSuccess": "আইটেম সমাপ্ত হয়নি বলে চিহ্নিত",
"ToastItemUpdateFailed": "আইটেম আপডেট করতে ব্যর্থ",
"ToastItemUpdateSuccess": "আইটেম আপডেট করা হয়েছে", "ToastItemUpdateSuccess": "আইটেম আপডেট করা হয়েছে",
"ToastLibraryCreateFailed": "লাইব্রেরি তৈরি করতে ব্যর্থ", "ToastLibraryCreateFailed": "লাইব্রেরি তৈরি করতে ব্যর্থ",
"ToastLibraryCreateSuccess": "লাইব্রেরি \"{0}\" তৈরি করা হয়েছে", "ToastLibraryCreateSuccess": "লাইব্রেরি \"{0}\" তৈরি করা হয়েছে",
@ -897,7 +918,6 @@
"ToastLibraryDeleteSuccess": "লাইব্রেরি মুছে ফেলা হয়েছে", "ToastLibraryDeleteSuccess": "লাইব্রেরি মুছে ফেলা হয়েছে",
"ToastLibraryScanFailedToStart": "স্ক্যান শুরু করতে ব্যর্থ", "ToastLibraryScanFailedToStart": "স্ক্যান শুরু করতে ব্যর্থ",
"ToastLibraryScanStarted": "লাইব্রেরি স্ক্যান শুরু হয়েছে", "ToastLibraryScanStarted": "লাইব্রেরি স্ক্যান শুরু হয়েছে",
"ToastLibraryUpdateFailed": "লাইব্রেরি আপডেট করতে ব্যর্থ",
"ToastLibraryUpdateSuccess": "লাইব্রেরি \"{0}\" আপডেট করা হয়েছে", "ToastLibraryUpdateSuccess": "লাইব্রেরি \"{0}\" আপডেট করা হয়েছে",
"ToastNameEmailRequired": "নাম এবং ইমেইল আবশ্যক", "ToastNameEmailRequired": "নাম এবং ইমেইল আবশ্যক",
"ToastNameRequired": "নাম আবশ্যক", "ToastNameRequired": "নাম আবশ্যক",
@ -912,16 +932,13 @@
"ToastNotificationDeleteFailed": "বিজ্ঞপ্তি মুছে ফেলতে ব্যর্থ", "ToastNotificationDeleteFailed": "বিজ্ঞপ্তি মুছে ফেলতে ব্যর্থ",
"ToastNotificationFailedMaximum": "সর্বাধিক ব্যর্থ প্রচেষ্টা >= 0 হতে হবে", "ToastNotificationFailedMaximum": "সর্বাধিক ব্যর্থ প্রচেষ্টা >= 0 হতে হবে",
"ToastNotificationQueueMaximum": "সর্বাধিক বিজ্ঞপ্তি সারি >= 0 হতে হবে", "ToastNotificationQueueMaximum": "সর্বাধিক বিজ্ঞপ্তি সারি >= 0 হতে হবে",
"ToastNotificationSettingsUpdateFailed": "বিজ্ঞপ্তি সেটিংস আপডেট করতে ব্যর্থ",
"ToastNotificationSettingsUpdateSuccess": "বিজ্ঞপ্তি সেটিংস আপডেট করা হয়েছে", "ToastNotificationSettingsUpdateSuccess": "বিজ্ঞপ্তি সেটিংস আপডেট করা হয়েছে",
"ToastNotificationTestTriggerFailed": "পরীক্ষামূলক বিজ্ঞপ্তি ট্রিগার করতে ব্যর্থ হয়েছে", "ToastNotificationTestTriggerFailed": "পরীক্ষামূলক বিজ্ঞপ্তি ট্রিগার করতে ব্যর্থ হয়েছে",
"ToastNotificationTestTriggerSuccess": "পরীক্ষামুলক বিজ্ঞপ্তি ট্রিগার হয়েছে", "ToastNotificationTestTriggerSuccess": "পরীক্ষামুলক বিজ্ঞপ্তি ট্রিগার হয়েছে",
"ToastNotificationUpdateFailed": "বিজ্ঞপ্তি আপডেট করতে ব্যর্থ",
"ToastNotificationUpdateSuccess": "বিজ্ঞপ্তি আপডেট হয়েছে", "ToastNotificationUpdateSuccess": "বিজ্ঞপ্তি আপডেট হয়েছে",
"ToastPlaylistCreateFailed": "প্লেলিস্ট তৈরি করতে ব্যর্থ", "ToastPlaylistCreateFailed": "প্লেলিস্ট তৈরি করতে ব্যর্থ",
"ToastPlaylistCreateSuccess": "প্লেলিস্ট তৈরি করা হয়েছে", "ToastPlaylistCreateSuccess": "প্লেলিস্ট তৈরি করা হয়েছে",
"ToastPlaylistRemoveSuccess": "প্লেলিস্ট সরানো হয়েছে", "ToastPlaylistRemoveSuccess": "প্লেলিস্ট সরানো হয়েছে",
"ToastPlaylistUpdateFailed": "প্লেলিস্ট আপডেট করতে ব্যর্থ",
"ToastPlaylistUpdateSuccess": "প্লেলিস্ট আপডেট করা হয়েছে", "ToastPlaylistUpdateSuccess": "প্লেলিস্ট আপডেট করা হয়েছে",
"ToastPodcastCreateFailed": "পডকাস্ট তৈরি করতে ব্যর্থ", "ToastPodcastCreateFailed": "পডকাস্ট তৈরি করতে ব্যর্থ",
"ToastPodcastCreateSuccess": "পডকাস্ট সফলভাবে তৈরি করা হয়েছে", "ToastPodcastCreateSuccess": "পডকাস্ট সফলভাবে তৈরি করা হয়েছে",
@ -950,7 +967,6 @@
"ToastSendEbookToDeviceSuccess": "ইবুক \"{0}\" ডিভাইসে পাঠানো হয়েছে", "ToastSendEbookToDeviceSuccess": "ইবুক \"{0}\" ডিভাইসে পাঠানো হয়েছে",
"ToastSeriesUpdateFailed": "সিরিজ আপডেট ব্যর্থ হয়েছে", "ToastSeriesUpdateFailed": "সিরিজ আপডেট ব্যর্থ হয়েছে",
"ToastSeriesUpdateSuccess": "সিরিজ আপডেট সাফল্য", "ToastSeriesUpdateSuccess": "সিরিজ আপডেট সাফল্য",
"ToastServerSettingsUpdateFailed": "সার্ভার সেটিংস আপডেট করতে ব্যর্থ হয়েছে",
"ToastServerSettingsUpdateSuccess": "সার্ভার সেটিংস আপডেট করা হয়েছে", "ToastServerSettingsUpdateSuccess": "সার্ভার সেটিংস আপডেট করা হয়েছে",
"ToastSessionCloseFailed": "অধিবেশন বন্ধ করতে ব্যর্থ হয়েছে", "ToastSessionCloseFailed": "অধিবেশন বন্ধ করতে ব্যর্থ হয়েছে",
"ToastSessionDeleteFailed": "সেশন মুছে ফেলতে ব্যর্থ", "ToastSessionDeleteFailed": "সেশন মুছে ফেলতে ব্যর্থ",
@ -961,7 +977,6 @@
"ToastSocketDisconnected": "সকেট সংযোগ বিচ্ছিন্ন", "ToastSocketDisconnected": "সকেট সংযোগ বিচ্ছিন্ন",
"ToastSocketFailedToConnect": "সকেট সংযোগ করতে ব্যর্থ হয়েছে", "ToastSocketFailedToConnect": "সকেট সংযোগ করতে ব্যর্থ হয়েছে",
"ToastSortingPrefixesEmptyError": "কমপক্ষে ১ টি সাজানোর উপসর্গ থাকতে হবে", "ToastSortingPrefixesEmptyError": "কমপক্ষে ১ টি সাজানোর উপসর্গ থাকতে হবে",
"ToastSortingPrefixesUpdateFailed": "বাছাই উপসর্গ আপডেট করতে ব্যর্থ হয়েছে",
"ToastSortingPrefixesUpdateSuccess": "বাছাই করা উপসর্গ আপডেট করা হয়েছে ({0}টি আইটেম)", "ToastSortingPrefixesUpdateSuccess": "বাছাই করা উপসর্গ আপডেট করা হয়েছে ({0}টি আইটেম)",
"ToastTitleRequired": "শিরোনাম আবশ্যক", "ToastTitleRequired": "শিরোনাম আবশ্যক",
"ToastUnknownError": "অজানা ত্রুটি", "ToastUnknownError": "অজানা ত্রুটি",

View file

@ -28,6 +28,7 @@
"ButtonEdit": "Upravit", "ButtonEdit": "Upravit",
"ButtonEditChapters": "Upravit kapitoly", "ButtonEditChapters": "Upravit kapitoly",
"ButtonEditPodcast": "Upravit podcast", "ButtonEditPodcast": "Upravit podcast",
"ButtonEnable": "Povolit",
"ButtonForceReScan": "Vynutit opětovné prohledání", "ButtonForceReScan": "Vynutit opětovné prohledání",
"ButtonFullPath": "Úplná cesta", "ButtonFullPath": "Úplná cesta",
"ButtonHide": "Skrýt", "ButtonHide": "Skrýt",
@ -44,10 +45,15 @@
"ButtonMatchAllAuthors": "Spárovat všechny autory", "ButtonMatchAllAuthors": "Spárovat všechny autory",
"ButtonMatchBooks": "Spárovat Knihy", "ButtonMatchBooks": "Spárovat Knihy",
"ButtonNevermind": "Nevadí", "ButtonNevermind": "Nevadí",
"ButtonNext": "Další",
"ButtonNextChapter": "Další Kapitola", "ButtonNextChapter": "Další Kapitola",
"ButtonNextItemInQueue": "Žádná další položka ve frontě",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Otevřít kanál", "ButtonOpenFeed": "Otevřít kanál",
"ButtonOpenManager": "Otevřít správce", "ButtonOpenManager": "Otevřít správce",
"ButtonPause": "Pozastavit",
"ButtonPlay": "Přehrát", "ButtonPlay": "Přehrát",
"ButtonPlayAll": "Přehrát vše",
"ButtonPlaying": "Hraje", "ButtonPlaying": "Hraje",
"ButtonPlaylists": "Seznamy skladeb", "ButtonPlaylists": "Seznamy skladeb",
"ButtonPrevious": "Předchozí", "ButtonPrevious": "Předchozí",
@ -88,6 +94,8 @@
"ButtonStartMetadataEmbed": "Spustit vkládání metadat", "ButtonStartMetadataEmbed": "Spustit vkládání metadat",
"ButtonStats": "Statistiky", "ButtonStats": "Statistiky",
"ButtonSubmit": "Odeslat", "ButtonSubmit": "Odeslat",
"ButtonTest": "Test",
"ButtonUnlinkOpenId": "Odpojit OpenID",
"ButtonUpload": "Nahrát", "ButtonUpload": "Nahrát",
"ButtonUploadBackup": "Nahrát zálohu", "ButtonUploadBackup": "Nahrát zálohu",
"ButtonUploadCover": "Nahrát obálku", "ButtonUploadCover": "Nahrát obálku",
@ -100,10 +108,12 @@
"ErrorUploadFetchMetadataNoResults": "Nepodařilo se načíst metadata - zkuste aktualizovat název a/nebo autora", "ErrorUploadFetchMetadataNoResults": "Nepodařilo se načíst metadata - zkuste aktualizovat název a/nebo autora",
"ErrorUploadLacksTitle": "Musí mít titul", "ErrorUploadLacksTitle": "Musí mít titul",
"HeaderAccount": "Účet", "HeaderAccount": "Účet",
"HeaderAddCustomMetadataProvider": "Přidat vlastního poskytovatele metadat",
"HeaderAdvanced": "Pokročilé", "HeaderAdvanced": "Pokročilé",
"HeaderAppriseNotificationSettings": "Nastavení oznámení Apprise", "HeaderAppriseNotificationSettings": "Nastavení oznámení Apprise",
"HeaderAudioTracks": "Zvukové stopy", "HeaderAudioTracks": "Zvukové stopy",
"HeaderAudiobookTools": "Nástroje pro správu souborů audioknih", "HeaderAudiobookTools": "Nástroje pro správu souborů audioknih",
"HeaderAuthentication": "Autentizace",
"HeaderBackups": "Zálohy", "HeaderBackups": "Zálohy",
"HeaderChangePassword": "Změnit heslo", "HeaderChangePassword": "Změnit heslo",
"HeaderChapters": "Kapitoly", "HeaderChapters": "Kapitoly",
@ -144,10 +154,13 @@
"HeaderMetadataToEmbed": "Metadata k vložení", "HeaderMetadataToEmbed": "Metadata k vložení",
"HeaderNewAccount": "Nový účet", "HeaderNewAccount": "Nový účet",
"HeaderNewLibrary": "Nová knihovna", "HeaderNewLibrary": "Nová knihovna",
"HeaderNotificationCreate": "Vytvořit notifikaci",
"HeaderNotificationUpdate": "Aktualizovat notifikaci",
"HeaderNotifications": "Oznámení", "HeaderNotifications": "Oznámení",
"HeaderOpenIDConnectAuthentication": "Ověřování pomocí OpenID Connect", "HeaderOpenIDConnectAuthentication": "Ověřování pomocí OpenID Connect",
"HeaderOpenRSSFeed": "Otevřít RSS kanál", "HeaderOpenRSSFeed": "Otevřít RSS kanál",
"HeaderOtherFiles": "Ostatní soubory", "HeaderOtherFiles": "Ostatní soubory",
"HeaderPasswordAuthentication": "Autentizace heslem",
"HeaderPermissions": "Oprávnění", "HeaderPermissions": "Oprávnění",
"HeaderPlayerQueue": "Fronta přehrávače", "HeaderPlayerQueue": "Fronta přehrávače",
"HeaderPlayerSettings": "Nastavení přehrávače", "HeaderPlayerSettings": "Nastavení přehrávače",
@ -200,6 +213,7 @@
"LabelAddToPlaylist": "Přidat do seznamu přehrávání", "LabelAddToPlaylist": "Přidat do seznamu přehrávání",
"LabelAddToPlaylistBatch": "Přidat {0} položky do seznamu přehrávání", "LabelAddToPlaylistBatch": "Přidat {0} položky do seznamu přehrávání",
"LabelAddedAt": "Přidáno v", "LabelAddedAt": "Přidáno v",
"LabelAddedDate": "Přidáno {0}",
"LabelAdminUsersOnly": "Pouze administrátoři", "LabelAdminUsersOnly": "Pouze administrátoři",
"LabelAll": "Vše", "LabelAll": "Vše",
"LabelAllUsers": "Všichni uživatelé", "LabelAllUsers": "Všichni uživatelé",
@ -229,6 +243,7 @@
"LabelBitrate": "Datový tok", "LabelBitrate": "Datový tok",
"LabelBooks": "Knihy", "LabelBooks": "Knihy",
"LabelButtonText": "Text tlačítka", "LabelButtonText": "Text tlačítka",
"LabelByAuthor": "od {0}",
"LabelChangePassword": "Změnit heslo", "LabelChangePassword": "Změnit heslo",
"LabelChannels": "Kanály", "LabelChannels": "Kanály",
"LabelChapterTitle": "Název kapitoly", "LabelChapterTitle": "Název kapitoly",
@ -238,6 +253,7 @@
"LabelClosePlayer": "Zavřít přehrávač", "LabelClosePlayer": "Zavřít přehrávač",
"LabelCodec": "Kodek", "LabelCodec": "Kodek",
"LabelCollapseSeries": "Sbalit sérii", "LabelCollapseSeries": "Sbalit sérii",
"LabelCollapseSubSeries": "Sbalit podsérie",
"LabelCollection": "Kolekce", "LabelCollection": "Kolekce",
"LabelCollections": "Kolekce", "LabelCollections": "Kolekce",
"LabelComplete": "Dokončeno", "LabelComplete": "Dokončeno",
@ -288,16 +304,21 @@
"LabelEpisode": "Epizoda", "LabelEpisode": "Epizoda",
"LabelEpisodeTitle": "Název epizody", "LabelEpisodeTitle": "Název epizody",
"LabelEpisodeType": "Typ epizody", "LabelEpisodeType": "Typ epizody",
"LabelEpisodes": "Epizody",
"LabelExample": "Příklad", "LabelExample": "Příklad",
"LabelExpandSeries": "Rozbalit série", "LabelExpandSeries": "Rozbalit série",
"LabelExpandSubSeries": "Rozbalit podsérie",
"LabelExplicit": "Explicitní", "LabelExplicit": "Explicitní",
"LabelExplicitChecked": "Explicitní (zaškrtnuto)", "LabelExplicitChecked": "Explicitní (zaškrtnuto)",
"LabelExplicitUnchecked": "Není explicitní (nezaškrtnuto)", "LabelExplicitUnchecked": "Není explicitní (nezaškrtnuto)",
"LabelExportOPML": "Export OPML",
"LabelFeedURL": "URL zdroje", "LabelFeedURL": "URL zdroje",
"LabelFetchingMetadata": "Získávání metadat", "LabelFetchingMetadata": "Získávání metadat",
"LabelFile": "Soubor", "LabelFile": "Soubor",
"LabelFileBirthtime": "Čas vzniku souboru", "LabelFileBirthtime": "Čas vzniku souboru",
"LabelFileBornDate": "Vytvořeno {0}",
"LabelFileModified": "Soubor změněn", "LabelFileModified": "Soubor změněn",
"LabelFileModifiedDate": "Změněno {0}",
"LabelFilename": "Název souboru", "LabelFilename": "Název souboru",
"LabelFilterByUser": "Filtrovat podle uživatele", "LabelFilterByUser": "Filtrovat podle uživatele",
"LabelFindEpisodes": "Najít epizody", "LabelFindEpisodes": "Najít epizody",
@ -307,6 +328,7 @@
"LabelFontBold": "Tučně", "LabelFontBold": "Tučně",
"LabelFontBoldness": "Výraznost písma", "LabelFontBoldness": "Výraznost písma",
"LabelFontFamily": "Rodina písem", "LabelFontFamily": "Rodina písem",
"LabelFontItalic": "Kurzíva",
"LabelFontScale": "Měřítko písma", "LabelFontScale": "Měřítko písma",
"LabelFontStrikethrough": "Přeškrtnutí", "LabelFontStrikethrough": "Přeškrtnutí",
"LabelFormat": "Formát", "LabelFormat": "Formát",
@ -325,6 +347,7 @@
"LabelInProgress": "Probíhá", "LabelInProgress": "Probíhá",
"LabelIncludeInTracklist": "Zahrnout do seznamu stop", "LabelIncludeInTracklist": "Zahrnout do seznamu stop",
"LabelIncomplete": "Neúplné", "LabelIncomplete": "Neúplné",
"LabelInterval": "Interval",
"LabelIntervalCustomDailyWeekly": "Vlastní denně/týdně", "LabelIntervalCustomDailyWeekly": "Vlastní denně/týdně",
"LabelIntervalEvery12Hours": "Každých 12 hodin", "LabelIntervalEvery12Hours": "Každých 12 hodin",
"LabelIntervalEvery15Minutes": "Každých 15 minut", "LabelIntervalEvery15Minutes": "Každých 15 minut",
@ -421,17 +444,22 @@
"LabelPersonalYearReview": "Váš přehled roku ({0})", "LabelPersonalYearReview": "Váš přehled roku ({0})",
"LabelPhotoPathURL": "Cesta k fotografii/URL", "LabelPhotoPathURL": "Cesta k fotografii/URL",
"LabelPlayMethod": "Metoda přehrávání", "LabelPlayMethod": "Metoda přehrávání",
"LabelPlayerChapterNumberMarker": "{0} z {1}",
"LabelPlaylists": "Seznamy skladeb", "LabelPlaylists": "Seznamy skladeb",
"LabelPodcast": "Podcast",
"LabelPodcastSearchRegion": "Oblast vyhledávání podcastu", "LabelPodcastSearchRegion": "Oblast vyhledávání podcastu",
"LabelPodcastType": "Typ podcastu", "LabelPodcastType": "Typ podcastu",
"LabelPodcasts": "Podcasty", "LabelPodcasts": "Podcasty",
"LabelPort": "Port",
"LabelPrefixesToIgnore": "Předpony, které se mají ignorovat (nerozlišují se malá a velká písmena)", "LabelPrefixesToIgnore": "Předpony, které se mají ignorovat (nerozlišují se malá a velká písmena)",
"LabelPreventIndexing": "Zabránit indexování vašeho kanálu v adresářích podcastů iTunes a Google", "LabelPreventIndexing": "Zabránit indexování vašeho kanálu v adresářích podcastů iTunes a Google",
"LabelPrimaryEbook": "Hlavní e-kniha", "LabelPrimaryEbook": "Hlavní e-kniha",
"LabelProgress": "Průběh", "LabelProgress": "Průběh",
"LabelProvider": "Poskytovatel", "LabelProvider": "Poskytovatel",
"LabelProviderAuthorizationValue": "Hodnota autorizačního headeru",
"LabelPubDate": "Datum vydání", "LabelPubDate": "Datum vydání",
"LabelPublishYear": "Rok vydání", "LabelPublishYear": "Rok vydání",
"LabelPublishedDate": "Vydáno {0}",
"LabelPublisher": "Vydavatel", "LabelPublisher": "Vydavatel",
"LabelPublishers": "Vydavatelé", "LabelPublishers": "Vydavatelé",
"LabelRSSFeedCustomOwnerEmail": "Vlastní e-mail vlastníka", "LabelRSSFeedCustomOwnerEmail": "Vlastní e-mail vlastníka",
@ -441,6 +469,7 @@
"LabelRSSFeedSlug": "RSS kanál Slug", "LabelRSSFeedSlug": "RSS kanál Slug",
"LabelRSSFeedURL": "URL RSS kanálu", "LabelRSSFeedURL": "URL RSS kanálu",
"LabelRandomly": "Náhodně", "LabelRandomly": "Náhodně",
"LabelReAddSeriesToContinueListening": "Znovu přidat sérii k pokračování poslechu",
"LabelRead": "Číst", "LabelRead": "Číst",
"LabelReadAgain": "Číst znovu", "LabelReadAgain": "Číst znovu",
"LabelReadEbookWithoutProgress": "Číst e-knihu bez zachování průběhu", "LabelReadEbookWithoutProgress": "Číst e-knihu bez zachování průběhu",
@ -448,6 +477,7 @@
"LabelRecentlyAdded": "Nedávno přidané", "LabelRecentlyAdded": "Nedávno přidané",
"LabelRecommended": "Doporučeno", "LabelRecommended": "Doporučeno",
"LabelRedo": "Přepracovat", "LabelRedo": "Přepracovat",
"LabelRegion": "Region",
"LabelReleaseDate": "Datum vydání", "LabelReleaseDate": "Datum vydání",
"LabelRemoveCover": "Odstranit obálku", "LabelRemoveCover": "Odstranit obálku",
"LabelRowsPerPage": "Řádky na stránku", "LabelRowsPerPage": "Řádky na stránku",
@ -539,6 +569,7 @@
"LabelTagsNotAccessibleToUser": "Značky nepřístupné uživateli", "LabelTagsNotAccessibleToUser": "Značky nepřístupné uživateli",
"LabelTasks": "Spuštěné Úlohy", "LabelTasks": "Spuštěné Úlohy",
"LabelTextEditorBulletedList": "Seznam s odrážkami", "LabelTextEditorBulletedList": "Seznam s odrážkami",
"LabelTextEditorLink": "Odkaz",
"LabelTextEditorNumberedList": "Seznam s čísly", "LabelTextEditorNumberedList": "Seznam s čísly",
"LabelTextEditorUnlink": "Zrušit odkaz", "LabelTextEditorUnlink": "Zrušit odkaz",
"LabelTheme": "Téma", "LabelTheme": "Téma",
@ -572,6 +603,7 @@
"LabelUnabridged": "Nezkráceno", "LabelUnabridged": "Nezkráceno",
"LabelUndo": "Zpět", "LabelUndo": "Zpět",
"LabelUnknown": "Neznámý", "LabelUnknown": "Neznámý",
"LabelUnknownPublishDate": "Neznámé datum vydání",
"LabelUpdateCover": "Aktualizovat obálku", "LabelUpdateCover": "Aktualizovat obálku",
"LabelUpdateCoverHelp": "Povolit přepsání existujících obálek pro vybrané knihy, pokud je nalezena shoda", "LabelUpdateCoverHelp": "Povolit přepsání existujících obálek pro vybrané knihy, pokud je nalezena shoda",
"LabelUpdateDetails": "Aktualizovat podrobnosti", "LabelUpdateDetails": "Aktualizovat podrobnosti",
@ -620,14 +652,19 @@
"MessageCheckingCron": "Kontrola cronu...", "MessageCheckingCron": "Kontrola cronu...",
"MessageConfirmCloseFeed": "Opravdu chcete zavřít tento kanál?", "MessageConfirmCloseFeed": "Opravdu chcete zavřít tento kanál?",
"MessageConfirmDeleteBackup": "Opravdu chcete smazat zálohu pro {0}?", "MessageConfirmDeleteBackup": "Opravdu chcete smazat zálohu pro {0}?",
"MessageConfirmDeleteDevice": "Opravdu chcete vymazat zařízení e-reader \"{0}\"?",
"MessageConfirmDeleteFile": "Tento krok smaže soubor ze souborového systému. Jsi si jisti?", "MessageConfirmDeleteFile": "Tento krok smaže soubor ze souborového systému. Jsi si jisti?",
"MessageConfirmDeleteLibrary": "Opravdu chcete trvale smazat knihovnu \"{0}\"?", "MessageConfirmDeleteLibrary": "Opravdu chcete trvale smazat knihovnu \"{0}\"?",
"MessageConfirmDeleteLibraryItem": "Tento krok odstraní položku knihovny z databáze a vašeho souborového systému. Jste si jisti?", "MessageConfirmDeleteLibraryItem": "Tento krok odstraní položku knihovny z databáze a vašeho souborového systému. Jste si jisti?",
"MessageConfirmDeleteLibraryItems": "Tímto smažete {0} položkek knihovny z databáze a vašeho souborového systému. Jsi si jisti?", "MessageConfirmDeleteLibraryItems": "Tímto smažete {0} položkek knihovny z databáze a vašeho souborového systému. Jsi si jisti?",
"MessageConfirmDeleteMetadataProvider": "Opravdu chcete vymazat vlastního poskytovatele metadat \"{0}\"?",
"MessageConfirmDeleteNotification": "Opravdu chcete vymazat tuto notifikaci?",
"MessageConfirmDeleteSession": "Opravdu chcete smazat tuto relaci?", "MessageConfirmDeleteSession": "Opravdu chcete smazat tuto relaci?",
"MessageConfirmForceReScan": "Opravdu chcete vynutit opětovné prohledání?", "MessageConfirmForceReScan": "Opravdu chcete vynutit opětovné prohledání?",
"MessageConfirmMarkAllEpisodesFinished": "Opravdu chcete označit všechny epizody jako dokončené?", "MessageConfirmMarkAllEpisodesFinished": "Opravdu chcete označit všechny epizody jako dokončené?",
"MessageConfirmMarkAllEpisodesNotFinished": "Opravdu chcete označit všechny epizody jako nedokončené?", "MessageConfirmMarkAllEpisodesNotFinished": "Opravdu chcete označit všechny epizody jako nedokončené?",
"MessageConfirmMarkItemFinished": "Opravdu chcete označit \"{0}\" jako dokončené?",
"MessageConfirmMarkItemNotFinished": "Opravdu chcete označit \"{0}\" jako nedokončené?",
"MessageConfirmMarkSeriesFinished": "Opravdu chcete označit všechny knihy z této série jako dokončené?", "MessageConfirmMarkSeriesFinished": "Opravdu chcete označit všechny knihy z této série jako dokončené?",
"MessageConfirmMarkSeriesNotFinished": "Opravdu chcete označit všechny knihy z této série jako nedokončené?", "MessageConfirmMarkSeriesNotFinished": "Opravdu chcete označit všechny knihy z této série jako nedokončené?",
"MessageConfirmPurgeCache": "Vyčistit mezipaměť odstraní celý adresář na adrese <code>/metadata/cache</code>. <br /><br />Určitě chcete odstranit adresář mezipaměti?", "MessageConfirmPurgeCache": "Vyčistit mezipaměť odstraní celý adresář na adrese <code>/metadata/cache</code>. <br /><br />Určitě chcete odstranit adresář mezipaměti?",
@ -648,7 +685,9 @@
"MessageConfirmRenameTag": "Opravdu chcete přejmenovat tag \"{0}\" na \"{1}\" pro všechny položky?", "MessageConfirmRenameTag": "Opravdu chcete přejmenovat tag \"{0}\" na \"{1}\" pro všechny položky?",
"MessageConfirmRenameTagMergeNote": "Poznámka: Tato značka již existuje, takže budou sloučeny.", "MessageConfirmRenameTagMergeNote": "Poznámka: Tato značka již existuje, takže budou sloučeny.",
"MessageConfirmRenameTagWarning": "Varování! Podobná značka s jinými velkými a malými písmeny již existuje \"{0}\".", "MessageConfirmRenameTagWarning": "Varování! Podobná značka s jinými velkými a malými písmeny již existuje \"{0}\".",
"MessageConfirmResetProgress": "Opravdu chcete zahodit svůj pokrok?",
"MessageConfirmSendEbookToDevice": "Opravdu chcete odeslat e-knihu {0} {1}\" do zařízení \"{2}\"?", "MessageConfirmSendEbookToDevice": "Opravdu chcete odeslat e-knihu {0} {1}\" do zařízení \"{2}\"?",
"MessageConfirmUnlinkOpenId": "Opravdu chcete odpojit tohoto uživatele z OpenID?",
"MessageDownloadingEpisode": "Stahuji epizodu", "MessageDownloadingEpisode": "Stahuji epizodu",
"MessageDragFilesIntoTrackOrder": "Přetáhněte soubory do správného pořadí stop", "MessageDragFilesIntoTrackOrder": "Přetáhněte soubory do správného pořadí stop",
"MessageEmbedFailed": "Vložení selhalo!", "MessageEmbedFailed": "Vložení selhalo!",
@ -656,7 +695,7 @@
"MessageEpisodesQueuedForDownload": "{0} Epizody zařazené do fronty ke stažení", "MessageEpisodesQueuedForDownload": "{0} Epizody zařazené do fronty ke stažení",
"MessageEreaderDevices": "Aby bylo zajištěno doručení elektronických knih, může být nutné přidat výše uvedenou e-mailovou adresu jako platného odesílatele pro každé zařízení uvedené níže.", "MessageEreaderDevices": "Aby bylo zajištěno doručení elektronických knih, může být nutné přidat výše uvedenou e-mailovou adresu jako platného odesílatele pro každé zařízení uvedené níže.",
"MessageFeedURLWillBe": "URL zdroje bude {0}", "MessageFeedURLWillBe": "URL zdroje bude {0}",
"MessageFetching": "Stahování...", "MessageFetching": "Načítání...",
"MessageForceReScanDescription": "znovu prohledá všechny soubory jako při novém skenování. ID3 tagy zvukových souborů OPF soubory a textové soubory budou skenovány jako nové.", "MessageForceReScanDescription": "znovu prohledá všechny soubory jako při novém skenování. ID3 tagy zvukových souborů OPF soubory a textové soubory budou skenovány jako nové.",
"MessageImportantNotice": "Důležité upozornění!", "MessageImportantNotice": "Důležité upozornění!",
"MessageInsertChapterBelow": "Vložit kapitolu níže", "MessageInsertChapterBelow": "Vložit kapitolu níže",
@ -683,6 +722,7 @@
"MessageNoCollections": "Žádné kolekce", "MessageNoCollections": "Žádné kolekce",
"MessageNoCoversFound": "Nebyly nalezeny žádné obálky", "MessageNoCoversFound": "Nebyly nalezeny žádné obálky",
"MessageNoDescription": "Bez popisu", "MessageNoDescription": "Bez popisu",
"MessageNoDevices": "Žádná zařízení",
"MessageNoDownloadsInProgress": "Momentálně neprobíhá žádné stahování", "MessageNoDownloadsInProgress": "Momentálně neprobíhá žádné stahování",
"MessageNoDownloadsQueued": "Žádné stahování ve frontě", "MessageNoDownloadsQueued": "Žádné stahování ve frontě",
"MessageNoEpisodeMatchesFound": "Nebyly nalezeny žádné odpovídající epizody", "MessageNoEpisodeMatchesFound": "Nebyly nalezeny žádné odpovídající epizody",
@ -710,6 +750,7 @@
"MessagePauseChapter": "Pozastavit přehrávání kapitoly", "MessagePauseChapter": "Pozastavit přehrávání kapitoly",
"MessagePlayChapter": "Poslechnout si začátek kapitoly", "MessagePlayChapter": "Poslechnout si začátek kapitoly",
"MessagePlaylistCreateFromCollection": "Vytvořit seznam skladeb z kolekce", "MessagePlaylistCreateFromCollection": "Vytvořit seznam skladeb z kolekce",
"MessagePleaseWait": "Čekejte prosím...",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nemá žádnou adresu URL kanálu RSS, kterou by mohl použít pro porovnávání", "MessagePodcastHasNoRSSFeedForMatching": "Podcast nemá žádnou adresu URL kanálu RSS, kterou by mohl použít pro porovnávání",
"MessageQuickMatchDescription": "Vyplňte prázdné detaily položky a obálku prvním výsledkem shody z '{0}'. Nepřepisuje podrobnosti, pokud není povoleno nastavení serveru \"Preferovat párování metadata\".", "MessageQuickMatchDescription": "Vyplňte prázdné detaily položky a obálku prvním výsledkem shody z '{0}'. Nepřepisuje podrobnosti, pokud není povoleno nastavení serveru \"Preferovat párování metadata\".",
"MessageRemoveChapter": "Odstranit kapitolu", "MessageRemoveChapter": "Odstranit kapitolu",
@ -728,17 +769,46 @@
"MessageShareExpiresIn": "Expiruje za {0}", "MessageShareExpiresIn": "Expiruje za {0}",
"MessageShareURLWillBe": "Sdílené URL bude <strong>{0}</strong>", "MessageShareURLWillBe": "Sdílené URL bude <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Spustit přehrávání pro \"{0}\" v {1}?", "MessageStartPlaybackAtTime": "Spustit přehrávání pro \"{0}\" v {1}?",
"MessageTaskAudioFileNotWritable": "Nelze zapisovat do audio souboru \"{0}\"",
"MessageTaskCanceledByUser": "Task zrušen uživatelem",
"MessageTaskDownloadingEpisodeDescription": "Stahování epizody \"{0}\"",
"MessageTaskEmbeddingMetadata": "Vkládání metadat",
"MessageTaskEmbeddingMetadataDescription": "Vkládání metadat do audioknihy \"{0}\"",
"MessageTaskEncodingM4b": "Kódování M4B",
"MessageTaskEncodingM4bDescription": "Kódování audioknihy \"{0}\" do jednoho m4b souboru",
"MessageTaskFailed": "Selhalo",
"MessageTaskFailedToBackupAudioFile": "Zálohování audio souboru \"{0}\" se selhalo",
"MessageTaskFailedToCreateCacheDirectory": "Vytvoření cache adresáře selhalo",
"MessageTaskFailedToEmbedMetadataInFile": "Vkládání metadat do souboru \"{0}\" selhalo",
"MessageTaskFailedToMergeAudioFiles": "Spojení audio souborů selhalo",
"MessageTaskFailedToMoveM4bFile": "Přesunutí m4b souboru selhalo",
"MessageTaskFailedToWriteMetadataFile": "Zápis souboru metadat selhal",
"MessageTaskNoFilesToScan": "Žádné soubory ke skenování",
"MessageTaskOpmlImport": "Import OPML",
"MessageTaskOpmlImportDescription": "Vytváření podcastů z {0} RSS feedů",
"MessageTaskOpmlImportFeedDescription": "Importování RSS feedu \"{0}\"",
"MessageTaskOpmlImportFeedPodcastDescription": "Vytváření podcastu \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast se stejnou cestou již existuje",
"MessageTaskOpmlImportFeedPodcastFailed": "Vytváření podcastu selhalo",
"MessageTaskOpmlImportFinished": "Přidáno {0} podcastů",
"MessageTaskScanItemsAdded": "{0} přidáno",
"MessageTaskScanItemsMissing": "{0} chybí",
"MessageTaskScanItemsUpdated": "{0} aktualizováno",
"MessageTaskScanNoChangesNeeded": "Žádné změny nejsou nutné",
"MessageTaskScanningFileChanges": "Skenování změn souborů v \"{0}\"",
"MessageTaskScanningLibrary": "Skenování \"{0}\" knihovny",
"MessageTaskTargetDirectoryNotWritable": "Do cílové složky nelze zapisovat",
"MessageThinking": "Přemýšlení...", "MessageThinking": "Přemýšlení...",
"MessageUploaderItemFailed": "Nahrávání se nezdařilo", "MessageUploaderItemFailed": "Nahrávání selhalo",
"MessageUploaderItemSuccess": "Nahráno bylo úspěšně!", "MessageUploaderItemSuccess": "Úspěšně nahráno!",
"MessageUploading": "Odesílám...", "MessageUploading": "Nahrávám...",
"MessageValidCronExpression": "Platný výraz cronu", "MessageValidCronExpression": "Platný výraz cronu",
"MessageWatcherIsDisabledGlobally": "Hlídač je globálně zakázán v nastavení serveru", "MessageWatcherIsDisabledGlobally": "Hlídač je globálně zakázán v nastavení serveru",
"MessageXLibraryIsEmpty": "{0} knihovna je prázdná!", "MessageXLibraryIsEmpty": "{0} knihovna je prázdná!",
"MessageYourAudiobookDurationIsLonger": "Doba trvání audioknihy je delší než nalezená délka", "MessageYourAudiobookDurationIsLonger": "Délka audioknihy je delší, než byla nalezena",
"MessageYourAudiobookDurationIsShorter": "Délka audioknihy je kratší, než byla nalezena", "MessageYourAudiobookDurationIsShorter": "Délka audioknihy je kratší, než byla nalezena",
"NoteChangeRootPassword": "Uživatel root je jediný uživatel, který může mít prázdné heslo", "NoteChangeRootPassword": "Uživatel root je jediný uživatel, který může mít prázdné heslo",
"NoteChapterEditorTimes": "Poznámka: Čas začátku první kapitoly musí zůstat v 0:00 a čas začátku poslední kapitoly nesmí překročit tuto dobu trvání audioknihy.", "NoteChapterEditorTimes": "Poznámka: Čas začátku první kapitoly musí zůstat na 0:00 a čas začátku poslední kapitoly nesmí překročit dobu trvání audioknihy.",
"NoteFolderPicker": "Poznámka: složky, které jsou již namapovány, nebudou zobrazeny", "NoteFolderPicker": "Poznámka: složky, které jsou již namapovány, nebudou zobrazeny",
"NoteRSSFeedPodcastAppsHttps": "Upozornění: Většina aplikací pro podcasty bude vyžadovat, aby adresa URL kanálu RSS používala protokol HTTPS", "NoteRSSFeedPodcastAppsHttps": "Upozornění: Většina aplikací pro podcasty bude vyžadovat, aby adresa URL kanálu RSS používala protokol HTTPS",
"NoteRSSFeedPodcastAppsPubDate": "Upozornění: 1 nebo více epizod nemá datum vydání. Některé podcastové aplikace to vyžadují.", "NoteRSSFeedPodcastAppsPubDate": "Upozornění: 1 nebo více epizod nemá datum vydání. Některé podcastové aplikace to vyžadují.",
@ -752,8 +822,10 @@
"PlaceholderSearchEpisode": "Hledat epizodu..", "PlaceholderSearchEpisode": "Hledat epizodu..",
"StatsAuthorsAdded": "autoři přidáni", "StatsAuthorsAdded": "autoři přidáni",
"StatsBooksAdded": "knihy přidány", "StatsBooksAdded": "knihy přidány",
"StatsBooksAdditional": "Některé další zahrnují…",
"StatsBooksFinished": "dokončené knihy", "StatsBooksFinished": "dokončené knihy",
"StatsBooksFinishedThisYear": "Některé knihy dokončené tento rok…", "StatsBooksFinishedThisYear": "Některé knihy dokončené tento rok…",
"StatsCollectionGrewTo": "Vaše kolekce knih se rozrostla na…",
"StatsSessions": "sezení", "StatsSessions": "sezení",
"StatsSpentListening": "stráveno posloucháním", "StatsSpentListening": "stráveno posloucháním",
"StatsTopAuthor": "TOP AUTOR", "StatsTopAuthor": "TOP AUTOR",
@ -763,59 +835,75 @@
"StatsTopMonth": "TOP MĚSÍC", "StatsTopMonth": "TOP MĚSÍC",
"StatsTotalDuration": "S celkovou dobou…", "StatsTotalDuration": "S celkovou dobou…",
"StatsYearInReview": "ROK V PŘEHLEDU", "StatsYearInReview": "ROK V PŘEHLEDU",
"ToastAccountUpdateFailed": "Aktualizace účtu se nezdařila",
"ToastAccountUpdateSuccess": "Účet aktualizován", "ToastAccountUpdateSuccess": "Účet aktualizován",
"ToastAppriseUrlRequired": "Je nutné zadat Apprise URL",
"ToastAuthorImageRemoveSuccess": "Obrázek autora odstraněn", "ToastAuthorImageRemoveSuccess": "Obrázek autora odstraněn",
"ToastAuthorUpdateFailed": "Aktualizace autora se nezdařila", "ToastAuthorNotFound": "Author \"{0}\" nenalezen",
"ToastAuthorRemoveSuccess": "Autor odstraněn",
"ToastAuthorSearchNotFound": "Autor nenalezen",
"ToastAuthorUpdateMerged": "Autor sloučen", "ToastAuthorUpdateMerged": "Autor sloučen",
"ToastAuthorUpdateSuccess": "Autor aktualizován", "ToastAuthorUpdateSuccess": "Autor aktualizován",
"ToastAuthorUpdateSuccessNoImageFound": "Autor aktualizován (nebyl nalezen žádný obrázek)", "ToastAuthorUpdateSuccessNoImageFound": "Autor aktualizován (nebyl nalezen žádný obrázek)",
"ToastBackupAppliedSuccess": "Záloha obnovena",
"ToastBackupCreateFailed": "Vytvoření zálohy se nezdařilo", "ToastBackupCreateFailed": "Vytvoření zálohy se nezdařilo",
"ToastBackupCreateSuccess": "Záloha vytvořena", "ToastBackupCreateSuccess": "Záloha vytvořena",
"ToastBackupDeleteFailed": "Nepodařilo se smazat zálohu", "ToastBackupDeleteFailed": "Nepodařilo se smazat zálohu",
"ToastBackupDeleteSuccess": "Záloha smazána", "ToastBackupDeleteSuccess": "Záloha smazána",
"ToastBackupInvalidMaxKeep": "Neplatný počet záloh k zachování",
"ToastBackupInvalidMaxSize": "Neplatná maximální velikost zálohy",
"ToastBackupRestoreFailed": "Nepodařilo se obnovit zálohu", "ToastBackupRestoreFailed": "Nepodařilo se obnovit zálohu",
"ToastBackupUploadFailed": "Nepodařilo se nahrát zálohu", "ToastBackupUploadFailed": "Nepodařilo se nahrát zálohu",
"ToastBackupUploadSuccess": "Záloha nahrána", "ToastBackupUploadSuccess": "Záloha nahrána",
"ToastBatchDeleteFailed": "Hromadné smazání selhalo",
"ToastBatchDeleteSuccess": "Hromadné smazání proběhlo úspěšně",
"ToastBatchUpdateFailed": "Dávková aktualizace se nezdařila", "ToastBatchUpdateFailed": "Dávková aktualizace se nezdařila",
"ToastBatchUpdateSuccess": "Dávková aktualizace proběhla úspěšně", "ToastBatchUpdateSuccess": "Dávková aktualizace proběhla úspěšně",
"ToastBookmarkCreateFailed": "Vytvoření záložky se nezdařilo", "ToastBookmarkCreateFailed": "Vytvoření záložky se nezdařilo",
"ToastBookmarkCreateSuccess": "Přidána záložka", "ToastBookmarkCreateSuccess": "Přidána záložka",
"ToastBookmarkRemoveSuccess": "Záložka odstraněna", "ToastBookmarkRemoveSuccess": "Záložka odstraněna",
"ToastBookmarkUpdateFailed": "Aktualizace záložky se nezdařila",
"ToastBookmarkUpdateSuccess": "Záložka aktualizována", "ToastBookmarkUpdateSuccess": "Záložka aktualizována",
"ToastCachePurgeFailed": "Nepodařilo se vyčistit mezipaměť", "ToastCachePurgeFailed": "Nepodařilo se vyčistit mezipaměť",
"ToastCachePurgeSuccess": "Vyrovnávací paměť úspěšně vyčištěna", "ToastCachePurgeSuccess": "Vyrovnávací paměť úspěšně vyčištěna",
"ToastChaptersHaveErrors": "Kapitoly obsahují chyby", "ToastChaptersHaveErrors": "Kapitoly obsahují chyby",
"ToastChaptersMustHaveTitles": "Kapitoly musí mít názvy", "ToastChaptersMustHaveTitles": "Kapitoly musí mít názvy",
"ToastChaptersRemoved": "Kapitoly odstraněny",
"ToastCollectionItemsRemoveSuccess": "Položky odstraněny z kolekce", "ToastCollectionItemsRemoveSuccess": "Položky odstraněny z kolekce",
"ToastCollectionRemoveSuccess": "Kolekce odstraněna", "ToastCollectionRemoveSuccess": "Kolekce odstraněna",
"ToastCollectionUpdateFailed": "Aktualizace kolekce se nezdařila",
"ToastCollectionUpdateSuccess": "Kolekce aktualizována", "ToastCollectionUpdateSuccess": "Kolekce aktualizována",
"ToastCoverUpdateFailed": "Aktualizace obálky selhala",
"ToastDeleteFileFailed": "Nepodařilo se smazat soubor", "ToastDeleteFileFailed": "Nepodařilo se smazat soubor",
"ToastDeleteFileSuccess": "Soubor smazán", "ToastDeleteFileSuccess": "Soubor smazán",
"ToastDeviceAddFailed": "Přidání zařízení selhalo",
"ToastDeviceNameAlreadyExists": "Zařízení se stejným jménem již existuje",
"ToastDeviceTestEmailFailed": "Odeslání testovacího emailu selhalo",
"ToastDeviceTestEmailSuccess": "Testovací email byl odeslán",
"ToastEmailSettingsUpdateSuccess": "Nastavení emailu aktualizována",
"ToastEpisodeDownloadQueueClearFailed": "Vyčištění fronty selhalo",
"ToastErrorCannotShare": "Na tomto zařízení nelze nativně sdílet", "ToastErrorCannotShare": "Na tomto zařízení nelze nativně sdílet",
"ToastFailedToLoadData": "Nepodařilo se načíst data", "ToastFailedToLoadData": "Nepodařilo se načíst data",
"ToastItemCoverUpdateFailed": "Aktualizace obálky se nezdařila", "ToastFailedToShare": "Sdílení selhalo",
"ToastFailedToUpdate": "Aktualizace selhala",
"ToastInvalidImageUrl": "Neplatná URL obrázku",
"ToastInvalidUrl": "Neplatná URL",
"ToastItemCoverUpdateSuccess": "Obálka předmětu byl aktualizována", "ToastItemCoverUpdateSuccess": "Obálka předmětu byl aktualizována",
"ToastItemDetailsUpdateFailed": "Nepodařilo se aktualizovat podrobnosti o položce", "ToastItemDeletedFailed": "Smazání položky selhalo",
"ToastItemDeletedSuccess": "Položka smazána",
"ToastItemDetailsUpdateSuccess": "Podrobnosti o položce byly aktualizovány", "ToastItemDetailsUpdateSuccess": "Podrobnosti o položce byly aktualizovány",
"ToastItemMarkedAsFinishedFailed": "Nepodařilo se označit jako dokončené", "ToastItemMarkedAsFinishedFailed": "Nepodařilo se označit jako dokončené",
"ToastItemMarkedAsFinishedSuccess": "Položka označena jako dokončená", "ToastItemMarkedAsFinishedSuccess": "Položka označena jako dokončená",
"ToastItemMarkedAsNotFinishedFailed": "Nepodařilo se označit jako nedokončené", "ToastItemMarkedAsNotFinishedFailed": "Nepodařilo se označit jako nedokončené",
"ToastItemMarkedAsNotFinishedSuccess": "Položka označena jako nedokončená", "ToastItemMarkedAsNotFinishedSuccess": "Položka označena jako nedokončená",
"ToastItemUpdateSuccess": "Položka aktualizována",
"ToastLibraryCreateFailed": "Vytvoření knihovny se nezdařilo", "ToastLibraryCreateFailed": "Vytvoření knihovny se nezdařilo",
"ToastLibraryCreateSuccess": "Knihovna \"{0}\" vytvořena", "ToastLibraryCreateSuccess": "Knihovna \"{0}\" vytvořena",
"ToastLibraryDeleteFailed": "Nepodařilo se smazat knihovnu", "ToastLibraryDeleteFailed": "Nepodařilo se smazat knihovnu",
"ToastLibraryDeleteSuccess": "Knihovna smazána", "ToastLibraryDeleteSuccess": "Knihovna smazána",
"ToastLibraryScanFailedToStart": "Nepodařilo se spustit kontrolu", "ToastLibraryScanFailedToStart": "Nepodařilo se spustit kontrolu",
"ToastLibraryScanStarted": "Kontrola knihovny spuštěna", "ToastLibraryScanStarted": "Kontrola knihovny spuštěna",
"ToastLibraryUpdateFailed": "Aktualizace knihovny se nezdařila",
"ToastLibraryUpdateSuccess": "Knihovna \"{0}\" aktualizována", "ToastLibraryUpdateSuccess": "Knihovna \"{0}\" aktualizována",
"ToastPlaylistCreateFailed": "Vytvoření seznamu přehrávání se nezdařilo", "ToastPlaylistCreateFailed": "Vytvoření seznamu přehrávání se nezdařilo",
"ToastPlaylistCreateSuccess": "Seznam přehrávání vytvořen", "ToastPlaylistCreateSuccess": "Seznam přehrávání vytvořen",
"ToastPlaylistRemoveSuccess": "Seznam přehrávání odstraněn", "ToastPlaylistRemoveSuccess": "Seznam přehrávání odstraněn",
"ToastPlaylistUpdateFailed": "Aktualizace seznamu přehrávání se nezdařila",
"ToastPlaylistUpdateSuccess": "Seznam přehrávání aktualizován", "ToastPlaylistUpdateSuccess": "Seznam přehrávání aktualizován",
"ToastPodcastCreateFailed": "Vytvoření podcastu se nezdařilo", "ToastPodcastCreateFailed": "Vytvoření podcastu se nezdařilo",
"ToastPodcastCreateSuccess": "Podcast byl úspěšně vytvořen", "ToastPodcastCreateSuccess": "Podcast byl úspěšně vytvořen",
@ -827,7 +915,6 @@
"ToastSendEbookToDeviceSuccess": "E-kniha odeslána do zařízení \"{0}\"", "ToastSendEbookToDeviceSuccess": "E-kniha odeslána do zařízení \"{0}\"",
"ToastSeriesUpdateFailed": "Aktualizace série se nezdařila", "ToastSeriesUpdateFailed": "Aktualizace série se nezdařila",
"ToastSeriesUpdateSuccess": "Aktualizace série byla úspěšná", "ToastSeriesUpdateSuccess": "Aktualizace série byla úspěšná",
"ToastServerSettingsUpdateFailed": "Nepodařilo se aktualizovat nastavení serveru",
"ToastServerSettingsUpdateSuccess": "Nastavení serveru aktualizováno", "ToastServerSettingsUpdateSuccess": "Nastavení serveru aktualizováno",
"ToastSessionDeleteFailed": "Nepodařilo se smazat relaci", "ToastSessionDeleteFailed": "Nepodařilo se smazat relaci",
"ToastSessionDeleteSuccess": "Relace smazána", "ToastSessionDeleteSuccess": "Relace smazána",
@ -835,7 +922,6 @@
"ToastSocketDisconnected": "Socket odpojen", "ToastSocketDisconnected": "Socket odpojen",
"ToastSocketFailedToConnect": "Socket se nepodařilo připojit", "ToastSocketFailedToConnect": "Socket se nepodařilo připojit",
"ToastSortingPrefixesEmptyError": "Musí mít alespoň 1 třídicí předponu", "ToastSortingPrefixesEmptyError": "Musí mít alespoň 1 třídicí předponu",
"ToastSortingPrefixesUpdateFailed": "Nepodařilo se aktualizovat třídicí předpony",
"ToastSortingPrefixesUpdateSuccess": "Aktualizovány předpony třídění ({0} položek)", "ToastSortingPrefixesUpdateSuccess": "Aktualizovány předpony třídění ({0} položek)",
"ToastUserDeleteFailed": "Nepodařilo se smazat uživatele", "ToastUserDeleteFailed": "Nepodařilo se smazat uživatele",
"ToastUserDeleteSuccess": "Uživatel smazán" "ToastUserDeleteSuccess": "Uživatel smazán"

View file

@ -1,7 +1,10 @@
{ {
"ButtonAdd": "Tilføj", "ButtonAdd": "Tilføj",
"ButtonAddChapters": "Tilføj kapitler", "ButtonAddChapters": "Tilføj kapitler",
"ButtonAddDevice": "Tilføj enhed",
"ButtonAddLibrary": "Tilføj Bibliotek",
"ButtonAddPodcasts": "Tilføj podcasts", "ButtonAddPodcasts": "Tilføj podcasts",
"ButtonAddUser": "Tilføj bruger",
"ButtonAddYourFirstLibrary": "Tilføj din første bibliotek", "ButtonAddYourFirstLibrary": "Tilføj din første bibliotek",
"ButtonApply": "Anvend", "ButtonApply": "Anvend",
"ButtonApplyChapters": "Anvend kapitler", "ButtonApplyChapters": "Anvend kapitler",
@ -25,6 +28,7 @@
"ButtonEdit": "Rediger", "ButtonEdit": "Rediger",
"ButtonEditChapters": "Rediger kapitler", "ButtonEditChapters": "Rediger kapitler",
"ButtonEditPodcast": "Rediger podcast", "ButtonEditPodcast": "Rediger podcast",
"ButtonEnable": "Aktiver",
"ButtonForceReScan": "Tvungen genindlæsning", "ButtonForceReScan": "Tvungen genindlæsning",
"ButtonFullPath": "Fuld sti", "ButtonFullPath": "Fuld sti",
"ButtonHide": "Skjul", "ButtonHide": "Skjul",
@ -42,6 +46,7 @@
"ButtonOk": "OK", "ButtonOk": "OK",
"ButtonOpenFeed": "Åbn feed", "ButtonOpenFeed": "Åbn feed",
"ButtonOpenManager": "Åbn manager", "ButtonOpenManager": "Åbn manager",
"ButtonPause": "Pause",
"ButtonPlay": "Afspil", "ButtonPlay": "Afspil",
"ButtonPlaying": "Afspiller", "ButtonPlaying": "Afspiller",
"ButtonPlaylists": "Afspilningslister", "ButtonPlaylists": "Afspilningslister",
@ -66,7 +71,7 @@
"ButtonScanLibrary": "Scan Bibliotek", "ButtonScanLibrary": "Scan Bibliotek",
"ButtonSearch": "Søg", "ButtonSearch": "Søg",
"ButtonSelectFolderPath": "Vælg Mappen Sti", "ButtonSelectFolderPath": "Vælg Mappen Sti",
"ButtonSeries": "Serie", "ButtonSeries": "Serier",
"ButtonSetChaptersFromTracks": "Sæt kapitler fra spor", "ButtonSetChaptersFromTracks": "Sæt kapitler fra spor",
"ButtonShiftTimes": "Skift Tider", "ButtonShiftTimes": "Skift Tider",
"ButtonShow": "Vis", "ButtonShow": "Vis",
@ -188,14 +193,14 @@
"LabelChapters": "Kapitler", "LabelChapters": "Kapitler",
"LabelChaptersFound": "fundne kapitler", "LabelChaptersFound": "fundne kapitler",
"LabelClosePlayer": "Luk afspiller", "LabelClosePlayer": "Luk afspiller",
"LabelCollapseSeries": "Fold Serie Sammen", "LabelCollapseSeries": "Fold Serier Sammen",
"LabelCollection": "Samling", "LabelCollection": "Samling",
"LabelCollections": "Samlinger", "LabelCollections": "Samlinger",
"LabelComplete": "Fuldfør", "LabelComplete": "Fuldfør",
"LabelConfirmPassword": "Bekræft Adgangskode", "LabelConfirmPassword": "Bekræft Adgangskode",
"LabelContinueListening": "Fortsæt Lytning", "LabelContinueListening": "Fortsæt med at lytte",
"LabelContinueReading": "Fortsæt Læsning", "LabelContinueReading": "Fortsæt med at læse",
"LabelContinueSeries": "Fortsæt Serie", "LabelContinueSeries": "Fortsæt Serien",
"LabelCover": "Omslag", "LabelCover": "Omslag",
"LabelCoverImageURL": "Omslagsbillede URL", "LabelCoverImageURL": "Omslagsbillede URL",
"LabelCreatedAt": "Oprettet Kl.", "LabelCreatedAt": "Oprettet Kl.",
@ -212,6 +217,7 @@
"LabelDiscFromFilename": "Disk fra Filnavn", "LabelDiscFromFilename": "Disk fra Filnavn",
"LabelDiscFromMetadata": "Disk fra Metadata", "LabelDiscFromMetadata": "Disk fra Metadata",
"LabelDiscover": "Opdag", "LabelDiscover": "Opdag",
"LabelDownload": "Download",
"LabelDownloadNEpisodes": "Download {0} episoder", "LabelDownloadNEpisodes": "Download {0} episoder",
"LabelDuration": "Varighed", "LabelDuration": "Varighed",
"LabelDurationFound": "Fundet varighed:", "LabelDurationFound": "Fundet varighed:",
@ -225,12 +231,15 @@
"LabelEmbeddedCover": "Indlejret Omslag", "LabelEmbeddedCover": "Indlejret Omslag",
"LabelEnable": "Aktivér", "LabelEnable": "Aktivér",
"LabelEnd": "Slut", "LabelEnd": "Slut",
"LabelEndOfChapter": "Slutningen af kapitel",
"LabelEpisode": "Episode",
"LabelEpisodeTitle": "Episodetitel", "LabelEpisodeTitle": "Episodetitel",
"LabelEpisodeType": "Episodetype", "LabelEpisodeType": "Episodetype",
"LabelExample": "Eksempel", "LabelExample": "Eksempel",
"LabelExplicit": "Eksplisit", "LabelExplicit": "Eksplisit",
"LabelFeedURL": "Feed URL",
"LabelFile": "Fil", "LabelFile": "Fil",
"LabelFileBirthtime": "Fødselstidspunkt for fil", "LabelFileBirthtime": "Oprettelsestidspunkt for fil",
"LabelFileModified": "Fil ændret", "LabelFileModified": "Fil ændret",
"LabelFilename": "Filnavn", "LabelFilename": "Filnavn",
"LabelFilterByUser": "Filtrér efter bruger", "LabelFilterByUser": "Filtrér efter bruger",
@ -238,8 +247,10 @@
"LabelFinished": "Færdig", "LabelFinished": "Færdig",
"LabelFolder": "Mappe", "LabelFolder": "Mappe",
"LabelFolders": "Mapper", "LabelFolders": "Mapper",
"LabelFontBoldness": "Skrift tykkelse",
"LabelFontFamily": "Fontfamilie", "LabelFontFamily": "Fontfamilie",
"LabelFontScale": "Skriftstørrelse", "LabelFontScale": "Skriftstørrelse",
"LabelGenre": "Genre",
"LabelGenres": "Genrer", "LabelGenres": "Genrer",
"LabelHardDeleteFile": "Permanent slet fil", "LabelHardDeleteFile": "Permanent slet fil",
"LabelHasEbook": "Har e-bog", "LabelHasEbook": "Har e-bog",
@ -267,6 +278,7 @@
"LabelLastSeen": "Sidst set", "LabelLastSeen": "Sidst set",
"LabelLastTime": "Sidste gang", "LabelLastTime": "Sidste gang",
"LabelLastUpdate": "Seneste opdatering", "LabelLastUpdate": "Seneste opdatering",
"LabelLayout": "Layout",
"LabelLayoutSinglePage": "Enkeltside", "LabelLayoutSinglePage": "Enkeltside",
"LabelLayoutSplitPage": "Opdelt side", "LabelLayoutSplitPage": "Opdelt side",
"LabelLess": "Mindre", "LabelLess": "Mindre",
@ -344,10 +356,11 @@
"LabelRSSFeedPreventIndexing": "Forhindrer indeksering", "LabelRSSFeedPreventIndexing": "Forhindrer indeksering",
"LabelRSSFeedSlug": "RSS-feed-slug", "LabelRSSFeedSlug": "RSS-feed-slug",
"LabelRSSFeedURL": "RSS-feed-URL", "LabelRSSFeedURL": "RSS-feed-URL",
"LabelRandomly": "Tilfældigt",
"LabelRead": "Læst", "LabelRead": "Læst",
"LabelReadAgain": "Læs igen", "LabelReadAgain": "Læs igen",
"LabelReadEbookWithoutProgress": "Læs e-bog uden at følge fremskridt", "LabelReadEbookWithoutProgress": "Læs e-bog uden at følge fremskridt",
"LabelRecentSeries": "Seneste serie", "LabelRecentSeries": "Seneste serier",
"LabelRecentlyAdded": "Senest tilføjet", "LabelRecentlyAdded": "Senest tilføjet",
"LabelRecommended": "Anbefalet", "LabelRecommended": "Anbefalet",
"LabelReleaseDate": "Udgivelsesdato", "LabelReleaseDate": "Udgivelsesdato",
@ -604,10 +617,8 @@
"PlaceholderNewPlaylist": "Nyt afspilningslistnavn", "PlaceholderNewPlaylist": "Nyt afspilningslistnavn",
"PlaceholderSearch": "Søg..", "PlaceholderSearch": "Søg..",
"PlaceholderSearchEpisode": "Søg efter episode..", "PlaceholderSearchEpisode": "Søg efter episode..",
"ToastAccountUpdateFailed": "Mislykkedes opdatering af konto",
"ToastAccountUpdateSuccess": "Konto opdateret", "ToastAccountUpdateSuccess": "Konto opdateret",
"ToastAuthorImageRemoveSuccess": "Forfatterbillede fjernet", "ToastAuthorImageRemoveSuccess": "Forfatterbillede fjernet",
"ToastAuthorUpdateFailed": "Mislykkedes opdatering af forfatter",
"ToastAuthorUpdateMerged": "Forfatter fusioneret", "ToastAuthorUpdateMerged": "Forfatter fusioneret",
"ToastAuthorUpdateSuccess": "Forfatter opdateret", "ToastAuthorUpdateSuccess": "Forfatter opdateret",
"ToastAuthorUpdateSuccessNoImageFound": "Forfatter opdateret (ingen billede fundet)", "ToastAuthorUpdateSuccessNoImageFound": "Forfatter opdateret (ingen billede fundet)",
@ -623,17 +634,13 @@
"ToastBookmarkCreateFailed": "Mislykkedes oprettelse af bogmærke", "ToastBookmarkCreateFailed": "Mislykkedes oprettelse af bogmærke",
"ToastBookmarkCreateSuccess": "Bogmærke tilføjet", "ToastBookmarkCreateSuccess": "Bogmærke tilføjet",
"ToastBookmarkRemoveSuccess": "Bogmærke fjernet", "ToastBookmarkRemoveSuccess": "Bogmærke fjernet",
"ToastBookmarkUpdateFailed": "Mislykkedes opdatering af bogmærke",
"ToastBookmarkUpdateSuccess": "Bogmærke opdateret", "ToastBookmarkUpdateSuccess": "Bogmærke opdateret",
"ToastChaptersHaveErrors": "Kapitler har fejl", "ToastChaptersHaveErrors": "Kapitler har fejl",
"ToastChaptersMustHaveTitles": "Kapitler skal have titler", "ToastChaptersMustHaveTitles": "Kapitler skal have titler",
"ToastCollectionItemsRemoveSuccess": "Element(er) fjernet fra samlingen", "ToastCollectionItemsRemoveSuccess": "Element(er) fjernet fra samlingen",
"ToastCollectionRemoveSuccess": "Samling fjernet", "ToastCollectionRemoveSuccess": "Samling fjernet",
"ToastCollectionUpdateFailed": "Mislykkedes opdatering af samling",
"ToastCollectionUpdateSuccess": "Samling opdateret", "ToastCollectionUpdateSuccess": "Samling opdateret",
"ToastItemCoverUpdateFailed": "Mislykkedes opdatering af varens omslag",
"ToastItemCoverUpdateSuccess": "Varens omslag opdateret", "ToastItemCoverUpdateSuccess": "Varens omslag opdateret",
"ToastItemDetailsUpdateFailed": "Mislykkedes opdatering af varedetaljer",
"ToastItemDetailsUpdateSuccess": "Varedetaljer opdateret", "ToastItemDetailsUpdateSuccess": "Varedetaljer opdateret",
"ToastItemMarkedAsFinishedFailed": "Mislykkedes markering som afsluttet", "ToastItemMarkedAsFinishedFailed": "Mislykkedes markering som afsluttet",
"ToastItemMarkedAsFinishedSuccess": "Vare markeret som afsluttet", "ToastItemMarkedAsFinishedSuccess": "Vare markeret som afsluttet",
@ -645,12 +652,10 @@
"ToastLibraryDeleteSuccess": "Bibliotek slettet", "ToastLibraryDeleteSuccess": "Bibliotek slettet",
"ToastLibraryScanFailedToStart": "Mislykkedes start af skanning", "ToastLibraryScanFailedToStart": "Mislykkedes start af skanning",
"ToastLibraryScanStarted": "Biblioteksskanning startet", "ToastLibraryScanStarted": "Biblioteksskanning startet",
"ToastLibraryUpdateFailed": "Mislykkedes opdatering af bibliotek",
"ToastLibraryUpdateSuccess": "Bibliotek \"{0}\" opdateret", "ToastLibraryUpdateSuccess": "Bibliotek \"{0}\" opdateret",
"ToastPlaylistCreateFailed": "Mislykkedes oprettelse af afspilningsliste", "ToastPlaylistCreateFailed": "Mislykkedes oprettelse af afspilningsliste",
"ToastPlaylistCreateSuccess": "Afspilningsliste oprettet", "ToastPlaylistCreateSuccess": "Afspilningsliste oprettet",
"ToastPlaylistRemoveSuccess": "Afspilningsliste fjernet", "ToastPlaylistRemoveSuccess": "Afspilningsliste fjernet",
"ToastPlaylistUpdateFailed": "Mislykkedes opdatering af afspilningsliste",
"ToastPlaylistUpdateSuccess": "Afspilningsliste opdateret", "ToastPlaylistUpdateSuccess": "Afspilningsliste opdateret",
"ToastPodcastCreateFailed": "Mislykkedes oprettelse af podcast", "ToastPodcastCreateFailed": "Mislykkedes oprettelse af podcast",
"ToastPodcastCreateSuccess": "Podcast oprettet med succes", "ToastPodcastCreateSuccess": "Podcast oprettet med succes",

View file

@ -56,6 +56,7 @@
"ButtonOpenManager": "Manager öffnen", "ButtonOpenManager": "Manager öffnen",
"ButtonPause": "Pausieren", "ButtonPause": "Pausieren",
"ButtonPlay": "Abspielen", "ButtonPlay": "Abspielen",
"ButtonPlayAll": "Alles abspielen",
"ButtonPlaying": "Spielt", "ButtonPlaying": "Spielt",
"ButtonPlaylists": "Wiedergabelisten", "ButtonPlaylists": "Wiedergabelisten",
"ButtonPrevious": "Zurück", "ButtonPrevious": "Zurück",
@ -566,7 +567,7 @@
"LabelStatsMinutesListening": "Gehörte Minuten", "LabelStatsMinutesListening": "Gehörte Minuten",
"LabelStatsOverallDays": "Gesamte Tage", "LabelStatsOverallDays": "Gesamte Tage",
"LabelStatsOverallHours": "Gesamte Stunden", "LabelStatsOverallHours": "Gesamte Stunden",
"LabelStatsWeekListening": "Gehörte Wochen", "LabelStatsWeekListening": "Wochenhördauer",
"LabelSubtitle": "Untertitel", "LabelSubtitle": "Untertitel",
"LabelSupportedFileTypes": "Unterstützte Dateitypen", "LabelSupportedFileTypes": "Unterstützte Dateitypen",
"LabelTag": "Schlagwort", "LabelTag": "Schlagwort",
@ -776,6 +777,31 @@
"MessageShareExpiresIn": "Läuft in {0} ab", "MessageShareExpiresIn": "Läuft in {0} ab",
"MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein.", "MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein.",
"MessageStartPlaybackAtTime": "Start der Wiedergabe für \"{0}\" bei {1}?", "MessageStartPlaybackAtTime": "Start der Wiedergabe für \"{0}\" bei {1}?",
"MessageTaskAudioFileNotWritable": "Die Audiodatei \"{0}\" ist schreibgeschützt",
"MessageTaskCanceledByUser": "Aufgabe vom Benutzer abgebrochen",
"MessageTaskDownloadingEpisodeDescription": "Folge \"{0}\" wird heruntergeladen",
"MessageTaskEmbeddingMetadata": "Metadaten werden eingebettet",
"MessageTaskEmbeddingMetadataDescription": "Metadaten werden in Hörbuch \"{0}\" eingebettet",
"MessageTaskEncodingM4b": "M4B wird encodiert",
"MessageTaskEncodingM4bDescription": "Hörbuch \"{0}\" wird in eine einzelne m4b Datei encodiert",
"MessageTaskFailed": "Fehlgeschlagen",
"MessageTaskFailedToBackupAudioFile": "Sicherung der Audiodatei \"{0}\" fehlgeschlagen",
"MessageTaskFailedToCreateCacheDirectory": "Fehler beim erstellen des Cache-Verzeichnisses",
"MessageTaskFailedToEmbedMetadataInFile": "Einbetten der Metadaten in die Datei \"{0}\" fehlgeschlagen",
"MessageTaskFailedToMergeAudioFiles": "Fehler beim zusammenführen der Audiodateien",
"MessageTaskFailedToMoveM4bFile": "Fehler beim verschieben der m4b Datei",
"MessageTaskFailedToWriteMetadataFile": "Fehler beim schreiben der Metadaten-Datei",
"MessageTaskNoFilesToScan": "Keine Dateien zum scannen",
"MessageTaskOpmlImportDescription": "Podcasts von {0} RSS-Feeds werden ersrtellt",
"MessageTaskOpmlImportFeedDescription": "RSS-Feed \"{0}\" wird importiert",
"MessageTaskOpmlImportFeedFailed": "Podcast Feed konnte nicht geladen werden",
"MessageTaskOpmlImportFeedPodcastDescription": "Podcast \"{0}\" wird erstellt",
"MessageTaskOpmlImportFeedPodcastFailed": "Erstellen des Podcasts fehlgeschlagen",
"MessageTaskOpmlImportFinished": "{0} Podcasts hinzugefügt",
"MessageTaskScanItemsAdded": "{0} hinzugefügt",
"MessageTaskScanItemsMissing": "{0} fehlend",
"MessageTaskScanItemsUpdated": "{0} aktualisiert",
"MessageTaskScanNoChangesNeeded": "Keine Änderungen nötig",
"MessageThinking": "Nachdenken...", "MessageThinking": "Nachdenken...",
"MessageUploaderItemFailed": "Hochladen fehlgeschlagen", "MessageUploaderItemFailed": "Hochladen fehlgeschlagen",
"MessageUploaderItemSuccess": "Erfolgreich hochgeladen!", "MessageUploaderItemSuccess": "Erfolgreich hochgeladen!",
@ -816,14 +842,12 @@
"StatsTopNarrators": "TOP SPRECHER", "StatsTopNarrators": "TOP SPRECHER",
"StatsTotalDuration": "Mit einer totalen Dauer von…", "StatsTotalDuration": "Mit einer totalen Dauer von…",
"StatsYearInReview": "DAS JAHR IM RÜCKBLICK", "StatsYearInReview": "DAS JAHR IM RÜCKBLICK",
"ToastAccountUpdateFailed": "Aktualisierung des Kontos fehlgeschlagen",
"ToastAccountUpdateSuccess": "Konto aktualisiert", "ToastAccountUpdateSuccess": "Konto aktualisiert",
"ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig", "ToastAppriseUrlRequired": "Eine Apprise-URL ist notwendig",
"ToastAuthorImageRemoveSuccess": "Autorenbild entfernt", "ToastAuthorImageRemoveSuccess": "Autorenbild entfernt",
"ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden", "ToastAuthorNotFound": "Autor \"{0}\" nicht gefunden",
"ToastAuthorRemoveSuccess": "Autor entfernt", "ToastAuthorRemoveSuccess": "Autor entfernt",
"ToastAuthorSearchNotFound": "Autor nicht gefunden", "ToastAuthorSearchNotFound": "Autor nicht gefunden",
"ToastAuthorUpdateFailed": "Aktualisierung des Autors fehlgeschlagen",
"ToastAuthorUpdateMerged": "Autor zusammengeführt", "ToastAuthorUpdateMerged": "Autor zusammengeführt",
"ToastAuthorUpdateSuccess": "Autor aktualisiert", "ToastAuthorUpdateSuccess": "Autor aktualisiert",
"ToastAuthorUpdateSuccessNoImageFound": "Autor aktualisiert (kein Bild gefunden)", "ToastAuthorUpdateSuccessNoImageFound": "Autor aktualisiert (kein Bild gefunden)",
@ -834,7 +858,6 @@
"ToastBackupDeleteSuccess": "Sicherung gelöscht", "ToastBackupDeleteSuccess": "Sicherung gelöscht",
"ToastBackupInvalidMaxKeep": "Ungültige Anzahl aufzubewahrender Backups", "ToastBackupInvalidMaxKeep": "Ungültige Anzahl aufzubewahrender Backups",
"ToastBackupInvalidMaxSize": "Ungültige maximale Backupgröße", "ToastBackupInvalidMaxSize": "Ungültige maximale Backupgröße",
"ToastBackupPathUpdateFailed": "Der Backuppfad konnte nicht aktualisiert werden",
"ToastBackupRestoreFailed": "Sicherung konnte nicht wiederhergestellt werden", "ToastBackupRestoreFailed": "Sicherung konnte nicht wiederhergestellt werden",
"ToastBackupUploadFailed": "Sicherung konnte nicht hochgeladen werden", "ToastBackupUploadFailed": "Sicherung konnte nicht hochgeladen werden",
"ToastBackupUploadSuccess": "Sicherung hochgeladen", "ToastBackupUploadSuccess": "Sicherung hochgeladen",
@ -845,7 +868,6 @@
"ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden", "ToastBookmarkCreateFailed": "Lesezeichen konnte nicht erstellt werden",
"ToastBookmarkCreateSuccess": "Lesezeichen hinzugefügt", "ToastBookmarkCreateSuccess": "Lesezeichen hinzugefügt",
"ToastBookmarkRemoveSuccess": "Lesezeichen entfernt", "ToastBookmarkRemoveSuccess": "Lesezeichen entfernt",
"ToastBookmarkUpdateFailed": "Lesezeichenaktualisierung fehlgeschlagen",
"ToastBookmarkUpdateSuccess": "Lesezeichen aktualisiert", "ToastBookmarkUpdateSuccess": "Lesezeichen aktualisiert",
"ToastCachePurgeFailed": "Cache leeren fehlgeschlagen", "ToastCachePurgeFailed": "Cache leeren fehlgeschlagen",
"ToastCachePurgeSuccess": "Cache geleert", "ToastCachePurgeSuccess": "Cache geleert",
@ -856,7 +878,6 @@
"ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt", "ToastCollectionItemsAddSuccess": "Element(e) erfolgreich zur Sammlung hinzugefügt",
"ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt", "ToastCollectionItemsRemoveSuccess": "Medien aus der Sammlung entfernt",
"ToastCollectionRemoveSuccess": "Sammlung entfernt", "ToastCollectionRemoveSuccess": "Sammlung entfernt",
"ToastCollectionUpdateFailed": "Sammlung konnte nicht aktualisiert werden",
"ToastCollectionUpdateSuccess": "Sammlung aktualisiert", "ToastCollectionUpdateSuccess": "Sammlung aktualisiert",
"ToastCoverUpdateFailed": "Cover-Update fehlgeschlagen", "ToastCoverUpdateFailed": "Cover-Update fehlgeschlagen",
"ToastDeleteFileFailed": "Die Datei konnte nicht gelöscht werden", "ToastDeleteFileFailed": "Die Datei konnte nicht gelöscht werden",
@ -865,8 +886,6 @@
"ToastDeviceNameAlreadyExists": "E-Reader-Gerät mit diesem Namen existiert bereits", "ToastDeviceNameAlreadyExists": "E-Reader-Gerät mit diesem Namen existiert bereits",
"ToastDeviceTestEmailFailed": "Senden der Test-E-Mail fehlgeschlagen", "ToastDeviceTestEmailFailed": "Senden der Test-E-Mail fehlgeschlagen",
"ToastDeviceTestEmailSuccess": "Test-E-Mail gesendet", "ToastDeviceTestEmailSuccess": "Test-E-Mail gesendet",
"ToastDeviceUpdateFailed": "Das Gerät konnte nicht aktualisiert werden",
"ToastEmailSettingsUpdateFailed": "E-Mail-Einstellungen konnten nicht aktualisiert werden",
"ToastEmailSettingsUpdateSuccess": "E-Mail-Einstellungen aktualisiert", "ToastEmailSettingsUpdateSuccess": "E-Mail-Einstellungen aktualisiert",
"ToastEncodeCancelFailed": "Das Encoding konnte nicht abgebrochen werden", "ToastEncodeCancelFailed": "Das Encoding konnte nicht abgebrochen werden",
"ToastEncodeCancelSucces": "Encoding abgebrochen", "ToastEncodeCancelSucces": "Encoding abgebrochen",
@ -875,21 +894,16 @@
"ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden", "ToastErrorCannotShare": "Das kann nicht nativ auf diesem Gerät freigegeben werden",
"ToastFailedToLoadData": "Daten laden fehlgeschlagen", "ToastFailedToLoadData": "Daten laden fehlgeschlagen",
"ToastFailedToShare": "Fehler beim Teilen", "ToastFailedToShare": "Fehler beim Teilen",
"ToastFailedToUpdateAccount": "Fehler beim ändern des Accounts",
"ToastFailedToUpdateUser": "Fehler beim ändern des Benutzers",
"ToastInvalidImageUrl": "Ungültiger Bild URL", "ToastInvalidImageUrl": "Ungültiger Bild URL",
"ToastInvalidUrl": "Ungültiger URL", "ToastInvalidUrl": "Ungültiger URL",
"ToastItemCoverUpdateFailed": "Fehler bei der Aktualisierung des Titelbildes",
"ToastItemCoverUpdateSuccess": "Titelbild aktualisiert", "ToastItemCoverUpdateSuccess": "Titelbild aktualisiert",
"ToastItemDeletedFailed": "Fehler beim löschen des Artikels", "ToastItemDeletedFailed": "Fehler beim löschen des Artikels",
"ToastItemDeletedSuccess": "Artikel gelöscht", "ToastItemDeletedSuccess": "Artikel gelöscht",
"ToastItemDetailsUpdateFailed": "Fehler bei der Aktualisierung der Artikeldetails",
"ToastItemDetailsUpdateSuccess": "Artikeldetails aktualisiert", "ToastItemDetailsUpdateSuccess": "Artikeldetails aktualisiert",
"ToastItemMarkedAsFinishedFailed": "Fehler bei der Markierung des Artikels als \"Beendet\"", "ToastItemMarkedAsFinishedFailed": "Fehler bei der Markierung des Artikels als \"Beendet\"",
"ToastItemMarkedAsFinishedSuccess": "Artikel als \"Beendet\" markiert", "ToastItemMarkedAsFinishedSuccess": "Artikel als \"Beendet\" markiert",
"ToastItemMarkedAsNotFinishedFailed": "Fehler bei der Markierung des Artikels als \"Nicht Beendet\"", "ToastItemMarkedAsNotFinishedFailed": "Fehler bei der Markierung des Artikels als \"Nicht Beendet\"",
"ToastItemMarkedAsNotFinishedSuccess": "Artikel als \"Nicht Beendet\" markiert", "ToastItemMarkedAsNotFinishedSuccess": "Artikel als \"Nicht Beendet\" markiert",
"ToastItemUpdateFailed": "Fehler beim ändern des Artikels",
"ToastItemUpdateSuccess": "Artikel wurde verändert", "ToastItemUpdateSuccess": "Artikel wurde verändert",
"ToastLibraryCreateFailed": "Bibliothek konnte nicht erstellt werden", "ToastLibraryCreateFailed": "Bibliothek konnte nicht erstellt werden",
"ToastLibraryCreateSuccess": "Bibliothek \"{0}\" erstellt", "ToastLibraryCreateSuccess": "Bibliothek \"{0}\" erstellt",
@ -897,7 +911,6 @@
"ToastLibraryDeleteSuccess": "Bibliothek gelöscht", "ToastLibraryDeleteSuccess": "Bibliothek gelöscht",
"ToastLibraryScanFailedToStart": "Scan konnte nicht gestartet werden", "ToastLibraryScanFailedToStart": "Scan konnte nicht gestartet werden",
"ToastLibraryScanStarted": "Bibliotheksscan gestartet", "ToastLibraryScanStarted": "Bibliotheksscan gestartet",
"ToastLibraryUpdateFailed": "Aktualisierung der Bibliothek fehlgeschlagen",
"ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert", "ToastLibraryUpdateSuccess": "Bibliothek \"{0}\" aktualisiert",
"ToastNameEmailRequired": "Name und E-Mail sind erforderlich", "ToastNameEmailRequired": "Name und E-Mail sind erforderlich",
"ToastNameRequired": "Name ist erforderlich", "ToastNameRequired": "Name ist erforderlich",
@ -912,16 +925,13 @@
"ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung", "ToastNotificationDeleteFailed": "Fehler beim löschen der Benachrichtigung",
"ToastNotificationFailedMaximum": "Maximale Fehlversuche muss >= 0 sein", "ToastNotificationFailedMaximum": "Maximale Fehlversuche muss >= 0 sein",
"ToastNotificationQueueMaximum": "Maximale Benachrichtigungswarteschlange muss >= 0 sein", "ToastNotificationQueueMaximum": "Maximale Benachrichtigungswarteschlange muss >= 0 sein",
"ToastNotificationSettingsUpdateFailed": "Fehler beim ändern der Benachrichtigungseinstellungen",
"ToastNotificationSettingsUpdateSuccess": "Benachrichtigungseinstellungen geändert", "ToastNotificationSettingsUpdateSuccess": "Benachrichtigungseinstellungen geändert",
"ToastNotificationTestTriggerFailed": "Fehler beim Auslösen der Testbenachrichtigung", "ToastNotificationTestTriggerFailed": "Fehler beim Auslösen der Testbenachrichtigung",
"ToastNotificationTestTriggerSuccess": "Testbenachrichtigung ausgelöst", "ToastNotificationTestTriggerSuccess": "Testbenachrichtigung ausgelöst",
"ToastNotificationUpdateFailed": "Fehler bein ändern der Benachrichtigung",
"ToastNotificationUpdateSuccess": "Benachrichtigung geändert", "ToastNotificationUpdateSuccess": "Benachrichtigung geändert",
"ToastPlaylistCreateFailed": "Erstellen der Wiedergabeliste fehlgeschlagen", "ToastPlaylistCreateFailed": "Erstellen der Wiedergabeliste fehlgeschlagen",
"ToastPlaylistCreateSuccess": "Wiedergabeliste erstellt", "ToastPlaylistCreateSuccess": "Wiedergabeliste erstellt",
"ToastPlaylistRemoveSuccess": "Wiedergabeliste gelöscht", "ToastPlaylistRemoveSuccess": "Wiedergabeliste gelöscht",
"ToastPlaylistUpdateFailed": "Aktualisieren der Wiedergabeliste fehlgeschlagen",
"ToastPlaylistUpdateSuccess": "Wiedergabeliste aktualisiert", "ToastPlaylistUpdateSuccess": "Wiedergabeliste aktualisiert",
"ToastPodcastCreateFailed": "Podcast konnte nicht erstellt werden", "ToastPodcastCreateFailed": "Podcast konnte nicht erstellt werden",
"ToastPodcastCreateSuccess": "Podcast erstellt", "ToastPodcastCreateSuccess": "Podcast erstellt",
@ -950,7 +960,6 @@
"ToastSendEbookToDeviceSuccess": "E-Buch an Gerät „{0}“ gesendet", "ToastSendEbookToDeviceSuccess": "E-Buch an Gerät „{0}“ gesendet",
"ToastSeriesUpdateFailed": "Aktualisierung der Serien fehlgeschlagen", "ToastSeriesUpdateFailed": "Aktualisierung der Serien fehlgeschlagen",
"ToastSeriesUpdateSuccess": "Serien aktualisiert", "ToastSeriesUpdateSuccess": "Serien aktualisiert",
"ToastServerSettingsUpdateFailed": "Die Server-Einstellungen wurden nicht gespeichert",
"ToastServerSettingsUpdateSuccess": "Die Server-Einstellungen wurden geupdated", "ToastServerSettingsUpdateSuccess": "Die Server-Einstellungen wurden geupdated",
"ToastSessionCloseFailed": "Fehler beim schließen der Sitzung", "ToastSessionCloseFailed": "Fehler beim schließen der Sitzung",
"ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden", "ToastSessionDeleteFailed": "Sitzung konnte nicht gelöscht werden",
@ -961,7 +970,6 @@
"ToastSocketDisconnected": "Verbindung zum WebSocket verloren", "ToastSocketDisconnected": "Verbindung zum WebSocket verloren",
"ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen", "ToastSocketFailedToConnect": "Verbindung zum WebSocket fehlgeschlagen",
"ToastSortingPrefixesEmptyError": "Es muss mindestens ein Sortier-Prefix vorhanden sein", "ToastSortingPrefixesEmptyError": "Es muss mindestens ein Sortier-Prefix vorhanden sein",
"ToastSortingPrefixesUpdateFailed": "Update der Sortier-Prefixe ist fehlgeschlagen",
"ToastSortingPrefixesUpdateSuccess": "Die Sortier-Prefixe wirden geupdated ({0} Einträge)", "ToastSortingPrefixesUpdateSuccess": "Die Sortier-Prefixe wirden geupdated ({0} Einträge)",
"ToastTitleRequired": "Titel erforderlich", "ToastTitleRequired": "Titel erforderlich",
"ToastUnknownError": "Unbekannter Fehler", "ToastUnknownError": "Unbekannter Fehler",

View file

@ -465,6 +465,8 @@
"LabelPubDate": "Pub Date", "LabelPubDate": "Pub Date",
"LabelPublishYear": "Publish Year", "LabelPublishYear": "Publish Year",
"LabelPublishedDate": "Published {0}", "LabelPublishedDate": "Published {0}",
"LabelPublishedDecade": "Published Decade",
"LabelPublishedDecades": "Published Decades",
"LabelPublisher": "Publisher", "LabelPublisher": "Publisher",
"LabelPublishers": "Publishers", "LabelPublishers": "Publishers",
"LabelRSSFeedCustomOwnerEmail": "Custom owner Email", "LabelRSSFeedCustomOwnerEmail": "Custom owner Email",
@ -777,6 +779,38 @@
"MessageShareExpiresIn": "Expires in {0}", "MessageShareExpiresIn": "Expires in {0}",
"MessageShareURLWillBe": "Share URL will be <strong>{0}</strong>", "MessageShareURLWillBe": "Share URL will be <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?", "MessageStartPlaybackAtTime": "Start playback for \"{0}\" at {1}?",
"MessageTaskAudioFileNotWritable": "Audio file \"{0}\" is not writable",
"MessageTaskCanceledByUser": "Task canceled by user",
"MessageTaskDownloadingEpisodeDescription": "Downloading episode \"{0}\"",
"MessageTaskEmbeddingMetadata": "Embedding metadata",
"MessageTaskEmbeddingMetadataDescription": "Embedding metadata in audiobook \"{0}\"",
"MessageTaskEncodingM4b": "Encoding M4B",
"MessageTaskEncodingM4bDescription": "Encoding audiobook \"{0}\" into a single m4b file",
"MessageTaskFailed": "Failed",
"MessageTaskFailedToBackupAudioFile": "Failed to backup audio file \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "Failed to create cache directory",
"MessageTaskFailedToEmbedMetadataInFile": "Failed to embed metadata in file \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Failed to merge audio files",
"MessageTaskFailedToMoveM4bFile": "Failed to move m4b file",
"MessageTaskFailedToWriteMetadataFile": "Failed to write metadata file",
"MessageTaskMatchingBooksInLibrary": "Matching books in library \"{0}\"",
"MessageTaskNoFilesToScan": "No files to scan",
"MessageTaskOpmlImport": "OPML import",
"MessageTaskOpmlImportDescription": "Creating podcasts from {0} RSS feeds",
"MessageTaskOpmlImportFeed": "OPML import feed",
"MessageTaskOpmlImportFeedDescription": "Importing RSS feed \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Failed to get podcast feed",
"MessageTaskOpmlImportFeedPodcastDescription": "Creating podcast \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast already exists at path",
"MessageTaskOpmlImportFeedPodcastFailed": "Failed to create podcast",
"MessageTaskOpmlImportFinished": "Added {0} podcasts",
"MessageTaskScanItemsAdded": "{0} added",
"MessageTaskScanItemsMissing": "{0} missing",
"MessageTaskScanItemsUpdated": "{0} updated",
"MessageTaskScanNoChangesNeeded": "No changes needed",
"MessageTaskScanningFileChanges": "Scanning file changes in \"{0}\"",
"MessageTaskScanningLibrary": "Scanning \"{0}\" library",
"MessageTaskTargetDirectoryNotWritable": "Target directory is not writable",
"MessageThinking": "Thinking...", "MessageThinking": "Thinking...",
"MessageUploaderItemFailed": "Failed to upload", "MessageUploaderItemFailed": "Failed to upload",
"MessageUploaderItemSuccess": "Successfully Uploaded!", "MessageUploaderItemSuccess": "Successfully Uploaded!",
@ -817,14 +851,12 @@
"StatsTopNarrators": "TOP NARRATORS", "StatsTopNarrators": "TOP NARRATORS",
"StatsTotalDuration": "With a total duration of…", "StatsTotalDuration": "With a total duration of…",
"StatsYearInReview": "YEAR IN REVIEW", "StatsYearInReview": "YEAR IN REVIEW",
"ToastAccountUpdateFailed": "Failed to update account",
"ToastAccountUpdateSuccess": "Account updated", "ToastAccountUpdateSuccess": "Account updated",
"ToastAppriseUrlRequired": "Must enter an Apprise URL", "ToastAppriseUrlRequired": "Must enter an Apprise URL",
"ToastAuthorImageRemoveSuccess": "Author image removed", "ToastAuthorImageRemoveSuccess": "Author image removed",
"ToastAuthorNotFound": "Author \"{0}\" not found", "ToastAuthorNotFound": "Author \"{0}\" not found",
"ToastAuthorRemoveSuccess": "Author removed", "ToastAuthorRemoveSuccess": "Author removed",
"ToastAuthorSearchNotFound": "Author not found", "ToastAuthorSearchNotFound": "Author not found",
"ToastAuthorUpdateFailed": "Failed to update author",
"ToastAuthorUpdateMerged": "Author merged", "ToastAuthorUpdateMerged": "Author merged",
"ToastAuthorUpdateSuccess": "Author updated", "ToastAuthorUpdateSuccess": "Author updated",
"ToastAuthorUpdateSuccessNoImageFound": "Author updated (no image found)", "ToastAuthorUpdateSuccessNoImageFound": "Author updated (no image found)",
@ -835,7 +867,6 @@
"ToastBackupDeleteSuccess": "Backup deleted", "ToastBackupDeleteSuccess": "Backup deleted",
"ToastBackupInvalidMaxKeep": "Invalid number of backups to keep", "ToastBackupInvalidMaxKeep": "Invalid number of backups to keep",
"ToastBackupInvalidMaxSize": "Invalid maximum backup size", "ToastBackupInvalidMaxSize": "Invalid maximum backup size",
"ToastBackupPathUpdateFailed": "Failed to update backup path",
"ToastBackupRestoreFailed": "Failed to restore backup", "ToastBackupRestoreFailed": "Failed to restore backup",
"ToastBackupUploadFailed": "Failed to upload backup", "ToastBackupUploadFailed": "Failed to upload backup",
"ToastBackupUploadSuccess": "Backup uploaded", "ToastBackupUploadSuccess": "Backup uploaded",
@ -846,7 +877,6 @@
"ToastBookmarkCreateFailed": "Failed to create bookmark", "ToastBookmarkCreateFailed": "Failed to create bookmark",
"ToastBookmarkCreateSuccess": "Bookmark added", "ToastBookmarkCreateSuccess": "Bookmark added",
"ToastBookmarkRemoveSuccess": "Bookmark removed", "ToastBookmarkRemoveSuccess": "Bookmark removed",
"ToastBookmarkUpdateFailed": "Failed to update bookmark",
"ToastBookmarkUpdateSuccess": "Bookmark updated", "ToastBookmarkUpdateSuccess": "Bookmark updated",
"ToastCachePurgeFailed": "Failed to purge cache", "ToastCachePurgeFailed": "Failed to purge cache",
"ToastCachePurgeSuccess": "Cache purged successfully", "ToastCachePurgeSuccess": "Cache purged successfully",
@ -857,7 +887,6 @@
"ToastCollectionItemsAddSuccess": "Item(s) added to collection success", "ToastCollectionItemsAddSuccess": "Item(s) added to collection success",
"ToastCollectionItemsRemoveSuccess": "Item(s) removed from collection", "ToastCollectionItemsRemoveSuccess": "Item(s) removed from collection",
"ToastCollectionRemoveSuccess": "Collection removed", "ToastCollectionRemoveSuccess": "Collection removed",
"ToastCollectionUpdateFailed": "Failed to update collection",
"ToastCollectionUpdateSuccess": "Collection updated", "ToastCollectionUpdateSuccess": "Collection updated",
"ToastCoverUpdateFailed": "Cover update failed", "ToastCoverUpdateFailed": "Cover update failed",
"ToastDeleteFileFailed": "Failed to delete file", "ToastDeleteFileFailed": "Failed to delete file",
@ -866,8 +895,6 @@
"ToastDeviceNameAlreadyExists": "Ereader device with that name already exists", "ToastDeviceNameAlreadyExists": "Ereader device with that name already exists",
"ToastDeviceTestEmailFailed": "Failed to send test email", "ToastDeviceTestEmailFailed": "Failed to send test email",
"ToastDeviceTestEmailSuccess": "Test email sent", "ToastDeviceTestEmailSuccess": "Test email sent",
"ToastDeviceUpdateFailed": "Failed to update device",
"ToastEmailSettingsUpdateFailed": "Failed to update email settings",
"ToastEmailSettingsUpdateSuccess": "Email settings updated", "ToastEmailSettingsUpdateSuccess": "Email settings updated",
"ToastEncodeCancelFailed": "Failed to cancel encode", "ToastEncodeCancelFailed": "Failed to cancel encode",
"ToastEncodeCancelSucces": "Encode canceled", "ToastEncodeCancelSucces": "Encode canceled",
@ -876,21 +903,17 @@
"ToastErrorCannotShare": "Cannot share natively on this device", "ToastErrorCannotShare": "Cannot share natively on this device",
"ToastFailedToLoadData": "Failed to load data", "ToastFailedToLoadData": "Failed to load data",
"ToastFailedToShare": "Failed to share", "ToastFailedToShare": "Failed to share",
"ToastFailedToUpdateAccount": "Failed to update account", "ToastFailedToUpdate": "Failed to update",
"ToastFailedToUpdateUser": "Failed to update user",
"ToastInvalidImageUrl": "Invalid image URL", "ToastInvalidImageUrl": "Invalid image URL",
"ToastInvalidUrl": "Invalid URL", "ToastInvalidUrl": "Invalid URL",
"ToastItemCoverUpdateFailed": "Failed to update item cover",
"ToastItemCoverUpdateSuccess": "Item cover updated", "ToastItemCoverUpdateSuccess": "Item cover updated",
"ToastItemDeletedFailed": "Failed to delete item", "ToastItemDeletedFailed": "Failed to delete item",
"ToastItemDeletedSuccess": "Deleted item", "ToastItemDeletedSuccess": "Deleted item",
"ToastItemDetailsUpdateFailed": "Failed to update item details",
"ToastItemDetailsUpdateSuccess": "Item details updated", "ToastItemDetailsUpdateSuccess": "Item details updated",
"ToastItemMarkedAsFinishedFailed": "Failed to mark as Finished", "ToastItemMarkedAsFinishedFailed": "Failed to mark as Finished",
"ToastItemMarkedAsFinishedSuccess": "Item marked as Finished", "ToastItemMarkedAsFinishedSuccess": "Item marked as Finished",
"ToastItemMarkedAsNotFinishedFailed": "Failed to mark as Not Finished", "ToastItemMarkedAsNotFinishedFailed": "Failed to mark as Not Finished",
"ToastItemMarkedAsNotFinishedSuccess": "Item marked as Not Finished", "ToastItemMarkedAsNotFinishedSuccess": "Item marked as Not Finished",
"ToastItemUpdateFailed": "Failed to update item",
"ToastItemUpdateSuccess": "Item updated", "ToastItemUpdateSuccess": "Item updated",
"ToastLibraryCreateFailed": "Failed to create library", "ToastLibraryCreateFailed": "Failed to create library",
"ToastLibraryCreateSuccess": "Library \"{0}\" created", "ToastLibraryCreateSuccess": "Library \"{0}\" created",
@ -898,8 +921,8 @@
"ToastLibraryDeleteSuccess": "Library deleted", "ToastLibraryDeleteSuccess": "Library deleted",
"ToastLibraryScanFailedToStart": "Failed to start scan", "ToastLibraryScanFailedToStart": "Failed to start scan",
"ToastLibraryScanStarted": "Library scan started", "ToastLibraryScanStarted": "Library scan started",
"ToastLibraryUpdateFailed": "Failed to update library",
"ToastLibraryUpdateSuccess": "Library \"{0}\" updated", "ToastLibraryUpdateSuccess": "Library \"{0}\" updated",
"ToastMatchAllAuthorsFailed": "Failed to match all authors",
"ToastNameEmailRequired": "Name and email are required", "ToastNameEmailRequired": "Name and email are required",
"ToastNameRequired": "Name is required", "ToastNameRequired": "Name is required",
"ToastNewUserCreatedFailed": "Failed to create account: \"{0}\"", "ToastNewUserCreatedFailed": "Failed to create account: \"{0}\"",
@ -913,16 +936,13 @@
"ToastNotificationDeleteFailed": "Failed to delete notification", "ToastNotificationDeleteFailed": "Failed to delete notification",
"ToastNotificationFailedMaximum": "Max failed attempts must be >= 0", "ToastNotificationFailedMaximum": "Max failed attempts must be >= 0",
"ToastNotificationQueueMaximum": "Max notification queue must be >= 0", "ToastNotificationQueueMaximum": "Max notification queue must be >= 0",
"ToastNotificationSettingsUpdateFailed": "Failed to update notification settings",
"ToastNotificationSettingsUpdateSuccess": "Notification settings updated", "ToastNotificationSettingsUpdateSuccess": "Notification settings updated",
"ToastNotificationTestTriggerFailed": "Failed to trigger test notification", "ToastNotificationTestTriggerFailed": "Failed to trigger test notification",
"ToastNotificationTestTriggerSuccess": "Triggered test notification", "ToastNotificationTestTriggerSuccess": "Triggered test notification",
"ToastNotificationUpdateFailed": "Failed to update notification",
"ToastNotificationUpdateSuccess": "Notification updated", "ToastNotificationUpdateSuccess": "Notification updated",
"ToastPlaylistCreateFailed": "Failed to create playlist", "ToastPlaylistCreateFailed": "Failed to create playlist",
"ToastPlaylistCreateSuccess": "Playlist created", "ToastPlaylistCreateSuccess": "Playlist created",
"ToastPlaylistRemoveSuccess": "Playlist removed", "ToastPlaylistRemoveSuccess": "Playlist removed",
"ToastPlaylistUpdateFailed": "Failed to update playlist",
"ToastPlaylistUpdateSuccess": "Playlist updated", "ToastPlaylistUpdateSuccess": "Playlist updated",
"ToastPodcastCreateFailed": "Failed to create podcast", "ToastPodcastCreateFailed": "Failed to create podcast",
"ToastPodcastCreateSuccess": "Podcast created successfully", "ToastPodcastCreateSuccess": "Podcast created successfully",
@ -951,7 +971,6 @@
"ToastSendEbookToDeviceSuccess": "Ebook sent to device \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook sent to device \"{0}\"",
"ToastSeriesUpdateFailed": "Series update failed", "ToastSeriesUpdateFailed": "Series update failed",
"ToastSeriesUpdateSuccess": "Series update success", "ToastSeriesUpdateSuccess": "Series update success",
"ToastServerSettingsUpdateFailed": "Failed to update server settings",
"ToastServerSettingsUpdateSuccess": "Server settings updated", "ToastServerSettingsUpdateSuccess": "Server settings updated",
"ToastSessionCloseFailed": "Failed to close session", "ToastSessionCloseFailed": "Failed to close session",
"ToastSessionDeleteFailed": "Failed to delete session", "ToastSessionDeleteFailed": "Failed to delete session",
@ -962,7 +981,6 @@
"ToastSocketDisconnected": "Socket disconnected", "ToastSocketDisconnected": "Socket disconnected",
"ToastSocketFailedToConnect": "Socket failed to connect", "ToastSocketFailedToConnect": "Socket failed to connect",
"ToastSortingPrefixesEmptyError": "Must have at least 1 sorting prefix", "ToastSortingPrefixesEmptyError": "Must have at least 1 sorting prefix",
"ToastSortingPrefixesUpdateFailed": "Failed to update sorting prefixes",
"ToastSortingPrefixesUpdateSuccess": "Sorting prefixes updated ({0} items)", "ToastSortingPrefixesUpdateSuccess": "Sorting prefixes updated ({0} items)",
"ToastTitleRequired": "Title is required", "ToastTitleRequired": "Title is required",
"ToastUnknownError": "Unknown error", "ToastUnknownError": "Unknown error",

View file

@ -30,6 +30,7 @@
"ButtonEditChapters": "Editar Capítulo", "ButtonEditChapters": "Editar Capítulo",
"ButtonEditPodcast": "Editar Podcast", "ButtonEditPodcast": "Editar Podcast",
"ButtonEnable": "Permitir", "ButtonEnable": "Permitir",
"ButtonFireAndFail": "Ejecutado y fallido",
"ButtonFireOnTest": "Activar evento de prueba", "ButtonFireOnTest": "Activar evento de prueba",
"ButtonForceReScan": "Forzar Re-Escaneo", "ButtonForceReScan": "Forzar Re-Escaneo",
"ButtonFullPath": "Ruta de Acceso Completa", "ButtonFullPath": "Ruta de Acceso Completa",
@ -55,6 +56,7 @@
"ButtonOpenManager": "Abrir Editor", "ButtonOpenManager": "Abrir Editor",
"ButtonPause": "Pausar", "ButtonPause": "Pausar",
"ButtonPlay": "Reproducir", "ButtonPlay": "Reproducir",
"ButtonPlayAll": "Reproducir todo",
"ButtonPlaying": "Reproduciendo", "ButtonPlaying": "Reproduciendo",
"ButtonPlaylists": "Listas de reproducción", "ButtonPlaylists": "Listas de reproducción",
"ButtonPrevious": "Anterior", "ButtonPrevious": "Anterior",
@ -459,6 +461,7 @@
"LabelPrimaryEbook": "Ebook principal", "LabelPrimaryEbook": "Ebook principal",
"LabelProgress": "Progreso", "LabelProgress": "Progreso",
"LabelProvider": "Proveedor", "LabelProvider": "Proveedor",
"LabelProviderAuthorizationValue": "Valor del encabezado de autorización",
"LabelPubDate": "Fecha de publicación", "LabelPubDate": "Fecha de publicación",
"LabelPublishYear": "Año de publicación", "LabelPublishYear": "Año de publicación",
"LabelPublishedDate": "Publicado {0}", "LabelPublishedDate": "Publicado {0}",
@ -774,6 +777,38 @@
"MessageShareExpiresIn": "Caduduca en {0}", "MessageShareExpiresIn": "Caduduca en {0}",
"MessageShareURLWillBe": "La URL para compartir será <strong> {0} </strong>", "MessageShareURLWillBe": "La URL para compartir será <strong> {0} </strong>",
"MessageStartPlaybackAtTime": "Iniciar reproducción para \"{0}\" en {1}?", "MessageStartPlaybackAtTime": "Iniciar reproducción para \"{0}\" en {1}?",
"MessageTaskAudioFileNotWritable": "El archivo de audio \"{0}\" no se puede grabar",
"MessageTaskCanceledByUser": "Tarea cancelada por el usuario",
"MessageTaskDownloadingEpisodeDescription": "Descargando el episodio \"{0}\"",
"MessageTaskEmbeddingMetadata": "Inserción de metadatos",
"MessageTaskEmbeddingMetadataDescription": "Inserción de metadatos en el audiolibro \"{0}\"",
"MessageTaskEncodingM4b": "Codificación M4B",
"MessageTaskEncodingM4bDescription": "Codificación del audiolibro \"{0}\" en un único archivo m4b",
"MessageTaskFailed": "Fallida",
"MessageTaskFailedToBackupAudioFile": "Error en la copia de seguridad del archivo de audio \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "Error al crear el directorio de la caché",
"MessageTaskFailedToEmbedMetadataInFile": "Error al incrustar metadatos en el archivo \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Error al fusionar archivos de audio",
"MessageTaskFailedToMoveM4bFile": "Error al mover el archivo m4b",
"MessageTaskFailedToWriteMetadataFile": "Error al escribir el archivo de metadatos",
"MessageTaskMatchingBooksInLibrary": "Libros coincidentes en la biblioteca \"{0}\"",
"MessageTaskNoFilesToScan": "Sin archivos para escanear",
"MessageTaskOpmlImport": "Importar OPML",
"MessageTaskOpmlImportDescription": "Creando podcasts a partir de {0} fuentes RSS",
"MessageTaskOpmlImportFeed": "Feed de importación OPML",
"MessageTaskOpmlImportFeedDescription": "Importando el feed RSS \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "No se puede obtener el podcast",
"MessageTaskOpmlImportFeedPodcastDescription": "Creando podcast \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast ya existe en la ruta",
"MessageTaskOpmlImportFeedPodcastFailed": "Error al crear podcast",
"MessageTaskOpmlImportFinished": "Añadido {0} podcasts",
"MessageTaskScanItemsAdded": "{0} añadido",
"MessageTaskScanItemsMissing": "Falta {0}",
"MessageTaskScanItemsUpdated": "{0} actualizado",
"MessageTaskScanNoChangesNeeded": "No se necesitan cambios",
"MessageTaskScanningFileChanges": "Escaneando cambios en el archivo en \"{0}\"",
"MessageTaskScanningLibrary": "Escaneando la biblioteca \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "El directorio de destino no se puede escribir",
"MessageThinking": "Pensando...", "MessageThinking": "Pensando...",
"MessageUploaderItemFailed": "Error al Subir", "MessageUploaderItemFailed": "Error al Subir",
"MessageUploaderItemSuccess": "¡Éxito al Subir!", "MessageUploaderItemSuccess": "¡Éxito al Subir!",
@ -814,14 +849,12 @@
"StatsTopNarrators": "NARRADORES DESTACADOS", "StatsTopNarrators": "NARRADORES DESTACADOS",
"StatsTotalDuration": "Con una duración total de…", "StatsTotalDuration": "Con una duración total de…",
"StatsYearInReview": "RESEÑA DEL AÑO", "StatsYearInReview": "RESEÑA DEL AÑO",
"ToastAccountUpdateFailed": "Error al actualizar cuenta",
"ToastAccountUpdateSuccess": "Cuenta actualizada", "ToastAccountUpdateSuccess": "Cuenta actualizada",
"ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise", "ToastAppriseUrlRequired": "Debes ingresar una URL de Apprise",
"ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor", "ToastAuthorImageRemoveSuccess": "Se eliminó la imagen del autor",
"ToastAuthorNotFound": "No se encontró el autor \"{0}\"", "ToastAuthorNotFound": "No se encontró el autor \"{0}\"",
"ToastAuthorRemoveSuccess": "Autor eliminado", "ToastAuthorRemoveSuccess": "Autor eliminado",
"ToastAuthorSearchNotFound": "No se encontró al autor", "ToastAuthorSearchNotFound": "No se encontró al autor",
"ToastAuthorUpdateFailed": "Error al actualizar el autor",
"ToastAuthorUpdateMerged": "Autor combinado", "ToastAuthorUpdateMerged": "Autor combinado",
"ToastAuthorUpdateSuccess": "Autor actualizado", "ToastAuthorUpdateSuccess": "Autor actualizado",
"ToastAuthorUpdateSuccessNoImageFound": "Autor actualizado (Imagen no encontrada)", "ToastAuthorUpdateSuccessNoImageFound": "Autor actualizado (Imagen no encontrada)",
@ -832,7 +865,6 @@
"ToastBackupDeleteSuccess": "Respaldo eliminado", "ToastBackupDeleteSuccess": "Respaldo eliminado",
"ToastBackupInvalidMaxKeep": "Número no válido de copias de seguridad a conservar", "ToastBackupInvalidMaxKeep": "Número no válido de copias de seguridad a conservar",
"ToastBackupInvalidMaxSize": "Tamaño máximo de copia de seguridad no válido", "ToastBackupInvalidMaxSize": "Tamaño máximo de copia de seguridad no válido",
"ToastBackupPathUpdateFailed": "Error al actualizar la ruta de la copia de seguridad",
"ToastBackupRestoreFailed": "Error al restaurar el respaldo", "ToastBackupRestoreFailed": "Error al restaurar el respaldo",
"ToastBackupUploadFailed": "Error al subir el respaldo", "ToastBackupUploadFailed": "Error al subir el respaldo",
"ToastBackupUploadSuccess": "Respaldo cargado", "ToastBackupUploadSuccess": "Respaldo cargado",
@ -843,7 +875,6 @@
"ToastBookmarkCreateFailed": "Error al crear marcador", "ToastBookmarkCreateFailed": "Error al crear marcador",
"ToastBookmarkCreateSuccess": "Marcador Agregado", "ToastBookmarkCreateSuccess": "Marcador Agregado",
"ToastBookmarkRemoveSuccess": "Marcador eliminado", "ToastBookmarkRemoveSuccess": "Marcador eliminado",
"ToastBookmarkUpdateFailed": "Error al actualizar el marcador",
"ToastBookmarkUpdateSuccess": "Marcador actualizado", "ToastBookmarkUpdateSuccess": "Marcador actualizado",
"ToastCachePurgeFailed": "Error al purgar el caché", "ToastCachePurgeFailed": "Error al purgar el caché",
"ToastCachePurgeSuccess": "Caché purgado de manera exitosa", "ToastCachePurgeSuccess": "Caché purgado de manera exitosa",
@ -854,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "Artículo(s) añadido(s) a la colección correctamente", "ToastCollectionItemsAddSuccess": "Artículo(s) añadido(s) a la colección correctamente",
"ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección", "ToastCollectionItemsRemoveSuccess": "Elementos(s) removidos de la colección",
"ToastCollectionRemoveSuccess": "Colección removida", "ToastCollectionRemoveSuccess": "Colección removida",
"ToastCollectionUpdateFailed": "Error al actualizar la colección",
"ToastCollectionUpdateSuccess": "Colección actualizada", "ToastCollectionUpdateSuccess": "Colección actualizada",
"ToastCoverUpdateFailed": "Error al actualizar la cubierta", "ToastCoverUpdateFailed": "Error al actualizar la cubierta",
"ToastDeleteFileFailed": "Error el eliminar archivo", "ToastDeleteFileFailed": "Error el eliminar archivo",
@ -863,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "Un libro electrónico ya existe con ese nombre", "ToastDeviceNameAlreadyExists": "Un libro electrónico ya existe con ese nombre",
"ToastDeviceTestEmailFailed": "Error al enviar correo de prueba", "ToastDeviceTestEmailFailed": "Error al enviar correo de prueba",
"ToastDeviceTestEmailSuccess": "Correo electrónico de prueba enviado", "ToastDeviceTestEmailSuccess": "Correo electrónico de prueba enviado",
"ToastDeviceUpdateFailed": "Error al actualizar el dispositivo",
"ToastEmailSettingsUpdateFailed": "Error al actualizar la configuración del correo electrónico",
"ToastEmailSettingsUpdateSuccess": "Configuración del correo electrónico actualizada", "ToastEmailSettingsUpdateSuccess": "Configuración del correo electrónico actualizada",
"ToastEncodeCancelFailed": "No se pudo cancelar la codificación", "ToastEncodeCancelFailed": "No se pudo cancelar la codificación",
"ToastEncodeCancelSucces": "Codificación cancelada", "ToastEncodeCancelSucces": "Codificación cancelada",
@ -873,21 +901,17 @@
"ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo", "ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo",
"ToastFailedToLoadData": "Error al cargar data", "ToastFailedToLoadData": "Error al cargar data",
"ToastFailedToShare": "Error al compartir", "ToastFailedToShare": "Error al compartir",
"ToastFailedToUpdateAccount": "Error al actualizar la cuenta", "ToastFailedToUpdate": "Error al actualizar",
"ToastFailedToUpdateUser": "Error al actualizar el usuario",
"ToastInvalidImageUrl": "URL de la imagen no válida", "ToastInvalidImageUrl": "URL de la imagen no válida",
"ToastInvalidUrl": "URL no válida", "ToastInvalidUrl": "URL no válida",
"ToastItemCoverUpdateFailed": "Error al actualizar la portada del elemento",
"ToastItemCoverUpdateSuccess": "Portada del elemento actualizada", "ToastItemCoverUpdateSuccess": "Portada del elemento actualizada",
"ToastItemDeletedFailed": "Error al eliminar el elemento", "ToastItemDeletedFailed": "Error al eliminar el elemento",
"ToastItemDeletedSuccess": "Elemento borrado", "ToastItemDeletedSuccess": "Elemento borrado",
"ToastItemDetailsUpdateFailed": "Error al actualizar los detalles del elemento",
"ToastItemDetailsUpdateSuccess": "Detalles del Elemento Actualizados", "ToastItemDetailsUpdateSuccess": "Detalles del Elemento Actualizados",
"ToastItemMarkedAsFinishedFailed": "Error al marcar como terminado", "ToastItemMarkedAsFinishedFailed": "Error al marcar como terminado",
"ToastItemMarkedAsFinishedSuccess": "Elemento marcado como terminado", "ToastItemMarkedAsFinishedSuccess": "Elemento marcado como terminado",
"ToastItemMarkedAsNotFinishedFailed": "No se ha podido marcar como no finalizado", "ToastItemMarkedAsNotFinishedFailed": "No se ha podido marcar como no finalizado",
"ToastItemMarkedAsNotFinishedSuccess": "Elemento marcado como No Terminado", "ToastItemMarkedAsNotFinishedSuccess": "Elemento marcado como No Terminado",
"ToastItemUpdateFailed": "Error al actualizar el elemento",
"ToastItemUpdateSuccess": "Elemento actualizado", "ToastItemUpdateSuccess": "Elemento actualizado",
"ToastLibraryCreateFailed": "Error al crear biblioteca", "ToastLibraryCreateFailed": "Error al crear biblioteca",
"ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada", "ToastLibraryCreateSuccess": "Biblioteca \"{0}\" creada",
@ -895,7 +919,6 @@
"ToastLibraryDeleteSuccess": "Biblioteca eliminada", "ToastLibraryDeleteSuccess": "Biblioteca eliminada",
"ToastLibraryScanFailedToStart": "Error al iniciar el escaneo", "ToastLibraryScanFailedToStart": "Error al iniciar el escaneo",
"ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca", "ToastLibraryScanStarted": "Se inició el escaneo de la biblioteca",
"ToastLibraryUpdateFailed": "Error al actualizar la biblioteca",
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada", "ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" actualizada",
"ToastNameEmailRequired": "Nombre y correo electrónico obligatorios", "ToastNameEmailRequired": "Nombre y correo electrónico obligatorios",
"ToastNameRequired": "Nombre obligatorio", "ToastNameRequired": "Nombre obligatorio",
@ -910,16 +933,13 @@
"ToastNotificationDeleteFailed": "Error al borrar la notificación", "ToastNotificationDeleteFailed": "Error al borrar la notificación",
"ToastNotificationFailedMaximum": "El número máximo de intentos fallidos debe ser ≥ 0", "ToastNotificationFailedMaximum": "El número máximo de intentos fallidos debe ser ≥ 0",
"ToastNotificationQueueMaximum": "La cola de notificación máxima debe ser ≥ 0", "ToastNotificationQueueMaximum": "La cola de notificación máxima debe ser ≥ 0",
"ToastNotificationSettingsUpdateFailed": "Error al actualizar los ajustes de la notificación",
"ToastNotificationSettingsUpdateSuccess": "Ajustes de la notificación actualizados", "ToastNotificationSettingsUpdateSuccess": "Ajustes de la notificación actualizados",
"ToastNotificationTestTriggerFailed": "No se ha podido activar la notificación de prueba", "ToastNotificationTestTriggerFailed": "No se ha podido activar la notificación de prueba",
"ToastNotificationTestTriggerSuccess": "Notificación de prueba activada", "ToastNotificationTestTriggerSuccess": "Notificación de prueba activada",
"ToastNotificationUpdateFailed": "No se ha podido actualizar la notificación",
"ToastNotificationUpdateSuccess": "Notificación actualizada", "ToastNotificationUpdateSuccess": "Notificación actualizada",
"ToastPlaylistCreateFailed": "Error al crear la lista de reproducción", "ToastPlaylistCreateFailed": "Error al crear la lista de reproducción",
"ToastPlaylistCreateSuccess": "Lista de reproducción creada", "ToastPlaylistCreateSuccess": "Lista de reproducción creada",
"ToastPlaylistRemoveSuccess": "Lista de reproducción eliminada", "ToastPlaylistRemoveSuccess": "Lista de reproducción eliminada",
"ToastPlaylistUpdateFailed": "Error al actualizar la lista de reproducción",
"ToastPlaylistUpdateSuccess": "Lista de reproducción actualizada", "ToastPlaylistUpdateSuccess": "Lista de reproducción actualizada",
"ToastPodcastCreateFailed": "Error al crear podcast", "ToastPodcastCreateFailed": "Error al crear podcast",
"ToastPodcastCreateSuccess": "Podcast creado", "ToastPodcastCreateSuccess": "Podcast creado",
@ -948,7 +968,6 @@
"ToastSendEbookToDeviceSuccess": "Ebook enviado al dispositivo \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook enviado al dispositivo \"{0}\"",
"ToastSeriesUpdateFailed": "Error al actualizar la serie", "ToastSeriesUpdateFailed": "Error al actualizar la serie",
"ToastSeriesUpdateSuccess": "Serie actualizada", "ToastSeriesUpdateSuccess": "Serie actualizada",
"ToastServerSettingsUpdateFailed": "Error al actualizar configuración del servidor",
"ToastServerSettingsUpdateSuccess": "Configuración del servidor actualizada", "ToastServerSettingsUpdateSuccess": "Configuración del servidor actualizada",
"ToastSessionCloseFailed": "Error al cerrar la sesión", "ToastSessionCloseFailed": "Error al cerrar la sesión",
"ToastSessionDeleteFailed": "Error al eliminar sesión", "ToastSessionDeleteFailed": "Error al eliminar sesión",
@ -959,7 +978,6 @@
"ToastSocketDisconnected": "Socket desconectado", "ToastSocketDisconnected": "Socket desconectado",
"ToastSocketFailedToConnect": "Error al conectar al Socket", "ToastSocketFailedToConnect": "Error al conectar al Socket",
"ToastSortingPrefixesEmptyError": "Debe tener por lo menos 1 prefijo para ordenar", "ToastSortingPrefixesEmptyError": "Debe tener por lo menos 1 prefijo para ordenar",
"ToastSortingPrefixesUpdateFailed": "Error al actualizar los prefijos de ordenar",
"ToastSortingPrefixesUpdateSuccess": "Prefijos de ordenar actualizaron ({0} items)", "ToastSortingPrefixesUpdateSuccess": "Prefijos de ordenar actualizaron ({0} items)",
"ToastTitleRequired": "Título obligatorio", "ToastTitleRequired": "Título obligatorio",
"ToastUnknownError": "Error desconocido", "ToastUnknownError": "Error desconocido",

View file

@ -9,6 +9,7 @@
"ButtonApply": "Rakenda", "ButtonApply": "Rakenda",
"ButtonApplyChapters": "Rakenda peatükid", "ButtonApplyChapters": "Rakenda peatükid",
"ButtonAuthors": "Autorid", "ButtonAuthors": "Autorid",
"ButtonBack": "Tagasi",
"ButtonBrowseForFolder": "Sirvi kausta", "ButtonBrowseForFolder": "Sirvi kausta",
"ButtonCancel": "Tühista", "ButtonCancel": "Tühista",
"ButtonCancelEncode": "Tühista kodeerimine", "ButtonCancelEncode": "Tühista kodeerimine",
@ -18,6 +19,7 @@
"ButtonChooseFiles": "Vali failid", "ButtonChooseFiles": "Vali failid",
"ButtonClearFilter": "Tühista filter", "ButtonClearFilter": "Tühista filter",
"ButtonCloseFeed": "Sulge voog", "ButtonCloseFeed": "Sulge voog",
"ButtonCloseSession": "Sulge avatud sessioon",
"ButtonCollections": "Kogud", "ButtonCollections": "Kogud",
"ButtonConfigureScanner": "Konfigureeri skanner", "ButtonConfigureScanner": "Konfigureeri skanner",
"ButtonCreate": "Loo", "ButtonCreate": "Loo",
@ -27,6 +29,7 @@
"ButtonEdit": "Muuda", "ButtonEdit": "Muuda",
"ButtonEditChapters": "Muuda peatükke", "ButtonEditChapters": "Muuda peatükke",
"ButtonEditPodcast": "Muuda podcasti", "ButtonEditPodcast": "Muuda podcasti",
"ButtonEnable": "Aktiveeri",
"ButtonForceReScan": "Sunnitud uuestiskaneerimine", "ButtonForceReScan": "Sunnitud uuestiskaneerimine",
"ButtonFullPath": "Täielik asukoht", "ButtonFullPath": "Täielik asukoht",
"ButtonHide": "Peida", "ButtonHide": "Peida",
@ -43,13 +46,18 @@
"ButtonMatchAllAuthors": "Sobita kõik autorid", "ButtonMatchAllAuthors": "Sobita kõik autorid",
"ButtonMatchBooks": "Sobita raamatud", "ButtonMatchBooks": "Sobita raamatud",
"ButtonNevermind": "Pole tähtis", "ButtonNevermind": "Pole tähtis",
"ButtonNext": "Järgmine",
"ButtonNextChapter": "Järgmine peatükk", "ButtonNextChapter": "Järgmine peatükk",
"ButtonNextItemInQueue": "Järgmine kirje järjekorras",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Ava voog", "ButtonOpenFeed": "Ava voog",
"ButtonOpenManager": "Ava haldur", "ButtonOpenManager": "Ava haldur",
"ButtonPause": "Peata", "ButtonPause": "Peata",
"ButtonPlay": "Mängi", "ButtonPlay": "Mängi",
"ButtonPlayAll": "Mängi kõik",
"ButtonPlaying": "Mängib", "ButtonPlaying": "Mängib",
"ButtonPlaylists": "Esitusloendid", "ButtonPlaylists": "Esitusloendid",
"ButtonPrevious": "Eelmine",
"ButtonPreviousChapter": "Eelmine peatükk", "ButtonPreviousChapter": "Eelmine peatükk",
"ButtonPurgeAllCache": "Tühjenda kogu vahemälu", "ButtonPurgeAllCache": "Tühjenda kogu vahemälu",
"ButtonPurgeItemsCache": "Tühjenda esemete vahemälu", "ButtonPurgeItemsCache": "Tühjenda esemete vahemälu",
@ -58,6 +66,9 @@
"ButtonQuickMatch": "Kiire sobitamine", "ButtonQuickMatch": "Kiire sobitamine",
"ButtonReScan": "Uuestiskaneeri", "ButtonReScan": "Uuestiskaneeri",
"ButtonRead": "Loe", "ButtonRead": "Loe",
"ButtonReadLess": "Loe vähem",
"ButtonReadMore": "Loe rohkem",
"ButtonRefresh": "Värskenda",
"ButtonRemove": "Eemalda", "ButtonRemove": "Eemalda",
"ButtonRemoveAll": "Eemalda kõik", "ButtonRemoveAll": "Eemalda kõik",
"ButtonRemoveAllLibraryItems": "Eemalda kõik raamatukogu esemed", "ButtonRemoveAllLibraryItems": "Eemalda kõik raamatukogu esemed",
@ -211,7 +222,7 @@
"LabelBackupLocation": "Varukoopia asukoht", "LabelBackupLocation": "Varukoopia asukoht",
"LabelBackupsEnableAutomaticBackups": "Luba automaatsed varukoopiad", "LabelBackupsEnableAutomaticBackups": "Luba automaatsed varukoopiad",
"LabelBackupsEnableAutomaticBackupsHelp": "Varukoopiad salvestatakse /metadata/backups kausta", "LabelBackupsEnableAutomaticBackupsHelp": "Varukoopiad salvestatakse /metadata/backups kausta",
"LabelBackupsMaxBackupSize": "Maksimaalne varukoopia suurus (GB-des)", "LabelBackupsMaxBackupSize": "Maksimaalne varukoopia suurus (GB-des) (0 lõpmatu suuruse jaoks)",
"LabelBackupsMaxBackupSizeHelp": "Kaitsena valesti seadistamise vastu ebaõnnestuvad varukoopiad, kui need ületavad seadistatud suuruse.", "LabelBackupsMaxBackupSizeHelp": "Kaitsena valesti seadistamise vastu ebaõnnestuvad varukoopiad, kui need ületavad seadistatud suuruse.",
"LabelBackupsNumberToKeep": "Varukoopiate arv, mida hoida", "LabelBackupsNumberToKeep": "Varukoopiate arv, mida hoida",
"LabelBackupsNumberToKeepHelp": "Ühel ajal eemaldatakse ainult 1 varukoopia, seega kui teil on juba rohkem varukoopiaid kui siin määratud, peaksite need käsitsi eemaldama.", "LabelBackupsNumberToKeepHelp": "Ühel ajal eemaldatakse ainult 1 varukoopia, seega kui teil on juba rohkem varukoopiaid kui siin määratud, peaksite need käsitsi eemaldama.",
@ -449,7 +460,7 @@
"LabelSettingsHomePageBookshelfView": "Avaleht kasutage raamatukoguvaadet", "LabelSettingsHomePageBookshelfView": "Avaleht kasutage raamatukoguvaadet",
"LabelSettingsLibraryBookshelfView": "Raamatukogu kasutamiseks kasutage raamatukoguvaadet", "LabelSettingsLibraryBookshelfView": "Raamatukogu kasutamiseks kasutage raamatukoguvaadet",
"LabelSettingsParseSubtitles": "Lugege subtiitreid", "LabelSettingsParseSubtitles": "Lugege subtiitreid",
"LabelSettingsParseSubtitlesHelp": "Eraldage subtiitrid heliraamatu kaustade nimedest.<br>Subtiitrid peavad olema eraldatud \" - \".<br>Näiteks: \"Raamatu pealkiri - Siin on alapealkiri\" alapealkiri on \"Siin on alapealkiri\"", "LabelSettingsParseSubtitlesHelp": "Eraldage subtiitrid heliraamatu kaustade nimedest.<br>Subtiitrid peavad olema eraldatud kasutades \" - \".<br>Näiteks: \"Raamatu pealkiri - Siin on alapealkiri\" alapealkiri on \"Siin on alapealkiri\"",
"LabelSettingsPreferMatchedMetadata": "Eelista sobitatud metaandmeid", "LabelSettingsPreferMatchedMetadata": "Eelista sobitatud metaandmeid",
"LabelSettingsPreferMatchedMetadataHelp": "Sobitatud andmed kirjutavad Kiir Sobitamise kasutamisel üle üksikasjad.", "LabelSettingsPreferMatchedMetadataHelp": "Sobitatud andmed kirjutavad Kiir Sobitamise kasutamisel üle üksikasjad.",
"LabelSettingsSkipMatchingBooksWithASIN": "Jätke ASIN-iga sobituvad raamatud vahele", "LabelSettingsSkipMatchingBooksWithASIN": "Jätke ASIN-iga sobituvad raamatud vahele",
@ -682,10 +693,8 @@
"PlaceholderNewPlaylist": "Uue esitusloendi nimi", "PlaceholderNewPlaylist": "Uue esitusloendi nimi",
"PlaceholderSearch": "Otsi...", "PlaceholderSearch": "Otsi...",
"PlaceholderSearchEpisode": "Otsi episoodi...", "PlaceholderSearchEpisode": "Otsi episoodi...",
"ToastAccountUpdateFailed": "Konto värskendamine ebaõnnestus",
"ToastAccountUpdateSuccess": "Konto on värskendatud", "ToastAccountUpdateSuccess": "Konto on värskendatud",
"ToastAuthorImageRemoveSuccess": "Autori pilt on eemaldatud", "ToastAuthorImageRemoveSuccess": "Autori pilt on eemaldatud",
"ToastAuthorUpdateFailed": "Autori värskendamine ebaõnnestus",
"ToastAuthorUpdateMerged": "Autor liidetud", "ToastAuthorUpdateMerged": "Autor liidetud",
"ToastAuthorUpdateSuccess": "Autor värskendatud", "ToastAuthorUpdateSuccess": "Autor värskendatud",
"ToastAuthorUpdateSuccessNoImageFound": "Autor värskendatud (pilti ei leitud)", "ToastAuthorUpdateSuccessNoImageFound": "Autor värskendatud (pilti ei leitud)",
@ -701,17 +710,13 @@
"ToastBookmarkCreateFailed": "Järjehoidja loomine ebaõnnestus", "ToastBookmarkCreateFailed": "Järjehoidja loomine ebaõnnestus",
"ToastBookmarkCreateSuccess": "Järjehoidja lisatud", "ToastBookmarkCreateSuccess": "Järjehoidja lisatud",
"ToastBookmarkRemoveSuccess": "Järjehoidja eemaldatud", "ToastBookmarkRemoveSuccess": "Järjehoidja eemaldatud",
"ToastBookmarkUpdateFailed": "Järjehoidja värskendamine ebaõnnestus",
"ToastBookmarkUpdateSuccess": "Järjehoidja värskendatud", "ToastBookmarkUpdateSuccess": "Järjehoidja värskendatud",
"ToastChaptersHaveErrors": "Peatükkidel on vigu", "ToastChaptersHaveErrors": "Peatükkidel on vigu",
"ToastChaptersMustHaveTitles": "Peatükkidel peab olema pealkiri", "ToastChaptersMustHaveTitles": "Peatükkidel peab olema pealkiri",
"ToastCollectionItemsRemoveSuccess": "Üksus(ed) eemaldatud kogumist", "ToastCollectionItemsRemoveSuccess": "Üksus(ed) eemaldatud kogumist",
"ToastCollectionRemoveSuccess": "Kogum eemaldatud", "ToastCollectionRemoveSuccess": "Kogum eemaldatud",
"ToastCollectionUpdateFailed": "Kogumi värskendamine ebaõnnestus",
"ToastCollectionUpdateSuccess": "Kogum värskendatud", "ToastCollectionUpdateSuccess": "Kogum värskendatud",
"ToastItemCoverUpdateFailed": "Üksuse kaane värskendamine ebaõnnestus",
"ToastItemCoverUpdateSuccess": "Üksuse kaas värskendatud", "ToastItemCoverUpdateSuccess": "Üksuse kaas värskendatud",
"ToastItemDetailsUpdateFailed": "Üksuse üksikasjade värskendamine ebaõnnestus",
"ToastItemDetailsUpdateSuccess": "Üksuse üksikasjad värskendatud", "ToastItemDetailsUpdateSuccess": "Üksuse üksikasjad värskendatud",
"ToastItemMarkedAsFinishedFailed": "Märgistamine kui lõpetatud ebaõnnestus", "ToastItemMarkedAsFinishedFailed": "Märgistamine kui lõpetatud ebaõnnestus",
"ToastItemMarkedAsFinishedSuccess": "Üksus märgitud kui lõpetatud", "ToastItemMarkedAsFinishedSuccess": "Üksus märgitud kui lõpetatud",
@ -723,12 +728,10 @@
"ToastLibraryDeleteSuccess": "Raamatukogu kustutatud", "ToastLibraryDeleteSuccess": "Raamatukogu kustutatud",
"ToastLibraryScanFailedToStart": "Skanneerimine ei käivitunud", "ToastLibraryScanFailedToStart": "Skanneerimine ei käivitunud",
"ToastLibraryScanStarted": "Raamatukogu skaneerimine alustatud", "ToastLibraryScanStarted": "Raamatukogu skaneerimine alustatud",
"ToastLibraryUpdateFailed": "Raamatukogu värskendamine ebaõnnestus",
"ToastLibraryUpdateSuccess": "Raamatukogu \"{0}\" värskendatud", "ToastLibraryUpdateSuccess": "Raamatukogu \"{0}\" värskendatud",
"ToastPlaylistCreateFailed": "Esitusloendi loomine ebaõnnestus", "ToastPlaylistCreateFailed": "Esitusloendi loomine ebaõnnestus",
"ToastPlaylistCreateSuccess": "Esitusloend loodud", "ToastPlaylistCreateSuccess": "Esitusloend loodud",
"ToastPlaylistRemoveSuccess": "Esitusloend eemaldatud", "ToastPlaylistRemoveSuccess": "Esitusloend eemaldatud",
"ToastPlaylistUpdateFailed": "Esitusloendi värskendamine ebaõnnestus",
"ToastPlaylistUpdateSuccess": "Esitusloend värskendatud", "ToastPlaylistUpdateSuccess": "Esitusloend värskendatud",
"ToastPodcastCreateFailed": "Podcasti loomine ebaõnnestus", "ToastPodcastCreateFailed": "Podcasti loomine ebaõnnestus",
"ToastPodcastCreateSuccess": "Podcast loodud edukalt", "ToastPodcastCreateSuccess": "Podcast loodud edukalt",

View file

@ -19,6 +19,7 @@
"ButtonChooseFiles": "Valitse tiedostot", "ButtonChooseFiles": "Valitse tiedostot",
"ButtonClearFilter": "Poista suodatus", "ButtonClearFilter": "Poista suodatus",
"ButtonCloseFeed": "Sulje syöte", "ButtonCloseFeed": "Sulje syöte",
"ButtonCloseSession": "Sulje Avoin Sessio",
"ButtonCollections": "Kokoelmat", "ButtonCollections": "Kokoelmat",
"ButtonConfigureScanner": "Skannerin asetukset", "ButtonConfigureScanner": "Skannerin asetukset",
"ButtonCreate": "Luo", "ButtonCreate": "Luo",
@ -28,6 +29,9 @@
"ButtonEdit": "Muokkaa", "ButtonEdit": "Muokkaa",
"ButtonEditChapters": "Muokkaa lukuja", "ButtonEditChapters": "Muokkaa lukuja",
"ButtonEditPodcast": "Muokkaa podcastia", "ButtonEditPodcast": "Muokkaa podcastia",
"ButtonEnable": "Aktivoi",
"ButtonFireAndFail": "Laukaise ja epäonnistu",
"ButtonFireOnTest": "Laukaise onTest tapahtuma",
"ButtonForceReScan": "Pakota uudelleenskannaus", "ButtonForceReScan": "Pakota uudelleenskannaus",
"ButtonFullPath": "Koko polku", "ButtonFullPath": "Koko polku",
"ButtonHide": "Piilota", "ButtonHide": "Piilota",
@ -46,10 +50,13 @@
"ButtonNevermind": "Ei sittenkään", "ButtonNevermind": "Ei sittenkään",
"ButtonNext": "Seuraava", "ButtonNext": "Seuraava",
"ButtonNextChapter": "Seuraava luku", "ButtonNextChapter": "Seuraava luku",
"ButtonNextItemInQueue": "Seuraava jonossa",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Avaa syöte", "ButtonOpenFeed": "Avaa syöte",
"ButtonOpenManager": "Avaa hallinta", "ButtonOpenManager": "Avaa hallinta",
"ButtonPause": "Pysäytä", "ButtonPause": "Pysäytä",
"ButtonPlay": "Toista", "ButtonPlay": "Toista",
"ButtonPlayAll": "Toista kaikki",
"ButtonPlaying": "Toistetaan", "ButtonPlaying": "Toistetaan",
"ButtonPlaylists": "Soittolistat", "ButtonPlaylists": "Soittolistat",
"ButtonPrevious": "Edellinen", "ButtonPrevious": "Edellinen",
@ -90,6 +97,7 @@
"ButtonStats": "Tilastot", "ButtonStats": "Tilastot",
"ButtonSubmit": "Lähetä", "ButtonSubmit": "Lähetä",
"ButtonTest": "Testi", "ButtonTest": "Testi",
"ButtonUnlinkOpenId": "Poista OpenID linkitys",
"ButtonUpload": "Lähetä palvelimelle", "ButtonUpload": "Lähetä palvelimelle",
"ButtonUploadBackup": "Lähetä varmuuskopio", "ButtonUploadBackup": "Lähetä varmuuskopio",
"ButtonUploadCover": "Lähetä kansikuva", "ButtonUploadCover": "Lähetä kansikuva",
@ -102,6 +110,7 @@
"ErrorUploadFetchMetadataNoResults": "Metadatan haku epäonnistui, yritä päivittää Teoksen nimi ja/tai Tekijä", "ErrorUploadFetchMetadataNoResults": "Metadatan haku epäonnistui, yritä päivittää Teoksen nimi ja/tai Tekijä",
"ErrorUploadLacksTitle": "Pitää sisältää Nimi", "ErrorUploadLacksTitle": "Pitää sisältää Nimi",
"HeaderAccount": "Tili", "HeaderAccount": "Tili",
"HeaderAddCustomMetadataProvider": "Lisää mukautettu metadata tarjoaja",
"HeaderAdvanced": "Edistynyt", "HeaderAdvanced": "Edistynyt",
"HeaderAppriseNotificationSettings": "Apprise-ilmoitusasetukset", "HeaderAppriseNotificationSettings": "Apprise-ilmoitusasetukset",
"HeaderAudioTracks": "Ääniraidat", "HeaderAudioTracks": "Ääniraidat",
@ -126,38 +135,60 @@
"HeaderEreaderDevices": "E-lukijalaitteet", "HeaderEreaderDevices": "E-lukijalaitteet",
"HeaderEreaderSettings": "E-lukijan asetukset", "HeaderEreaderSettings": "E-lukijan asetukset",
"HeaderFiles": "Tiedostot", "HeaderFiles": "Tiedostot",
"HeaderFindChapters": "Etsi kappaleet",
"HeaderIgnoredFiles": "Ohitetut tiedostot", "HeaderIgnoredFiles": "Ohitetut tiedostot",
"HeaderLastListeningSession": "Edellinen kuuntelukerta",
"HeaderLatestEpisodes": "Viimeisimmät jaksot", "HeaderLatestEpisodes": "Viimeisimmät jaksot",
"HeaderLibraries": "Kirjastot", "HeaderLibraries": "Kirjastot",
"HeaderLibraryFiles": "Kirjaston tiedostot", "HeaderLibraryFiles": "Kirjaston tiedostot",
"HeaderLibraryStats": "Kirjaston tilastot", "HeaderLibraryStats": "Kirjaston tilastot",
"HeaderListeningSessions": "Kuuntelukerrat",
"HeaderListeningStats": "Kuuntelutilastot", "HeaderListeningStats": "Kuuntelutilastot",
"HeaderLogin": "Kirjaudu",
"HeaderLogs": "Lokit", "HeaderLogs": "Lokit",
"HeaderManageGenres": "Hallitse lajityyppejä",
"HeaderManageTags": "Hallitse tageja",
"HeaderMetadataToEmbed": "Sisällytettävä metadata",
"HeaderNewAccount": "Uusi tili", "HeaderNewAccount": "Uusi tili",
"HeaderNewLibrary": "Uusi kirjasto", "HeaderNewLibrary": "Uusi kirjasto",
"HeaderNotificationCreate": "Luo ilmoitus",
"HeaderNotificationUpdate": "Päivitä ilmoitus",
"HeaderNotifications": "Ilmoitukset", "HeaderNotifications": "Ilmoitukset",
"HeaderOpenRSSFeed": "Avaa RSS-syöte", "HeaderOpenRSSFeed": "Avaa RSS-syöte",
"HeaderOtherFiles": "Muut tiedostot", "HeaderOtherFiles": "Muut tiedostot",
"HeaderPermissions": "Käyttöoikeudet", "HeaderPermissions": "Käyttöoikeudet",
"HeaderPlayerQueue": "Soittimen jono",
"HeaderPlayerSettings": "Soittimen asetukset",
"HeaderPlaylist": "Soittolista", "HeaderPlaylist": "Soittolista",
"HeaderPlaylistItems": "Soittolistan kohteet", "HeaderPlaylistItems": "Soittolistan kohteet",
"HeaderPodcastsToAdd": "Lisättävät podcastit",
"HeaderPreviewCover": "Esikatsele kansikuvaa",
"HeaderRSSFeedGeneral": "RSS yksityiskohdat", "HeaderRSSFeedGeneral": "RSS yksityiskohdat",
"HeaderRSSFeedIsOpen": "RSS syöte on avoinna", "HeaderRSSFeedIsOpen": "RSS syöte on avoinna",
"HeaderRSSFeeds": "RSS syötteet",
"HeaderRemoveEpisode": "Poista jakso", "HeaderRemoveEpisode": "Poista jakso",
"HeaderRemoveEpisodes": "Poista {0} jaksoa", "HeaderRemoveEpisodes": "Poista {0} jaksoa",
"HeaderSchedule": "Ajoita", "HeaderSchedule": "Ajoita",
"HeaderScheduleLibraryScans": "Ajoita automaattiset kirjastoskannaukset", "HeaderScheduleLibraryScans": "Ajoita automaattiset kirjastoskannaukset",
"HeaderSession": "Istunto",
"HeaderSetBackupSchedule": "Aseta varmuuskopiointiaikataulu", "HeaderSetBackupSchedule": "Aseta varmuuskopiointiaikataulu",
"HeaderSettings": "Asetukset", "HeaderSettings": "Asetukset",
"HeaderSettingsExperimental": "Kokeelliset ominaisuudet", "HeaderSettingsExperimental": "Kokeelliset ominaisuudet",
"HeaderSettingsGeneral": "Yleiset",
"HeaderSleepTimer": "Uniajastin", "HeaderSleepTimer": "Uniajastin",
"HeaderStatsMinutesListeningChart": "Kuunteluminuutit (viim. 7 pv)", "HeaderStatsMinutesListeningChart": "Kuunteluminuutit (viim. 7 pv)",
"HeaderStatsRecentSessions": "Viimeaikaiset istunnot", "HeaderStatsRecentSessions": "Viimeaikaiset istunnot",
"HeaderStatsTop5Genres": "Top 5 lajityypit",
"HeaderTableOfContents": "Sisällysluettelo", "HeaderTableOfContents": "Sisällysluettelo",
"HeaderTools": "Työkalut", "HeaderTools": "Työkalut",
"HeaderUpdateAccount": "Päivitä tili",
"HeaderUpdateAuthor": "Päivitä kirjailija",
"HeaderUpdateLibrary": "Päivitä kirjasto",
"HeaderUsers": "Käyttäjät", "HeaderUsers": "Käyttäjät",
"HeaderYourStats": "Tilastosi", "HeaderYourStats": "Tilastosi",
"LabelAbridged": "Lyhennetty",
"LabelAccountType": "Tilin tyyppi", "LabelAccountType": "Tilin tyyppi",
"LabelAccountTypeAdmin": "Järjestelmänvalvoja",
"LabelAccountTypeGuest": "Vieras", "LabelAccountTypeGuest": "Vieras",
"LabelAccountTypeUser": "Käyttäjä", "LabelAccountTypeUser": "Käyttäjä",
"LabelActivity": "Toiminta", "LabelActivity": "Toiminta",
@ -166,22 +197,29 @@
"LabelAddToPlaylist": "Lisää soittolistaan", "LabelAddToPlaylist": "Lisää soittolistaan",
"LabelAddToPlaylistBatch": "Lisää {0} kohdetta soittolistaan", "LabelAddToPlaylistBatch": "Lisää {0} kohdetta soittolistaan",
"LabelAddedAt": "Lisätty listalle", "LabelAddedAt": "Lisätty listalle",
"LabelAddedDate": "Lisätty {0}",
"LabelAdminUsersOnly": "Vain järjestelmänvalvojat",
"LabelAll": "Kaikki", "LabelAll": "Kaikki",
"LabelAllUsers": "Kaikki käyttäjät", "LabelAllUsers": "Kaikki käyttäjät",
"LabelAllUsersExcludingGuests": "Kaikki käyttäjät vieraita lukuun ottamatta", "LabelAllUsersExcludingGuests": "Kaikki käyttäjät vieraita lukuun ottamatta",
"LabelAllUsersIncludingGuests": "Kaikki käyttäjät mukaan lukien vieraat", "LabelAllUsersIncludingGuests": "Kaikki käyttäjät mukaan lukien vieraat",
"LabelAlreadyInYourLibrary": "Jo kirjastossasi",
"LabelAuthor": "Tekijä", "LabelAuthor": "Tekijä",
"LabelAuthorFirstLast": "Tekijä (Etunimi Sukunimi)", "LabelAuthorFirstLast": "Tekijä (Etunimi Sukunimi)",
"LabelAuthorLastFirst": "Tekijä (Sukunimi, Etunimi)", "LabelAuthorLastFirst": "Tekijä (Sukunimi, Etunimi)",
"LabelAuthors": "Tekijät", "LabelAuthors": "Tekijät",
"LabelAutoDownloadEpisodes": "Lataa jaksot automaattisesti", "LabelAutoDownloadEpisodes": "Lataa jaksot automaattisesti",
"LabelBackToUser": "Takaisin käyttäjään",
"LabelBackupLocation": "Varmuuskopiointipaikka",
"LabelBackupsEnableAutomaticBackups": "Ota automaattinen varmuuskopiointi käyttöön", "LabelBackupsEnableAutomaticBackups": "Ota automaattinen varmuuskopiointi käyttöön",
"LabelBackupsEnableAutomaticBackupsHelp": "Varmuuskopiot tallennettu kansioon /metadata/backups", "LabelBackupsEnableAutomaticBackupsHelp": "Varmuuskopiot tallennettu kansioon /metadata/backups",
"LabelBackupsMaxBackupSize": "Varmuuskopion enimmäiskoko (Gt) (0 rajaton)", "LabelBackupsMaxBackupSize": "Varmuuskopion enimmäiskoko (Gt) (0 rajaton)",
"LabelBackupsNumberToKeep": "Säilytettävien varmuuskopioiden määrä", "LabelBackupsNumberToKeep": "Säilytettävien varmuuskopioiden määrä",
"LabelBitrate": "Bittinopeus",
"LabelBooks": "Kirjat", "LabelBooks": "Kirjat",
"LabelButtonText": "Painikkeen teksti", "LabelButtonText": "Painikkeen teksti",
"LabelChangePassword": "Vaihda salasana", "LabelChangePassword": "Vaihda salasana",
"LabelChannels": "Kanavat",
"LabelChapters": "Luvut", "LabelChapters": "Luvut",
"LabelClickForMoreInfo": "Napsauta saadaksesi lisätietoja", "LabelClickForMoreInfo": "Napsauta saadaksesi lisätietoja",
"LabelClosePlayer": "Sulje soitin", "LabelClosePlayer": "Sulje soitin",
@ -196,79 +234,205 @@
"LabelContinueSeries": "Jatka sarjoja", "LabelContinueSeries": "Jatka sarjoja",
"LabelCover": "Kansikuva", "LabelCover": "Kansikuva",
"LabelCoverImageURL": "Kansikuvan URL-osoite", "LabelCoverImageURL": "Kansikuvan URL-osoite",
"LabelCreatedAt": "Luotu",
"LabelCurrent": "Nykyinen", "LabelCurrent": "Nykyinen",
"LabelDays": "Päivää",
"LabelDescription": "Kuvaus", "LabelDescription": "Kuvaus",
"LabelDevice": "Laite", "LabelDevice": "Laite",
"LabelDeviceInfo": "Laitteen tiedot", "LabelDeviceInfo": "Laitteen tiedot",
"LabelDiscover": "Löydä",
"LabelDownload": "Lataa", "LabelDownload": "Lataa",
"LabelDownloadNEpisodes": "Lataa {0} jaksoa", "LabelDownloadNEpisodes": "Lataa {0} jaksoa",
"LabelDuration": "Kesto", "LabelDuration": "Kesto",
"LabelDurationComparisonLonger": "({0} pidempi)",
"LabelDurationComparisonShorter": "({0} lyhyempi)",
"LabelEbook": "E-kirja", "LabelEbook": "E-kirja",
"LabelEbooks": "E-kirjat", "LabelEbooks": "E-kirjat",
"LabelEdit": "Muokkaa", "LabelEdit": "Muokkaa",
"LabelEmail": "Sähköposti", "LabelEmail": "Sähköposti",
"LabelEmailSettingsTestAddress": "Testiosoite",
"LabelEmbeddedCover": "Upotettu kansikuva",
"LabelEnable": "Ota käyttöön", "LabelEnable": "Ota käyttöön",
"LabelEnd": "Loppu",
"LabelEndOfChapter": "Luvun loppu", "LabelEndOfChapter": "Luvun loppu",
"LabelEpisode": "Jakso", "LabelEpisode": "Jakso",
"LabelEpisodes": "Jaksot",
"LabelExample": "Esimerkki",
"LabelFeedURL": "Syötteen URL",
"LabelFile": "Tiedosto", "LabelFile": "Tiedosto",
"LabelFileBirthtime": "Tiedoston syntymäaika", "LabelFileBirthtime": "Tiedoston syntymäaika",
"LabelFileBornDate": "Syntynyt {0}",
"LabelFileModified": "Muutettu tiedosto", "LabelFileModified": "Muutettu tiedosto",
"LabelFileModifiedDate": "Muokattu {0}",
"LabelFilename": "Tiedostonimi", "LabelFilename": "Tiedostonimi",
"LabelFindEpisodes": "Etsi jaksoja",
"LabelFinished": "Valmis",
"LabelFolder": "Kansio", "LabelFolder": "Kansio",
"LabelFolders": "Kansiot",
"LabelGenre": "Lajityyppi",
"LabelGenres": "Lajityypit",
"LabelHost": "Isäntä",
"LabelHours": "Tunnit",
"LabelInProgress": "Kesken", "LabelInProgress": "Kesken",
"LabelIncomplete": "Keskeneräinen", "LabelIncomplete": "Keskeneräinen",
"LabelIntervalEvery12Hours": "12 tunnin välein",
"LabelIntervalEvery15Minutes": "15 minuutin välein",
"LabelIntervalEvery2Hours": "2 tunnin välein",
"LabelIntervalEvery30Minutes": "30 minuutin välein",
"LabelIntervalEvery6Hours": "6 tunnin välein",
"LabelIntervalEveryDay": "Joka päivä",
"LabelIntervalEveryHour": "Joka tunti",
"LabelItem": "Kohde",
"LabelLanguage": "Kieli", "LabelLanguage": "Kieli",
"LabelLanguageDefaultServer": "Palvelimen oletuskieli",
"LabelLanguages": "Kielet",
"LabelLastBookAdded": "Viimeisin lisätty kirja",
"LabelLibrary": "Kirjasto",
"LabelLineSpacing": "Riviväli",
"LabelListenAgain": "Kuuntele uudelleen", "LabelListenAgain": "Kuuntele uudelleen",
"LabelMediaType": "Mediatyyppi", "LabelMediaType": "Mediatyyppi",
"LabelMinute": "Minuutti",
"LabelMinutes": "Minuutit",
"LabelMore": "Lisää", "LabelMore": "Lisää",
"LabelMoreInfo": "Lisätietoja", "LabelMoreInfo": "Lisätietoja",
"LabelName": "Nimi", "LabelName": "Nimi",
"LabelNarrator": "Lukija", "LabelNarrator": "Lukija",
"LabelNarrators": "Lukijat", "LabelNarrators": "Lukijat",
"LabelNew": "Uusi",
"LabelNewPassword": "Uusi salasana",
"LabelNewestAuthors": "Uusimmat kirjailijat", "LabelNewestAuthors": "Uusimmat kirjailijat",
"LabelNewestEpisodes": "Uusimmat jaksot", "LabelNewestEpisodes": "Uusimmat jaksot",
"LabelNotStarted": "Ei aloitettu",
"LabelPassword": "Salasana", "LabelPassword": "Salasana",
"LabelPath": "Polku", "LabelPath": "Polku",
"LabelPermanent": "Pysyvä",
"LabelPermissionsAccessAllLibraries": "Käyttöoikeudet kaikkiin kirjastoihin",
"LabelPermissionsDelete": "Voi poistaa",
"LabelPermissionsDownload": "Voi ladata",
"LabelPermissionsUpdate": "Voi päivittää",
"LabelPermissionsUpload": "Voi lähettää",
"LabelPlaylists": "Soittolistat",
"LabelPodcast": "Podcast",
"LabelPodcasts": "Podcastit", "LabelPodcasts": "Podcastit",
"LabelPort": "Portti",
"LabelPublishYear": "Julkaisuvuosi", "LabelPublishYear": "Julkaisuvuosi",
"LabelPublisher": "Julkaisija",
"LabelPublishers": "Julkaisijat",
"LabelRSSFeedPreventIndexing": "Estä indeksointi", "LabelRSSFeedPreventIndexing": "Estä indeksointi",
"LabelRandomly": "Satunnaisesti",
"LabelRead": "Lue", "LabelRead": "Lue",
"LabelReadAgain": "Lue uudelleen", "LabelReadAgain": "Lue uudelleen",
"LabelRecentSeries": "Viimeisimmät sarjat", "LabelRecentSeries": "Viimeisimmät sarjat",
"LabelRecentlyAdded": "Viimeeksi lisätyt", "LabelRecentlyAdded": "Viimeeksi lisätyt",
"LabelRecommended": "Suositeltu",
"LabelRegion": "Alue",
"LabelRemoveCover": "Poista kansikuva",
"LabelSeason": "Kausi", "LabelSeason": "Kausi",
"LabelSelectAll": "Valitse kaikki",
"LabelSelectUsers": "Valitse käyttäjät",
"LabelSeries": "Sarja",
"LabelSeriesName": "Sarjan nimi",
"LabelSetEbookAsPrimary": "Aseta ensisijaiseksi", "LabelSetEbookAsPrimary": "Aseta ensisijaiseksi",
"LabelSetEbookAsSupplementary": "Aseta täydentäväksi", "LabelSetEbookAsSupplementary": "Aseta täydentäväksi",
"LabelSettingsAudiobooksOnly": "Vain äänikirjat",
"LabelSettingsChromecastSupport": "Chromecast-tuki",
"LabelSettingsExperimentalFeatures": "Kokeelliset ominaisuudet",
"LabelSettingsFindCovers": "Etsi kansikuvia",
"LabelShare": "Jaa",
"LabelShowAll": "Näytä kaikki", "LabelShowAll": "Näytä kaikki",
"LabelShowSeconds": "Näytä sekunnit",
"LabelSize": "Koko", "LabelSize": "Koko",
"LabelSleepTimer": "Uniajastin", "LabelSleepTimer": "Uniajastin",
"LabelStart": "Aloita",
"LabelStartTime": "Aloitusaika",
"LabelStatsAudioTracks": "Ääniraidat",
"LabelStatsBestDay": "Paras päivä",
"LabelStatsDailyAverage": "Päivittäinen keskiarvo", "LabelStatsDailyAverage": "Päivittäinen keskiarvo",
"LabelStatsDays": "Päivää",
"LabelStatsDaysListened": "Päivää kuunneltu",
"LabelStatsHours": "Tunnit",
"LabelStatsInARow": "peräjälkeen", "LabelStatsInARow": "peräjälkeen",
"LabelStatsMinutes": "minuuttia", "LabelStatsMinutes": "minuuttia",
"LabelStatsMinutesListening": "Minuuttia kuunneltu",
"LabelStatsWeekListening": "Viikon aikana kuunneltu",
"LabelTag": "Tägi",
"LabelTags": "Tägit",
"LabelTheme": "Teema", "LabelTheme": "Teema",
"LabelThemeDark": "Tumma", "LabelThemeDark": "Tumma",
"LabelThemeLight": "Kirkas", "LabelThemeLight": "Kirkas",
"LabelTimeRemaining": "{0} jäljellä", "LabelTimeRemaining": "{0} jäljellä",
"LabelTitle": "Nimi",
"LabelTotalDuration": "Kokonaiskesto",
"LabelTracks": "Raidat",
"LabelType": "Tyyppi", "LabelType": "Tyyppi",
"LabelUnknown": "Tuntematon",
"LabelUpdateCover": "Päivitä kansikuva",
"LabelUser": "Käyttäjä", "LabelUser": "Käyttäjä",
"LabelUsername": "Käyttäjätunnus", "LabelUsername": "Käyttäjätunnus",
"LabelValue": "Arvo",
"LabelVersion": "Versio",
"LabelYourBookmarks": "Kirjanmerkkisi", "LabelYourBookmarks": "Kirjanmerkkisi",
"LabelYourProgress": "Edistymisesi", "LabelYourProgress": "Edistymisesi",
"MessageDownloadingEpisode": "Ladataan jaksoa", "MessageDownloadingEpisode": "Ladataan jaksoa",
"MessageEpisodesQueuedForDownload": "{0} jaksoa on latausjonossa", "MessageEpisodesQueuedForDownload": "{0} jaksoa on latausjonossa",
"MessageFeedURLWillBe": "Syötteen URL tulee olemaan {0}",
"MessageFetching": "Haetaan...", "MessageFetching": "Haetaan...",
"MessageLoading": "Ladataan...", "MessageLoading": "Ladataan...",
"MessageMarkAsFinished": "Merkitse valmiiksi", "MessageMarkAsFinished": "Merkitse valmiiksi",
"MessageNoBookmarks": "Ei kirjanmerkkejä", "MessageNoBookmarks": "Ei kirjanmerkkejä",
"MessageNoChapters": "Ei kappaleita",
"MessageNoCoversFound": "Kansikuvia ei löydetty",
"MessageNoGenres": "Ei lajityyppejä",
"MessageNoItems": "Ei kohteita", "MessageNoItems": "Ei kohteita",
"MessageNoItemsFound": "Kohteita ei löytynyt", "MessageNoItemsFound": "Kohteita ei löytynyt",
"MessageNoListeningSessions": "Ei kuunteluistuntoja",
"MessageNoPodcastsFound": "Podcasteja ei löytynyt", "MessageNoPodcastsFound": "Podcasteja ei löytynyt",
"MessageNoUpdatesWereNecessary": "Päivityksiä ei tarvittu",
"MessageNoUserPlaylists": "Sinulla ei ole soittolistoja", "MessageNoUserPlaylists": "Sinulla ei ole soittolistoja",
"MessageOr": "tai",
"MessageReportBugsAndContribute": "Ilmoita virheistä, toivo ominaisuuksia ja osallistu", "MessageReportBugsAndContribute": "Ilmoita virheistä, toivo ominaisuuksia ja osallistu",
"MessageTaskFailed": "Epäonnistunut",
"StatsSessions": "istunnot",
"ToastAccountUpdateSuccess": "Tili päivitetty",
"ToastBookmarkCreateFailed": "Kirjanmerkin luominen epäonnistui", "ToastBookmarkCreateFailed": "Kirjanmerkin luominen epäonnistui",
"ToastBookmarkUpdateFailed": "Kirjanmerkin päivittäminen epäonnistui", "ToastCoverUpdateFailed": "Kansikuvan päivitys epäonnistui",
"ToastItemCoverUpdateSuccess": "Kohteen kansikuva päivitetty",
"ToastItemMarkedAsFinishedFailed": "Valmiiksi merkitseminen epäonnistui", "ToastItemMarkedAsFinishedFailed": "Valmiiksi merkitseminen epäonnistui",
"ToastItemMarkedAsNotFinishedFailed": "Valmiiksi merkitsemisen poisto epäonnistui",
"ToastItemUpdateSuccess": "Kohde päivitetty",
"ToastLibraryCreateFailed": "Kirjaston luominen epäonnistui",
"ToastLibraryCreateSuccess": "Kirjasto \"{0}\" luotu",
"ToastLibraryDeleteFailed": "Kirjaston poistaminen epäonnistui",
"ToastLibraryDeleteSuccess": "Kirjasto poistettu",
"ToastLibraryUpdateSuccess": "Kirjasto \"{0}\" päivitetty",
"ToastNewUserCreatedFailed": "Tilin \"{0}\" luominen epäonnistui",
"ToastNewUserCreatedSuccess": "Uusi tili luotu",
"ToastPlaylistCreateFailed": "Soittolistan luominen epäonnistui", "ToastPlaylistCreateFailed": "Soittolistan luominen epäonnistui",
"ToastPlaylistCreateSuccess": "Soittolista luotu",
"ToastPlaylistRemoveSuccess": "Soittolista poistettu",
"ToastPlaylistUpdateSuccess": "Soittolista päivitetty",
"ToastPodcastCreateFailed": "Podcastin luominen epäonnistui", "ToastPodcastCreateFailed": "Podcastin luominen epäonnistui",
"ToastPodcastCreateSuccess": "Podcastin luominen onnistui" "ToastPodcastCreateSuccess": "Podcastin luominen onnistui",
"ToastRSSFeedCloseFailed": "RSS syötteen sulkeminen epäonnistui",
"ToastRSSFeedCloseSuccess": "RSS syöte suljettu",
"ToastRemoveFailed": "Poistaminen epäonnistui",
"ToastRemoveItemFromCollectionFailed": "Kohteen poistaminen kokoelmasta epäonnistui",
"ToastRemoveItemFromCollectionSuccess": "Kohde poistettu kokoelmasta",
"ToastRenameFailed": "Uudelleennimeäminen epäonnistui",
"ToastSelectAtLeastOneUser": "Valitse ainakin yksi käyttäjä",
"ToastServerSettingsUpdateSuccess": "Palvelimen asetukset päivitetty",
"ToastSessionCloseFailed": "Istunnon sulkeminen epäonnistui",
"ToastSessionDeleteFailed": "Istunnon poistaminen epäonnistui",
"ToastSessionDeleteSuccess": "Istunto poistettu",
"ToastSocketConnected": "Yhteys saatu",
"ToastSocketDisconnected": "Yhteys katkaistu",
"ToastSocketFailedToConnect": "Yhteyden muodostus epäonnistui",
"ToastTitleRequired": "Otsikko on pakollinen",
"ToastUnknownError": "Tuntematon virhe",
"ToastUserDeleteFailed": "Käyttäjän poisto epäonnistui",
"ToastUserDeleteSuccess": "Käyttäjä poistettu",
"ToastUserPasswordChangeSuccess": "Salasana vaihdettu onnistuneesti",
"ToastUserPasswordMismatch": "Salasanat eivät täsmää",
"ToastUserPasswordMustChange": "Uusi salasana ei voi olla sama kuin vanha salasana",
"ToastUserRootRequireName": "Pääkäyttäjän nimi on pakollinen"
} }

View file

@ -9,7 +9,7 @@
"ButtonApply": "Appliquer", "ButtonApply": "Appliquer",
"ButtonApplyChapters": "Appliquer aux chapitres", "ButtonApplyChapters": "Appliquer aux chapitres",
"ButtonAuthors": "Auteurs", "ButtonAuthors": "Auteurs",
"ButtonBack": "Reculer", "ButtonBack": "Retour",
"ButtonBrowseForFolder": "Naviguer vers le répertoire", "ButtonBrowseForFolder": "Naviguer vers le répertoire",
"ButtonCancel": "Annuler", "ButtonCancel": "Annuler",
"ButtonCancelEncode": "Annuler lencodage", "ButtonCancelEncode": "Annuler lencodage",
@ -56,6 +56,7 @@
"ButtonOpenManager": "Ouvrir le gestionnaire", "ButtonOpenManager": "Ouvrir le gestionnaire",
"ButtonPause": "Pause", "ButtonPause": "Pause",
"ButtonPlay": "Lire", "ButtonPlay": "Lire",
"ButtonPlayAll": "Lire tout",
"ButtonPlaying": "En lecture", "ButtonPlaying": "En lecture",
"ButtonPlaylists": "Listes de lecture", "ButtonPlaylists": "Listes de lecture",
"ButtonPrevious": "Précédent", "ButtonPrevious": "Précédent",
@ -212,11 +213,11 @@
"LabelAccountTypeUser": "Utilisateur", "LabelAccountTypeUser": "Utilisateur",
"LabelActivity": "Activité", "LabelActivity": "Activité",
"LabelAddToCollection": "Ajouter à la collection", "LabelAddToCollection": "Ajouter à la collection",
"LabelAddToCollectionBatch": "Ajout de {0} livres à la lollection", "LabelAddToCollectionBatch": "Ajout de {0} livres à la collection",
"LabelAddToPlaylist": "Ajouter à la liste de lecture", "LabelAddToPlaylist": "Ajouter à la liste de lecture",
"LabelAddToPlaylistBatch": "{0} éléments ajoutés à la liste de lecture", "LabelAddToPlaylistBatch": "{0} éléments ajoutés à la liste de lecture",
"LabelAddedAt": "Date dajout", "LabelAddedAt": "Date dajout",
"LabelAddedDate": "{0} ajoutés", "LabelAddedDate": "Ajouté le {0}",
"LabelAdminUsersOnly": "Administrateurs uniquement", "LabelAdminUsersOnly": "Administrateurs uniquement",
"LabelAll": "Tout", "LabelAll": "Tout",
"LabelAllUsers": "Tous les utilisateurs", "LabelAllUsers": "Tous les utilisateurs",
@ -319,7 +320,7 @@
"LabelFetchingMetadata": "Récupération des métadonnées", "LabelFetchingMetadata": "Récupération des métadonnées",
"LabelFile": "Fichier", "LabelFile": "Fichier",
"LabelFileBirthtime": "Création du fichier", "LabelFileBirthtime": "Création du fichier",
"LabelFileBornDate": "Créé {0}", "LabelFileBornDate": "Créé le {0}",
"LabelFileModified": "Modification du fichier", "LabelFileModified": "Modification du fichier",
"LabelFileModifiedDate": "Modifié le {0}", "LabelFileModifiedDate": "Modifié le {0}",
"LabelFilename": "Nom de fichier", "LabelFilename": "Nom de fichier",
@ -463,7 +464,7 @@
"LabelProviderAuthorizationValue": "Valeur de len-tête dautorisation", "LabelProviderAuthorizationValue": "Valeur de len-tête dautorisation",
"LabelPubDate": "Date de publication", "LabelPubDate": "Date de publication",
"LabelPublishYear": "Année de publication", "LabelPublishYear": "Année de publication",
"LabelPublishedDate": "{0} publiés", "LabelPublishedDate": "Publié en {0}",
"LabelPublisher": "Éditeur", "LabelPublisher": "Éditeur",
"LabelPublishers": "Éditeurs", "LabelPublishers": "Éditeurs",
"LabelRSSFeedCustomOwnerEmail": "Courriel personnalisée du propriétaire", "LabelRSSFeedCustomOwnerEmail": "Courriel personnalisée du propriétaire",
@ -491,7 +492,7 @@
"LabelSeason": "Saison", "LabelSeason": "Saison",
"LabelSelectAll": "Tout sélectionner", "LabelSelectAll": "Tout sélectionner",
"LabelSelectAllEpisodes": "Sélectionner tous les épisodes", "LabelSelectAllEpisodes": "Sélectionner tous les épisodes",
"LabelSelectEpisodesShowing": "Sélectionner {0} episode(s) en cours", "LabelSelectEpisodesShowing": "Sélectionner {0} épisode(s) en cours",
"LabelSelectUsers": "Sélectionner les utilisateurs", "LabelSelectUsers": "Sélectionner les utilisateurs",
"LabelSendEbookToDevice": "Envoyer le livre numérique à…", "LabelSendEbookToDevice": "Envoyer le livre numérique à…",
"LabelSequence": "Séquence", "LabelSequence": "Séquence",
@ -776,6 +777,38 @@
"MessageShareExpiresIn": "Expire dans {0}", "MessageShareExpiresIn": "Expire dans {0}",
"MessageShareURLWillBe": "Ladresse de partage sera <strong>{0}</strong>", "MessageShareURLWillBe": "Ladresse de partage sera <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Démarrer la lecture pour « {0} » à {1} ?", "MessageStartPlaybackAtTime": "Démarrer la lecture pour « {0} » à {1} ?",
"MessageTaskAudioFileNotWritable": "Le fichier audio « {0} » nest pas accessible en écriture",
"MessageTaskCanceledByUser": "Tâche annulée par lutilisateur",
"MessageTaskDownloadingEpisodeDescription": "Téléchargement de l'épisode « {0} »",
"MessageTaskEmbeddingMetadata": "Intégration de métadonnées",
"MessageTaskEmbeddingMetadataDescription": "Intégration de métadonnées dans le livre audio « {0} »",
"MessageTaskEncodingM4b": "Encodage M4B",
"MessageTaskEncodingM4bDescription": "Encodage du livre audio « {0} » dans un seul fichier M4B",
"MessageTaskFailed": "Échec",
"MessageTaskFailedToBackupAudioFile": "Échec de la sauvegarde du fichier audio « {0} »",
"MessageTaskFailedToCreateCacheDirectory": "Échec de la création du répertoire de cache",
"MessageTaskFailedToEmbedMetadataInFile": "Échec de l'intégration des métadonnées dans le fichier « {0} »",
"MessageTaskFailedToMergeAudioFiles": "Échec de la fusion des fichiers audio",
"MessageTaskFailedToMoveM4bFile": "Échec du déplacement du fichier M4B",
"MessageTaskFailedToWriteMetadataFile": "Échec de lécriture du fichier de métadonnées",
"MessageTaskMatchingBooksInLibrary": "Livres correspondants dans la bibliothèque « {0} »",
"MessageTaskNoFilesToScan": "Aucun fichier à analyser",
"MessageTaskOpmlImport": "Importation OPML",
"MessageTaskOpmlImportDescription": "Création de podcasts à partir de {0} flux RSS",
"MessageTaskOpmlImportFeed": "Flux dimportation OPML",
"MessageTaskOpmlImportFeedDescription": "Importation du flux RSS « {0} »",
"MessageTaskOpmlImportFeedFailed": "Échec de lobtention du flux de podcast",
"MessageTaskOpmlImportFeedPodcastDescription": "Création du podcast « {0} »",
"MessageTaskOpmlImportFeedPodcastExists": "Le podcast existe déjà à cet emplacement",
"MessageTaskOpmlImportFeedPodcastFailed": "Échec de la création du podcast",
"MessageTaskOpmlImportFinished": "Ajout de {0} podcasts",
"MessageTaskScanItemsAdded": "{0} ajouté",
"MessageTaskScanItemsMissing": "{0} manquant",
"MessageTaskScanItemsUpdated": "{0} mis à jour",
"MessageTaskScanNoChangesNeeded": "Aucun changement nécessaire",
"MessageTaskScanningFileChanges": "Analyse des modifications du fichier dans « {0} »",
"MessageTaskScanningLibrary": "Analyse de la bibliothèque « {0} »",
"MessageTaskTargetDirectoryNotWritable": "Le répertoire cible nest pas accessible en écriture",
"MessageThinking": "Je cherche…", "MessageThinking": "Je cherche…",
"MessageUploaderItemFailed": "Échec du téléversement", "MessageUploaderItemFailed": "Échec du téléversement",
"MessageUploaderItemSuccess": "Téléversement effectué !", "MessageUploaderItemSuccess": "Téléversement effectué !",
@ -816,14 +849,12 @@
"StatsTopNarrators": "TOP NARRATEURS", "StatsTopNarrators": "TOP NARRATEURS",
"StatsTotalDuration": "Pour une durée totale de…", "StatsTotalDuration": "Pour une durée totale de…",
"StatsYearInReview": "BILAN DE LANNÉE", "StatsYearInReview": "BILAN DE LANNÉE",
"ToastAccountUpdateFailed": "Échec de la mise à jour du compte",
"ToastAccountUpdateSuccess": "Compte mis à jour", "ToastAccountUpdateSuccess": "Compte mis à jour",
"ToastAppriseUrlRequired": "Vous devez entrer une URL Apprise", "ToastAppriseUrlRequired": "Vous devez entrer une URL Apprise",
"ToastAuthorImageRemoveSuccess": "Image de lauteur supprimée", "ToastAuthorImageRemoveSuccess": "Image de lauteur supprimée",
"ToastAuthorNotFound": "Auteur \"{0}\" non trouvé", "ToastAuthorNotFound": "Auteur \"{0}\" non trouvé",
"ToastAuthorRemoveSuccess": "Auteur supprimé", "ToastAuthorRemoveSuccess": "Auteur supprimé",
"ToastAuthorSearchNotFound": "Auteur non trouvé", "ToastAuthorSearchNotFound": "Auteur non trouvé",
"ToastAuthorUpdateFailed": "Échec de la mise à jour de lauteur",
"ToastAuthorUpdateMerged": "Auteur fusionné", "ToastAuthorUpdateMerged": "Auteur fusionné",
"ToastAuthorUpdateSuccess": "Auteur mis à jour", "ToastAuthorUpdateSuccess": "Auteur mis à jour",
"ToastAuthorUpdateSuccessNoImageFound": "Auteur mis à jour (aucune image trouvée)", "ToastAuthorUpdateSuccessNoImageFound": "Auteur mis à jour (aucune image trouvée)",
@ -834,7 +865,6 @@
"ToastBackupDeleteSuccess": "Sauvegarde supprimée", "ToastBackupDeleteSuccess": "Sauvegarde supprimée",
"ToastBackupInvalidMaxKeep": "Nombre de sauvegardes à conserver invalide", "ToastBackupInvalidMaxKeep": "Nombre de sauvegardes à conserver invalide",
"ToastBackupInvalidMaxSize": "Taille maximale de sauvegarde invalide", "ToastBackupInvalidMaxSize": "Taille maximale de sauvegarde invalide",
"ToastBackupPathUpdateFailed": "Échec de la mise à jour du chemin de sauvegarde",
"ToastBackupRestoreFailed": "Échec de la restauration de sauvegarde", "ToastBackupRestoreFailed": "Échec de la restauration de sauvegarde",
"ToastBackupUploadFailed": "Échec du téléversement de sauvegarde", "ToastBackupUploadFailed": "Échec du téléversement de sauvegarde",
"ToastBackupUploadSuccess": "Sauvegarde téléversée", "ToastBackupUploadSuccess": "Sauvegarde téléversée",
@ -845,7 +875,6 @@
"ToastBookmarkCreateFailed": "Échec de la création de signet", "ToastBookmarkCreateFailed": "Échec de la création de signet",
"ToastBookmarkCreateSuccess": "Signet ajouté", "ToastBookmarkCreateSuccess": "Signet ajouté",
"ToastBookmarkRemoveSuccess": "Signet supprimé", "ToastBookmarkRemoveSuccess": "Signet supprimé",
"ToastBookmarkUpdateFailed": "Échec de la mise à jour de signet",
"ToastBookmarkUpdateSuccess": "Signet mis à jour", "ToastBookmarkUpdateSuccess": "Signet mis à jour",
"ToastCachePurgeFailed": "Échec de la purge du cache", "ToastCachePurgeFailed": "Échec de la purge du cache",
"ToastCachePurgeSuccess": "Cache purgé avec succès", "ToastCachePurgeSuccess": "Cache purgé avec succès",
@ -856,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "Ajout de(s) élément(s) à la collection réussi", "ToastCollectionItemsAddSuccess": "Ajout de(s) élément(s) à la collection réussi",
"ToastCollectionItemsRemoveSuccess": "Élément(s) supprimé(s) de la collection", "ToastCollectionItemsRemoveSuccess": "Élément(s) supprimé(s) de la collection",
"ToastCollectionRemoveSuccess": "Collection supprimée", "ToastCollectionRemoveSuccess": "Collection supprimée",
"ToastCollectionUpdateFailed": "Échec de la mise à jour de la collection",
"ToastCollectionUpdateSuccess": "Collection mise à jour", "ToastCollectionUpdateSuccess": "Collection mise à jour",
"ToastCoverUpdateFailed": "Échec de la mise à jour de la couverture", "ToastCoverUpdateFailed": "Échec de la mise à jour de la couverture",
"ToastDeleteFileFailed": "Échec de la suppression du fichier", "ToastDeleteFileFailed": "Échec de la suppression du fichier",
@ -865,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "Un appareil de lecture avec ce nom existe déjà", "ToastDeviceNameAlreadyExists": "Un appareil de lecture avec ce nom existe déjà",
"ToastDeviceTestEmailFailed": "Échec de lenvoi du courriel de test", "ToastDeviceTestEmailFailed": "Échec de lenvoi du courriel de test",
"ToastDeviceTestEmailSuccess": "Courriel de test envoyé", "ToastDeviceTestEmailSuccess": "Courriel de test envoyé",
"ToastDeviceUpdateFailed": "Échec de la mise à jour",
"ToastEmailSettingsUpdateFailed": "Échec de la mise à jour des paramètres de messagerie",
"ToastEmailSettingsUpdateSuccess": "Paramètres de messagerie mis à jour", "ToastEmailSettingsUpdateSuccess": "Paramètres de messagerie mis à jour",
"ToastEncodeCancelFailed": "Échec de lannulation de lencodage", "ToastEncodeCancelFailed": "Échec de lannulation de lencodage",
"ToastEncodeCancelSucces": "Encodage annulé", "ToastEncodeCancelSucces": "Encodage annulé",
@ -875,21 +901,16 @@
"ToastErrorCannotShare": "Impossible de partager nativement sur cet appareil", "ToastErrorCannotShare": "Impossible de partager nativement sur cet appareil",
"ToastFailedToLoadData": "Échec du chargement des données", "ToastFailedToLoadData": "Échec du chargement des données",
"ToastFailedToShare": "Échec du partage", "ToastFailedToShare": "Échec du partage",
"ToastFailedToUpdateAccount": "Échec de la mise à jour du compte",
"ToastFailedToUpdateUser": "La mise a jour de l'utilisateur à échouée",
"ToastInvalidImageUrl": "URL de l'image invalide", "ToastInvalidImageUrl": "URL de l'image invalide",
"ToastInvalidUrl": "URL invalide", "ToastInvalidUrl": "URL invalide",
"ToastItemCoverUpdateFailed": "Échec de la mise à jour de la couverture de lélément",
"ToastItemCoverUpdateSuccess": "Couverture mise à jour", "ToastItemCoverUpdateSuccess": "Couverture mise à jour",
"ToastItemDeletedFailed": "La suppression de l'élément à échouée", "ToastItemDeletedFailed": "La suppression de l'élément à échouée",
"ToastItemDeletedSuccess": "Élément supprimé", "ToastItemDeletedSuccess": "Élément supprimé",
"ToastItemDetailsUpdateFailed": "Échec de la mise à jour des détails de lélément",
"ToastItemDetailsUpdateSuccess": "Détails de lélément mis à jour", "ToastItemDetailsUpdateSuccess": "Détails de lélément mis à jour",
"ToastItemMarkedAsFinishedFailed": "Échec de lannotation terminée", "ToastItemMarkedAsFinishedFailed": "Échec de lannotation terminée",
"ToastItemMarkedAsFinishedSuccess": "Article marqué comme terminé", "ToastItemMarkedAsFinishedSuccess": "Article marqué comme terminé",
"ToastItemMarkedAsNotFinishedFailed": "Échec de lannotation non-terminée", "ToastItemMarkedAsNotFinishedFailed": "Échec de lannotation non-terminée",
"ToastItemMarkedAsNotFinishedSuccess": "Article marqué comme non-terminé", "ToastItemMarkedAsNotFinishedSuccess": "Article marqué comme non-terminé",
"ToastItemUpdateFailed": "La mise a jour de lélément à échoué",
"ToastItemUpdateSuccess": "Élément mis a jour", "ToastItemUpdateSuccess": "Élément mis a jour",
"ToastLibraryCreateFailed": "Échec de la création de bibliothèque", "ToastLibraryCreateFailed": "Échec de la création de bibliothèque",
"ToastLibraryCreateSuccess": "Bibliothèque « {0} » créée", "ToastLibraryCreateSuccess": "Bibliothèque « {0} » créée",
@ -897,7 +918,6 @@
"ToastLibraryDeleteSuccess": "Bibliothèque supprimée", "ToastLibraryDeleteSuccess": "Bibliothèque supprimée",
"ToastLibraryScanFailedToStart": "Échec du démarrage de lanalyse", "ToastLibraryScanFailedToStart": "Échec du démarrage de lanalyse",
"ToastLibraryScanStarted": "Analyse de la bibliothèque démarrée", "ToastLibraryScanStarted": "Analyse de la bibliothèque démarrée",
"ToastLibraryUpdateFailed": "Échec de la mise à jour de la bibliothèque",
"ToastLibraryUpdateSuccess": "Bibliothèque « {0} » mise à jour", "ToastLibraryUpdateSuccess": "Bibliothèque « {0} » mise à jour",
"ToastNameEmailRequired": "Le nom et le courriel sont requis", "ToastNameEmailRequired": "Le nom et le courriel sont requis",
"ToastNameRequired": "Le nom est requis", "ToastNameRequired": "Le nom est requis",
@ -912,16 +932,13 @@
"ToastNotificationDeleteFailed": "La suppression de la notification à échouée", "ToastNotificationDeleteFailed": "La suppression de la notification à échouée",
"ToastNotificationFailedMaximum": "Le nombre maximum de tentatives échouées doit être >= 0", "ToastNotificationFailedMaximum": "Le nombre maximum de tentatives échouées doit être >= 0",
"ToastNotificationQueueMaximum": "Le nombre de notification maximum doit être >= 0", "ToastNotificationQueueMaximum": "Le nombre de notification maximum doit être >= 0",
"ToastNotificationSettingsUpdateFailed": "La mise a jour des paramètres de notification a échouée",
"ToastNotificationSettingsUpdateSuccess": "Paramètres de notification mis à jour", "ToastNotificationSettingsUpdateSuccess": "Paramètres de notification mis à jour",
"ToastNotificationTestTriggerFailed": "L'envoi de la notification de test à échoué", "ToastNotificationTestTriggerFailed": "L'envoi de la notification de test à échoué",
"ToastNotificationTestTriggerSuccess": "Notification de test déclenchée", "ToastNotificationTestTriggerSuccess": "Notification de test déclenchée",
"ToastNotificationUpdateFailed": "Échec de la mise à jour de la notification",
"ToastNotificationUpdateSuccess": "Notification mise à jour", "ToastNotificationUpdateSuccess": "Notification mise à jour",
"ToastPlaylistCreateFailed": "Échec de la création de la liste de lecture", "ToastPlaylistCreateFailed": "Échec de la création de la liste de lecture",
"ToastPlaylistCreateSuccess": "Liste de lecture créée", "ToastPlaylistCreateSuccess": "Liste de lecture créée",
"ToastPlaylistRemoveSuccess": "Liste de lecture supprimée", "ToastPlaylistRemoveSuccess": "Liste de lecture supprimée",
"ToastPlaylistUpdateFailed": "Échec de la mise à jour de la liste de lecture",
"ToastPlaylistUpdateSuccess": "Liste de lecture mise à jour", "ToastPlaylistUpdateSuccess": "Liste de lecture mise à jour",
"ToastPodcastCreateFailed": "Échec de la création du podcast", "ToastPodcastCreateFailed": "Échec de la création du podcast",
"ToastPodcastCreateSuccess": "Podcast créé avec succès", "ToastPodcastCreateSuccess": "Podcast créé avec succès",
@ -950,7 +967,6 @@
"ToastSendEbookToDeviceSuccess": "Livre numérique envoyé à lappareil : {0}", "ToastSendEbookToDeviceSuccess": "Livre numérique envoyé à lappareil : {0}",
"ToastSeriesUpdateFailed": "Échec de la mise à jour de la série", "ToastSeriesUpdateFailed": "Échec de la mise à jour de la série",
"ToastSeriesUpdateSuccess": "Mise à jour de la série réussie", "ToastSeriesUpdateSuccess": "Mise à jour de la série réussie",
"ToastServerSettingsUpdateFailed": "Échec de la mise à jour des paramètres du serveur",
"ToastServerSettingsUpdateSuccess": "Mise à jour des paramètres du serveur", "ToastServerSettingsUpdateSuccess": "Mise à jour des paramètres du serveur",
"ToastSessionCloseFailed": "Échec de la fermeture de la session", "ToastSessionCloseFailed": "Échec de la fermeture de la session",
"ToastSessionDeleteFailed": "Échec de la suppression de session", "ToastSessionDeleteFailed": "Échec de la suppression de session",
@ -961,7 +977,6 @@
"ToastSocketDisconnected": "WebSocket déconnecté", "ToastSocketDisconnected": "WebSocket déconnecté",
"ToastSocketFailedToConnect": "Échec de la connexion WebSocket", "ToastSocketFailedToConnect": "Échec de la connexion WebSocket",
"ToastSortingPrefixesEmptyError": "Doit avoir au moins 1 préfixe de tri", "ToastSortingPrefixesEmptyError": "Doit avoir au moins 1 préfixe de tri",
"ToastSortingPrefixesUpdateFailed": "Échec de la mise à jour des préfixes de tri",
"ToastSortingPrefixesUpdateSuccess": "Mise à jour des préfixes de tri ({0} élément)", "ToastSortingPrefixesUpdateSuccess": "Mise à jour des préfixes de tri ({0} élément)",
"ToastTitleRequired": "Le titre est requis", "ToastTitleRequired": "Le titre est requis",
"ToastUnknownError": "Erreur inconnue", "ToastUnknownError": "Erreur inconnue",

View file

@ -701,10 +701,8 @@
"PlaceholderNewPlaylist": "שם רשימת השמעה חדשה", "PlaceholderNewPlaylist": "שם רשימת השמעה חדשה",
"PlaceholderSearch": "חיפוש..", "PlaceholderSearch": "חיפוש..",
"PlaceholderSearchEpisode": "חיפוש פרק..", "PlaceholderSearchEpisode": "חיפוש פרק..",
"ToastAccountUpdateFailed": "עדכון חשבון נכשל",
"ToastAccountUpdateSuccess": "חשבון עודכן בהצלחה", "ToastAccountUpdateSuccess": "חשבון עודכן בהצלחה",
"ToastAuthorImageRemoveSuccess": "תמונת המחבר הוסרה בהצלחה", "ToastAuthorImageRemoveSuccess": "תמונת המחבר הוסרה בהצלחה",
"ToastAuthorUpdateFailed": "עדכון המחבר נכשל",
"ToastAuthorUpdateMerged": "המחבר מוזג", "ToastAuthorUpdateMerged": "המחבר מוזג",
"ToastAuthorUpdateSuccess": "המחבר עודכן בהצלחה", "ToastAuthorUpdateSuccess": "המחבר עודכן בהצלחה",
"ToastAuthorUpdateSuccessNoImageFound": "המחבר עודכן (תמונה לא נמצאה)", "ToastAuthorUpdateSuccessNoImageFound": "המחבר עודכן (תמונה לא נמצאה)",
@ -720,17 +718,13 @@
"ToastBookmarkCreateFailed": "יצירת סימניה נכשלה", "ToastBookmarkCreateFailed": "יצירת סימניה נכשלה",
"ToastBookmarkCreateSuccess": "הסימניה נוספה בהצלחה", "ToastBookmarkCreateSuccess": "הסימניה נוספה בהצלחה",
"ToastBookmarkRemoveSuccess": "הסימניה הוסרה בהצלחה", "ToastBookmarkRemoveSuccess": "הסימניה הוסרה בהצלחה",
"ToastBookmarkUpdateFailed": "עדכון הסימניה נכשל",
"ToastBookmarkUpdateSuccess": "הסימניה עודכנה בהצלחה", "ToastBookmarkUpdateSuccess": "הסימניה עודכנה בהצלחה",
"ToastChaptersHaveErrors": "פרקים מכילים שגיאות", "ToastChaptersHaveErrors": "פרקים מכילים שגיאות",
"ToastChaptersMustHaveTitles": "פרקים חייבים לכלול כותרות", "ToastChaptersMustHaveTitles": "פרקים חייבים לכלול כותרות",
"ToastCollectionItemsRemoveSuccess": "הפריט(ים) הוסרו מהאוסף בהצלחה", "ToastCollectionItemsRemoveSuccess": "הפריט(ים) הוסרו מהאוסף בהצלחה",
"ToastCollectionRemoveSuccess": "האוסף הוסר בהצלחה", "ToastCollectionRemoveSuccess": "האוסף הוסר בהצלחה",
"ToastCollectionUpdateFailed": "עדכון האוסף נכשל",
"ToastCollectionUpdateSuccess": "האוסף עודכן בהצלחה", "ToastCollectionUpdateSuccess": "האוסף עודכן בהצלחה",
"ToastItemCoverUpdateFailed": "עדכון כריכת הפריט נכשל",
"ToastItemCoverUpdateSuccess": "כריכת הפריט עודכנה בהצלחה", "ToastItemCoverUpdateSuccess": "כריכת הפריט עודכנה בהצלחה",
"ToastItemDetailsUpdateFailed": "עדכון פרטי הפריט נכשל",
"ToastItemDetailsUpdateSuccess": "פרטי הפריט עודכנו בהצלחה", "ToastItemDetailsUpdateSuccess": "פרטי הפריט עודכנו בהצלחה",
"ToastItemMarkedAsFinishedFailed": "סימון כפריט כהושלם נכשל", "ToastItemMarkedAsFinishedFailed": "סימון כפריט כהושלם נכשל",
"ToastItemMarkedAsFinishedSuccess": "הפריט סומן כהושלם בהצלחה", "ToastItemMarkedAsFinishedSuccess": "הפריט סומן כהושלם בהצלחה",
@ -742,12 +736,10 @@
"ToastLibraryDeleteSuccess": "הספרייה נמחקה בהצלחה", "ToastLibraryDeleteSuccess": "הספרייה נמחקה בהצלחה",
"ToastLibraryScanFailedToStart": "הפעלת הסריקה נכשלה", "ToastLibraryScanFailedToStart": "הפעלת הסריקה נכשלה",
"ToastLibraryScanStarted": "הסריקה של הספרייה החלה", "ToastLibraryScanStarted": "הסריקה של הספרייה החלה",
"ToastLibraryUpdateFailed": "עדכון הספרייה נכשל",
"ToastLibraryUpdateSuccess": "הספרייה \"{0}\" עודכנה בהצלחה", "ToastLibraryUpdateSuccess": "הספרייה \"{0}\" עודכנה בהצלחה",
"ToastPlaylistCreateFailed": "יצירת רשימת השמעה נכשלה", "ToastPlaylistCreateFailed": "יצירת רשימת השמעה נכשלה",
"ToastPlaylistCreateSuccess": "רשימת השמעה נוצרה בהצלחה", "ToastPlaylistCreateSuccess": "רשימת השמעה נוצרה בהצלחה",
"ToastPlaylistRemoveSuccess": "רשימת השמעה הוסרה בהצלחה", "ToastPlaylistRemoveSuccess": "רשימת השמעה הוסרה בהצלחה",
"ToastPlaylistUpdateFailed": "עדכון רשימת השמעה נכשל",
"ToastPlaylistUpdateSuccess": "רשימת השמעה עודכנה בהצלחה", "ToastPlaylistUpdateSuccess": "רשימת השמעה עודכנה בהצלחה",
"ToastPodcastCreateFailed": "יצירת הפודקאסט נכשלה", "ToastPodcastCreateFailed": "יצירת הפודקאסט נכשלה",
"ToastPodcastCreateSuccess": "הפודקאסט נוצר בהצלחה", "ToastPodcastCreateSuccess": "הפודקאסט נוצר בהצלחה",
@ -759,7 +751,6 @@
"ToastSendEbookToDeviceSuccess": "הספר נשלח אל המכשיר \"{0}\"", "ToastSendEbookToDeviceSuccess": "הספר נשלח אל המכשיר \"{0}\"",
"ToastSeriesUpdateFailed": "עדכון הסדרה נכשל", "ToastSeriesUpdateFailed": "עדכון הסדרה נכשל",
"ToastSeriesUpdateSuccess": "הסדרה עודכנה בהצלחה", "ToastSeriesUpdateSuccess": "הסדרה עודכנה בהצלחה",
"ToastServerSettingsUpdateFailed": "כשל בעדכון הגדרות שרת",
"ToastServerSettingsUpdateSuccess": "הגדרות שרת עודכנו בהצלחה", "ToastServerSettingsUpdateSuccess": "הגדרות שרת עודכנו בהצלחה",
"ToastSessionDeleteFailed": "מחיקת הפעולה נכשלה", "ToastSessionDeleteFailed": "מחיקת הפעולה נכשלה",
"ToastSessionDeleteSuccess": "הפעולה נמחקה בהצלחה", "ToastSessionDeleteSuccess": "הפעולה נמחקה בהצלחה",

View file

@ -56,6 +56,7 @@
"ButtonOpenManager": "Otvori Upravitelja", "ButtonOpenManager": "Otvori Upravitelja",
"ButtonPause": "Pauziraj", "ButtonPause": "Pauziraj",
"ButtonPlay": "Reproduciraj", "ButtonPlay": "Reproduciraj",
"ButtonPlayAll": "Reproduciraj sve",
"ButtonPlaying": "Izvodi se", "ButtonPlaying": "Izvodi se",
"ButtonPlaylists": "Popisi za izvođenje", "ButtonPlaylists": "Popisi za izvođenje",
"ButtonPrevious": "Prethodno", "ButtonPrevious": "Prethodno",
@ -96,7 +97,7 @@
"ButtonStartM4BEncode": "Pokreni M4B kodiranje", "ButtonStartM4BEncode": "Pokreni M4B kodiranje",
"ButtonStartMetadataEmbed": "Pokreni ugradnju meta-podataka", "ButtonStartMetadataEmbed": "Pokreni ugradnju meta-podataka",
"ButtonStats": "Statistika", "ButtonStats": "Statistika",
"ButtonSubmit": "Podnesi", "ButtonSubmit": "Pošalji",
"ButtonTest": "Test", "ButtonTest": "Test",
"ButtonUnlinkOpenId": "Prekini vezu s OpenID-jem", "ButtonUnlinkOpenId": "Prekini vezu s OpenID-jem",
"ButtonUpload": "Učitaj", "ButtonUpload": "Učitaj",
@ -266,7 +267,7 @@
"LabelContinueSeries": "Nastavi serijal", "LabelContinueSeries": "Nastavi serijal",
"LabelCover": "Naslovnica", "LabelCover": "Naslovnica",
"LabelCoverImageURL": "URL naslovnice", "LabelCoverImageURL": "URL naslovnice",
"LabelCreatedAt": "Stvoreno", "LabelCreatedAt": "Izrađen",
"LabelCronExpression": "Cron izraz", "LabelCronExpression": "Cron izraz",
"LabelCurrent": "Trenutan", "LabelCurrent": "Trenutan",
"LabelCurrently": "Trenutno:", "LabelCurrently": "Trenutno:",
@ -368,7 +369,7 @@
"LabelLanguages": "Jezici", "LabelLanguages": "Jezici",
"LabelLastBookAdded": "Zadnja dodana knjiga", "LabelLastBookAdded": "Zadnja dodana knjiga",
"LabelLastBookUpdated": "Zadnja ažurirana knjiga", "LabelLastBookUpdated": "Zadnja ažurirana knjiga",
"LabelLastSeen": "Zadnje pogledano", "LabelLastSeen": "Zadnji puta viđen",
"LabelLastTime": "Zadnji puta", "LabelLastTime": "Zadnji puta",
"LabelLastUpdate": "Zadnje ažuriranje", "LabelLastUpdate": "Zadnje ažuriranje",
"LabelLayout": "Prikaz", "LabelLayout": "Prikaz",
@ -411,7 +412,7 @@
"LabelNew": "Novo", "LabelNew": "Novo",
"LabelNewPassword": "Nova zaporka", "LabelNewPassword": "Nova zaporka",
"LabelNewestAuthors": "Najnoviji autori", "LabelNewestAuthors": "Najnoviji autori",
"LabelNewestEpisodes": "Najnoviji nastavci", "LabelNewestEpisodes": "Najnovije epizode",
"LabelNextBackupDate": "Sljedeće izrada sigurnosne kopije", "LabelNextBackupDate": "Sljedeće izrada sigurnosne kopije",
"LabelNextScheduledRun": "Sljedeće zakazano izvođenje", "LabelNextScheduledRun": "Sljedeće zakazano izvođenje",
"LabelNoCustomMetadataProviders": "Nema prilagođenih pružatelja meta-podataka", "LabelNoCustomMetadataProviders": "Nema prilagođenih pružatelja meta-podataka",
@ -654,7 +655,7 @@
"MessageChapterErrorFirstNotZero": "Prvo poglavlje mora započeti u 0", "MessageChapterErrorFirstNotZero": "Prvo poglavlje mora započeti u 0",
"MessageChapterErrorStartGteDuration": "Netočno vrijeme početka, mora biti manje od trajanja zvučne knjige", "MessageChapterErrorStartGteDuration": "Netočno vrijeme početka, mora biti manje od trajanja zvučne knjige",
"MessageChapterErrorStartLtPrev": "Netočno vrijeme početka, mora biti veće ili jednako vremenu početka prethodnog poglavlja", "MessageChapterErrorStartLtPrev": "Netočno vrijeme početka, mora biti veće ili jednako vremenu početka prethodnog poglavlja",
"MessageChapterStartIsAfter": "Početak poglavlja je nakon kraja zvučne knjige.", "MessageChapterStartIsAfter": "Početak poglavlja je nakon kraja zvučne knjige",
"MessageCheckingCron": "Provjeravam cron...", "MessageCheckingCron": "Provjeravam cron...",
"MessageConfirmCloseFeed": "Sigurno želite zatvoriti ovaj izvor?", "MessageConfirmCloseFeed": "Sigurno želite zatvoriti ovaj izvor?",
"MessageConfirmDeleteBackup": "Jeste li sigurni da želite obrisati backup za {0}?", "MessageConfirmDeleteBackup": "Jeste li sigurni da želite obrisati backup za {0}?",
@ -776,6 +777,38 @@
"MessageShareExpiresIn": "Istječe za {0}", "MessageShareExpiresIn": "Istječe za {0}",
"MessageShareURLWillBe": "URL za dijeljenje bit će <strong>{0}</strong>", "MessageShareURLWillBe": "URL za dijeljenje bit će <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Pokreni reprodukciju za \"{0}\" na {1}?", "MessageStartPlaybackAtTime": "Pokreni reprodukciju za \"{0}\" na {1}?",
"MessageTaskAudioFileNotWritable": "U zvučnu datoteku \"{0}\" nije moguće pisati",
"MessageTaskCanceledByUser": "Korisnik je otkazao izvršavanje zadatka",
"MessageTaskDownloadingEpisodeDescription": "Preuzimanje nastavka \"{0}\"",
"MessageTaskEmbeddingMetadata": "Ugrađivanje meta-podataka",
"MessageTaskEmbeddingMetadataDescription": "Ugrađivanje meta-podataka u zvučnu knjigu \"{0}\"",
"MessageTaskEncodingM4b": "Kodiranje M4B datoteke",
"MessageTaskEncodingM4bDescription": "Kodiranje zvučne knjige \"{0}\" u jedinstvenu m4b datoteku",
"MessageTaskFailed": "Nije uspjelo",
"MessageTaskFailedToBackupAudioFile": "Izrada sigurnosne kopije zvučne datoteke \"{0}\" nije uspjela",
"MessageTaskFailedToCreateCacheDirectory": "Izrada mape predmemorije nije uspjela",
"MessageTaskFailedToEmbedMetadataInFile": "Ugradnja meta-podataka u datoteku \"{0}\" nije uspjela",
"MessageTaskFailedToMergeAudioFiles": "Spajanje zvučnih datoteka nije uspjelo",
"MessageTaskFailedToMoveM4bFile": "Premještanje m4b datoteke nije uspjelo",
"MessageTaskFailedToWriteMetadataFile": "Pisanje datoteke s meta-podatcima nije uspjelo",
"MessageTaskMatchingBooksInLibrary": "Prepoznavanje knjiga u knjižnici \"{0}\"",
"MessageTaskNoFilesToScan": "Nema datoteka za skeniranje",
"MessageTaskOpmlImport": "Uvoz OPML-a",
"MessageTaskOpmlImportDescription": "Stvaram podcaste od {0} RSS izvora",
"MessageTaskOpmlImportFeed": "Uvoz OPML izvora",
"MessageTaskOpmlImportFeedDescription": "Uvoz RSS izvora \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Izvor podcasta nije dohvaćen",
"MessageTaskOpmlImportFeedPodcastDescription": "Stvaranje podcasta \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast već postoji u putanji",
"MessageTaskOpmlImportFeedPodcastFailed": "Stvaranje podcasta nije uspjelo",
"MessageTaskOpmlImportFinished": "Dodano {0} podcasta",
"MessageTaskScanItemsAdded": "{0} dodan(o)",
"MessageTaskScanItemsMissing": "{0} nedostaje",
"MessageTaskScanItemsUpdated": "{0} ažurirano",
"MessageTaskScanNoChangesNeeded": "Nisu potrebne izmjene",
"MessageTaskScanningFileChanges": "Skeniranje izmijenjenih datoteka u \"{0}\"",
"MessageTaskScanningLibrary": "Skeniranje knjižnice \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "U odredišnu mapu nije moguće pisati",
"MessageThinking": "Razmišljam...", "MessageThinking": "Razmišljam...",
"MessageUploaderItemFailed": "Učitavanje nije uspjelo", "MessageUploaderItemFailed": "Učitavanje nije uspjelo",
"MessageUploaderItemSuccess": "Uspješno učitano!", "MessageUploaderItemSuccess": "Uspješno učitano!",
@ -816,14 +849,12 @@
"StatsTopNarrators": "NAJPOPULARNIJI PRIPOVJEDAČI", "StatsTopNarrators": "NAJPOPULARNIJI PRIPOVJEDAČI",
"StatsTotalDuration": "S ukupnim trajanjem od…", "StatsTotalDuration": "S ukupnim trajanjem od…",
"StatsYearInReview": "PREGLED GODINE", "StatsYearInReview": "PREGLED GODINE",
"ToastAccountUpdateFailed": "Ažuriranje računa nije uspjelo",
"ToastAccountUpdateSuccess": "Račun ažuriran", "ToastAccountUpdateSuccess": "Račun ažuriran",
"ToastAppriseUrlRequired": "Obavezno upisati Apprise URL", "ToastAppriseUrlRequired": "Obavezno upisati Apprise URL",
"ToastAuthorImageRemoveSuccess": "Slika autora uklonjena", "ToastAuthorImageRemoveSuccess": "Slika autora uklonjena",
"ToastAuthorNotFound": "Autor \"{0}\" nije pronađen", "ToastAuthorNotFound": "Autor \"{0}\" nije pronađen",
"ToastAuthorRemoveSuccess": "Autor uklonjen", "ToastAuthorRemoveSuccess": "Autor uklonjen",
"ToastAuthorSearchNotFound": "Autor nije pronađen", "ToastAuthorSearchNotFound": "Autor nije pronađen",
"ToastAuthorUpdateFailed": "Ažuriranje autora nije uspjelo",
"ToastAuthorUpdateMerged": "Autor pripojen", "ToastAuthorUpdateMerged": "Autor pripojen",
"ToastAuthorUpdateSuccess": "Autor ažuriran", "ToastAuthorUpdateSuccess": "Autor ažuriran",
"ToastAuthorUpdateSuccessNoImageFound": "Autor ažuriran (slika nije pronađena)", "ToastAuthorUpdateSuccessNoImageFound": "Autor ažuriran (slika nije pronađena)",
@ -834,7 +865,6 @@
"ToastBackupDeleteSuccess": "Sigurnosna kopija izbrisana", "ToastBackupDeleteSuccess": "Sigurnosna kopija izbrisana",
"ToastBackupInvalidMaxKeep": "Neispravan broj sigurnosnih kopija za čuvanje", "ToastBackupInvalidMaxKeep": "Neispravan broj sigurnosnih kopija za čuvanje",
"ToastBackupInvalidMaxSize": "Neispravna najveća veličina sigurnosne kopije", "ToastBackupInvalidMaxSize": "Neispravna najveća veličina sigurnosne kopije",
"ToastBackupPathUpdateFailed": "Ažuriranje putanje za sigurnosne kopije nije uspjelo",
"ToastBackupRestoreFailed": "Vraćanje sigurnosne kopije nije uspjelo", "ToastBackupRestoreFailed": "Vraćanje sigurnosne kopije nije uspjelo",
"ToastBackupUploadFailed": "Učitavanje sigurnosne kopije nije uspjelo", "ToastBackupUploadFailed": "Učitavanje sigurnosne kopije nije uspjelo",
"ToastBackupUploadSuccess": "Sigurnosna kopija učitana", "ToastBackupUploadSuccess": "Sigurnosna kopija učitana",
@ -845,7 +875,6 @@
"ToastBookmarkCreateFailed": "Izrada knjižne oznake nije uspjela", "ToastBookmarkCreateFailed": "Izrada knjižne oznake nije uspjela",
"ToastBookmarkCreateSuccess": "Knjižna oznaka dodana", "ToastBookmarkCreateSuccess": "Knjižna oznaka dodana",
"ToastBookmarkRemoveSuccess": "Knjižna oznaka uklonjena", "ToastBookmarkRemoveSuccess": "Knjižna oznaka uklonjena",
"ToastBookmarkUpdateFailed": "Ažuriranje knjižne oznake nije uspjelo",
"ToastBookmarkUpdateSuccess": "Knjižna oznaka ažurirana", "ToastBookmarkUpdateSuccess": "Knjižna oznaka ažurirana",
"ToastCachePurgeFailed": "Čišćenje predmemorije nije uspjelo", "ToastCachePurgeFailed": "Čišćenje predmemorije nije uspjelo",
"ToastCachePurgeSuccess": "Predmemorija uspješno očišćena", "ToastCachePurgeSuccess": "Predmemorija uspješno očišćena",
@ -856,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "Uspješno dodavanje stavki u zbirku", "ToastCollectionItemsAddSuccess": "Uspješno dodavanje stavki u zbirku",
"ToastCollectionItemsRemoveSuccess": "Stavke izbrisane iz zbirke", "ToastCollectionItemsRemoveSuccess": "Stavke izbrisane iz zbirke",
"ToastCollectionRemoveSuccess": "Zbirka izbrisana", "ToastCollectionRemoveSuccess": "Zbirka izbrisana",
"ToastCollectionUpdateFailed": "Ažuriranje zbirke nije uspjelo",
"ToastCollectionUpdateSuccess": "Zbirka ažurirana", "ToastCollectionUpdateSuccess": "Zbirka ažurirana",
"ToastCoverUpdateFailed": "Ažuriranje naslovnice nije uspjelo", "ToastCoverUpdateFailed": "Ažuriranje naslovnice nije uspjelo",
"ToastDeleteFileFailed": "Brisanje datoteke nije uspjelo", "ToastDeleteFileFailed": "Brisanje datoteke nije uspjelo",
@ -865,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "E-čitač s tim nazivom već postoji", "ToastDeviceNameAlreadyExists": "E-čitač s tim nazivom već postoji",
"ToastDeviceTestEmailFailed": "Slanje probne poruke e-pošte nije uspjelo", "ToastDeviceTestEmailFailed": "Slanje probne poruke e-pošte nije uspjelo",
"ToastDeviceTestEmailSuccess": "Probna poruka e-pošte poslana", "ToastDeviceTestEmailSuccess": "Probna poruka e-pošte poslana",
"ToastDeviceUpdateFailed": "Ažuriranje uređaja nije uspjelo",
"ToastEmailSettingsUpdateFailed": "Ažuriranje postavki e-pošte nije uspjelo",
"ToastEmailSettingsUpdateSuccess": "Postavke e-pošte ažurirane", "ToastEmailSettingsUpdateSuccess": "Postavke e-pošte ažurirane",
"ToastEncodeCancelFailed": "Kodiranje nije uspješno otkazano", "ToastEncodeCancelFailed": "Kodiranje nije uspješno otkazano",
"ToastEncodeCancelSucces": "Kodiranje otkazano", "ToastEncodeCancelSucces": "Kodiranje otkazano",
@ -875,21 +901,17 @@
"ToastErrorCannotShare": "Dijeljenje na ovaj uređaj nije moguće", "ToastErrorCannotShare": "Dijeljenje na ovaj uređaj nije moguće",
"ToastFailedToLoadData": "Učitavanje podataka nije uspjelo", "ToastFailedToLoadData": "Učitavanje podataka nije uspjelo",
"ToastFailedToShare": "Dijeljenje nije uspjelo", "ToastFailedToShare": "Dijeljenje nije uspjelo",
"ToastFailedToUpdateAccount": "Ažuriranje računa nije uspjelo", "ToastFailedToUpdate": "Ažuriranje nije uspjelo",
"ToastFailedToUpdateUser": "Ažuriranje korisnika nije uspjelo",
"ToastInvalidImageUrl": "Neispravan URL slike", "ToastInvalidImageUrl": "Neispravan URL slike",
"ToastInvalidUrl": "Neispravan URL", "ToastInvalidUrl": "Neispravan URL",
"ToastItemCoverUpdateFailed": "Ažuriranje naslovnice stavke nije uspjelo",
"ToastItemCoverUpdateSuccess": "Naslovnica stavke ažurirana", "ToastItemCoverUpdateSuccess": "Naslovnica stavke ažurirana",
"ToastItemDeletedFailed": "Brisanje stavke nije uspjelo", "ToastItemDeletedFailed": "Brisanje stavke nije uspjelo",
"ToastItemDeletedSuccess": "Stavka je izbrisana", "ToastItemDeletedSuccess": "Stavka je izbrisana",
"ToastItemDetailsUpdateFailed": "Ažuriranje podataka stavke nije uspjelo",
"ToastItemDetailsUpdateSuccess": "Pojedinosti stavke su ažurirane", "ToastItemDetailsUpdateSuccess": "Pojedinosti stavke su ažurirane",
"ToastItemMarkedAsFinishedFailed": "Označavanje kao Dovršeno nije uspjelo", "ToastItemMarkedAsFinishedFailed": "Označavanje kao Dovršeno nije uspjelo",
"ToastItemMarkedAsFinishedSuccess": "Stavka označena kao dovršena", "ToastItemMarkedAsFinishedSuccess": "Stavka označena kao dovršena",
"ToastItemMarkedAsNotFinishedFailed": "Označavanje kao Nije dovršeno nije uspjelo", "ToastItemMarkedAsNotFinishedFailed": "Označavanje kao Nije dovršeno nije uspjelo",
"ToastItemMarkedAsNotFinishedSuccess": "Stavka označena kao nedovršena", "ToastItemMarkedAsNotFinishedSuccess": "Stavka označena kao nedovršena",
"ToastItemUpdateFailed": "Ažuriranje stavke nije uspjelo",
"ToastItemUpdateSuccess": "Stavka ažurirana", "ToastItemUpdateSuccess": "Stavka ažurirana",
"ToastLibraryCreateFailed": "Stvaranje knjižnice nije uspjelo", "ToastLibraryCreateFailed": "Stvaranje knjižnice nije uspjelo",
"ToastLibraryCreateSuccess": "Knjižnica \"{0}\" stvorena", "ToastLibraryCreateSuccess": "Knjižnica \"{0}\" stvorena",
@ -897,7 +919,6 @@
"ToastLibraryDeleteSuccess": "Knjižnica izbrisana", "ToastLibraryDeleteSuccess": "Knjižnica izbrisana",
"ToastLibraryScanFailedToStart": "Skeniranje nije uspjelo", "ToastLibraryScanFailedToStart": "Skeniranje nije uspjelo",
"ToastLibraryScanStarted": "Skeniranje knjižnice započelo", "ToastLibraryScanStarted": "Skeniranje knjižnice započelo",
"ToastLibraryUpdateFailed": "Ažuriranje knjižnice nije uspjelo",
"ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" ažurirana", "ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" ažurirana",
"ToastNameEmailRequired": "Ime i adresa e-pošte su obavezni", "ToastNameEmailRequired": "Ime i adresa e-pošte su obavezni",
"ToastNameRequired": "Ime je obavezno", "ToastNameRequired": "Ime je obavezno",
@ -912,16 +933,13 @@
"ToastNotificationDeleteFailed": "Brisanje obavijesti nije uspjelo", "ToastNotificationDeleteFailed": "Brisanje obavijesti nije uspjelo",
"ToastNotificationFailedMaximum": "Najveći broj neuspješnih pokušaja mora biti >= 0", "ToastNotificationFailedMaximum": "Najveći broj neuspješnih pokušaja mora biti >= 0",
"ToastNotificationQueueMaximum": "Najveći broj obavijesti u redu mora biti >= 0", "ToastNotificationQueueMaximum": "Najveći broj obavijesti u redu mora biti >= 0",
"ToastNotificationSettingsUpdateFailed": "Ažuriranje postavki obavijesti nije uspjelo",
"ToastNotificationSettingsUpdateSuccess": "Postavke obavijesti ažurirane", "ToastNotificationSettingsUpdateSuccess": "Postavke obavijesti ažurirane",
"ToastNotificationTestTriggerFailed": "Okidanje probne obavijesti nije uspjelo", "ToastNotificationTestTriggerFailed": "Okidanje probne obavijesti nije uspjelo",
"ToastNotificationTestTriggerSuccess": "Okinuta je probna obavijest", "ToastNotificationTestTriggerSuccess": "Okinuta je probna obavijest",
"ToastNotificationUpdateFailed": "Ažuriranje obavijesti nije uspjelo",
"ToastNotificationUpdateSuccess": "Obavijest ažurirana", "ToastNotificationUpdateSuccess": "Obavijest ažurirana",
"ToastPlaylistCreateFailed": "Popis za izvođenje nije izrađen", "ToastPlaylistCreateFailed": "Popis za izvođenje nije izrađen",
"ToastPlaylistCreateSuccess": "Popis za izvođenje izrađen", "ToastPlaylistCreateSuccess": "Popis za izvođenje izrađen",
"ToastPlaylistRemoveSuccess": "Popis za izvođenje uklonjen", "ToastPlaylistRemoveSuccess": "Popis za izvođenje uklonjen",
"ToastPlaylistUpdateFailed": "Ažuriranje popisa za izvođenje nije uspjelo",
"ToastPlaylistUpdateSuccess": "Popis za izvođenje ažuriran", "ToastPlaylistUpdateSuccess": "Popis za izvođenje ažuriran",
"ToastPodcastCreateFailed": "Podcast nije izrađen", "ToastPodcastCreateFailed": "Podcast nije izrađen",
"ToastPodcastCreateSuccess": "Podcast uspješno izrađen", "ToastPodcastCreateSuccess": "Podcast uspješno izrađen",
@ -950,7 +968,6 @@
"ToastSendEbookToDeviceSuccess": "E-knjiga poslana uređaju \"{0}\"", "ToastSendEbookToDeviceSuccess": "E-knjiga poslana uređaju \"{0}\"",
"ToastSeriesUpdateFailed": "Ažuriranje serijala nije uspjelo", "ToastSeriesUpdateFailed": "Ažuriranje serijala nije uspjelo",
"ToastSeriesUpdateSuccess": "Serijal uspješno ažuriran", "ToastSeriesUpdateSuccess": "Serijal uspješno ažuriran",
"ToastServerSettingsUpdateFailed": "Ažuriranje postavki poslužitelja nije uspjelo",
"ToastServerSettingsUpdateSuccess": "Postavke poslužitelja ažurirane", "ToastServerSettingsUpdateSuccess": "Postavke poslužitelja ažurirane",
"ToastSessionCloseFailed": "Zatvaranje sesije nije uspjelo", "ToastSessionCloseFailed": "Zatvaranje sesije nije uspjelo",
"ToastSessionDeleteFailed": "Neuspješno brisanje serije", "ToastSessionDeleteFailed": "Neuspješno brisanje serije",
@ -961,7 +978,6 @@
"ToastSocketDisconnected": "Veza sa socketom je prekinuta", "ToastSocketDisconnected": "Veza sa socketom je prekinuta",
"ToastSocketFailedToConnect": "Priključivanje na socket nije uspjelo", "ToastSocketFailedToConnect": "Priključivanje na socket nije uspjelo",
"ToastSortingPrefixesEmptyError": "Mora imati najmanje jedan prefiks za sortiranje", "ToastSortingPrefixesEmptyError": "Mora imati najmanje jedan prefiks za sortiranje",
"ToastSortingPrefixesUpdateFailed": "Ažuriranje prefiksa za sortiranje nije uspjelo",
"ToastSortingPrefixesUpdateSuccess": "Prefiksi za sortiranje ažurirani ({0} stavki)", "ToastSortingPrefixesUpdateSuccess": "Prefiksi za sortiranje ažurirani ({0} stavki)",
"ToastTitleRequired": "Naslov je obavezan", "ToastTitleRequired": "Naslov je obavezan",
"ToastUnknownError": "Nepoznata pogreška", "ToastUnknownError": "Nepoznata pogreška",

View file

@ -9,6 +9,7 @@
"ButtonApply": "Alkalmaz", "ButtonApply": "Alkalmaz",
"ButtonApplyChapters": "Fejezetek alkalmazása", "ButtonApplyChapters": "Fejezetek alkalmazása",
"ButtonAuthors": "Szerzők", "ButtonAuthors": "Szerzők",
"ButtonBack": "Vissza",
"ButtonBrowseForFolder": "Mappa keresése", "ButtonBrowseForFolder": "Mappa keresése",
"ButtonCancel": "Mégse", "ButtonCancel": "Mégse",
"ButtonCancelEncode": "Kódolás megszakítása", "ButtonCancelEncode": "Kódolás megszakítása",
@ -18,7 +19,8 @@
"ButtonChooseFiles": "Fájlok kiválasztása", "ButtonChooseFiles": "Fájlok kiválasztása",
"ButtonClearFilter": "Szűrő törlése", "ButtonClearFilter": "Szűrő törlése",
"ButtonCloseFeed": "Hírcsatorna bezárása", "ButtonCloseFeed": "Hírcsatorna bezárása",
"ButtonCollections": "Gyűjtemény", "ButtonCloseSession": "Nyitott munkamenet bezárása",
"ButtonCollections": "Gyűjtemények",
"ButtonConfigureScanner": "Szkenner konfigurálása", "ButtonConfigureScanner": "Szkenner konfigurálása",
"ButtonCreate": "Létrehozás", "ButtonCreate": "Létrehozás",
"ButtonCreateBackup": "Biztonsági másolat készítése", "ButtonCreateBackup": "Biztonsági másolat készítése",
@ -27,6 +29,9 @@
"ButtonEdit": "Szerkesztés", "ButtonEdit": "Szerkesztés",
"ButtonEditChapters": "Fejezetek szerkesztése", "ButtonEditChapters": "Fejezetek szerkesztése",
"ButtonEditPodcast": "Podcast szerkesztése", "ButtonEditPodcast": "Podcast szerkesztése",
"ButtonEnable": "Engedélyezés",
"ButtonFireAndFail": "Küldés és összeomlás",
"ButtonFireOnTest": "onTest esemény küldése",
"ButtonForceReScan": "Újraszkennelés kényszerítése", "ButtonForceReScan": "Újraszkennelés kényszerítése",
"ButtonFullPath": "Teljes útvonal", "ButtonFullPath": "Teljes útvonal",
"ButtonHide": "Elrejtés", "ButtonHide": "Elrejtés",
@ -43,22 +48,31 @@
"ButtonMatchAllAuthors": "Minden szerző egyeztetése", "ButtonMatchAllAuthors": "Minden szerző egyeztetése",
"ButtonMatchBooks": "Könyvek egyeztetése", "ButtonMatchBooks": "Könyvek egyeztetése",
"ButtonNevermind": "Mindegy", "ButtonNevermind": "Mindegy",
"ButtonNext": "Következő",
"ButtonNextChapter": "Következő fejezet", "ButtonNextChapter": "Következő fejezet",
"ButtonNextItemInQueue": "Következő elem a sorban",
"ButtonOk": "Oké", "ButtonOk": "Oké",
"ButtonOpenFeed": "Hírcsatorna megnyitása", "ButtonOpenFeed": "Hírcsatorna megnyitása",
"ButtonOpenManager": "Kezelő megnyitása", "ButtonOpenManager": "Kezelő megnyitása",
"ButtonPause": "Szünet", "ButtonPause": "Szünet",
"ButtonPlay": "Lejátszás", "ButtonPlay": "Lejátszás",
"ButtonPlayAll": "Összes lejátszása",
"ButtonPlaying": "Lejátszás folyamatban", "ButtonPlaying": "Lejátszás folyamatban",
"ButtonPlaylists": "Lejátszási listák", "ButtonPlaylists": "Lejátszási listák",
"ButtonPrevious": "Előző",
"ButtonPreviousChapter": "Előző fejezet", "ButtonPreviousChapter": "Előző fejezet",
"ButtonProbeAudioFile": "Hangfájl vizsgálata",
"ButtonPurgeAllCache": "Összes gyorsítótár törlése", "ButtonPurgeAllCache": "Összes gyorsítótár törlése",
"ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése", "ButtonPurgeItemsCache": "Elemek gyorsítótárának törlése",
"ButtonQueueAddItem": "Hozzáadás a sorhoz", "ButtonQueueAddItem": "Hozzáadás a sorhoz",
"ButtonQueueRemoveItem": "Eltávolítás a sorból", "ButtonQueueRemoveItem": "Eltávolítás a sorból",
"ButtonQuickEmbedMetadata": "Metaadat gyors beágyazása",
"ButtonQuickMatch": "Gyors egyeztetés", "ButtonQuickMatch": "Gyors egyeztetés",
"ButtonReScan": "Újraszkennelés", "ButtonReScan": "Újraszkennelés",
"ButtonRead": "Olvasás", "ButtonRead": "Olvasás",
"ButtonReadLess": "Kevesebb mutatása",
"ButtonReadMore": "Mutass többet",
"ButtonRefresh": "Frissítés",
"ButtonRemove": "Eltávolítás", "ButtonRemove": "Eltávolítás",
"ButtonRemoveAll": "Összes eltávolítása", "ButtonRemoveAll": "Összes eltávolítása",
"ButtonRemoveAllLibraryItems": "Összes könyvtárelem eltávolítása", "ButtonRemoveAllLibraryItems": "Összes könyvtárelem eltávolítása",
@ -77,12 +91,15 @@
"ButtonSelectFolderPath": "Mappa útvonalának kiválasztása", "ButtonSelectFolderPath": "Mappa útvonalának kiválasztása",
"ButtonSeries": "Sorozatok", "ButtonSeries": "Sorozatok",
"ButtonSetChaptersFromTracks": "Fejezetek beállítása sávokból", "ButtonSetChaptersFromTracks": "Fejezetek beállítása sávokból",
"ButtonShare": "Megosztás",
"ButtonShiftTimes": "Idők eltolása", "ButtonShiftTimes": "Idők eltolása",
"ButtonShow": "Megjelenítés", "ButtonShow": "Megjelenítés",
"ButtonStartM4BEncode": "M4B kódolás indítása", "ButtonStartM4BEncode": "M4B kódolás indítása",
"ButtonStartMetadataEmbed": "Metaadatok beágyazásának indítása", "ButtonStartMetadataEmbed": "Metaadatok beágyazásának indítása",
"ButtonStats": "Statisztikák",
"ButtonSubmit": "Beküldés", "ButtonSubmit": "Beküldés",
"ButtonTest": "Teszt", "ButtonTest": "Teszt",
"ButtonUnlinkOpenId": "OpenID szétkapcsolása",
"ButtonUpload": "Feltöltés", "ButtonUpload": "Feltöltés",
"ButtonUploadBackup": "Biztonsági másolat feltöltése", "ButtonUploadBackup": "Biztonsági másolat feltöltése",
"ButtonUploadCover": "Borító feltöltése", "ButtonUploadCover": "Borító feltöltése",
@ -95,6 +112,7 @@
"ErrorUploadFetchMetadataNoResults": "Nem sikerült a metaadatok lekérése - próbálja meg frissíteni a címet és/vagy a szerzőt", "ErrorUploadFetchMetadataNoResults": "Nem sikerült a metaadatok lekérése - próbálja meg frissíteni a címet és/vagy a szerzőt",
"ErrorUploadLacksTitle": "Cím szükséges", "ErrorUploadLacksTitle": "Cím szükséges",
"HeaderAccount": "Fiók", "HeaderAccount": "Fiók",
"HeaderAddCustomMetadataProvider": "Egyedi metaadat szolgáltató hozzáadása",
"HeaderAdvanced": "Haladó", "HeaderAdvanced": "Haladó",
"HeaderAppriseNotificationSettings": "Apprise értesítési beállítások", "HeaderAppriseNotificationSettings": "Apprise értesítési beállítások",
"HeaderAudioTracks": "Audiósávok", "HeaderAudioTracks": "Audiósávok",
@ -108,6 +126,7 @@
"HeaderCollectionItems": "Gyűjtemény elemek", "HeaderCollectionItems": "Gyűjtemény elemek",
"HeaderCover": "Borító", "HeaderCover": "Borító",
"HeaderCurrentDownloads": "Jelenlegi letöltések", "HeaderCurrentDownloads": "Jelenlegi letöltések",
"HeaderCustomMessageOnLogin": "Egyedi üzenet bejelentkezéskor",
"HeaderCustomMetadataProviders": "Egyéni metaadat-szolgáltatók", "HeaderCustomMetadataProviders": "Egyéni metaadat-szolgáltatók",
"HeaderDetails": "Részletek", "HeaderDetails": "Részletek",
"HeaderDownloadQueue": "Letöltési sor", "HeaderDownloadQueue": "Letöltési sor",
@ -139,6 +158,8 @@
"HeaderMetadataToEmbed": "Beágyazandó metaadatok", "HeaderMetadataToEmbed": "Beágyazandó metaadatok",
"HeaderNewAccount": "Új fiók", "HeaderNewAccount": "Új fiók",
"HeaderNewLibrary": "Új könyvtár", "HeaderNewLibrary": "Új könyvtár",
"HeaderNotificationCreate": "Értesítés készítése",
"HeaderNotificationUpdate": "Értesítés frissítése",
"HeaderNotifications": "Értesítések", "HeaderNotifications": "Értesítések",
"HeaderOpenIDConnectAuthentication": "OpenID Connect hitelesítés", "HeaderOpenIDConnectAuthentication": "OpenID Connect hitelesítés",
"HeaderOpenRSSFeed": "RSS hírcsatorna megnyitása", "HeaderOpenRSSFeed": "RSS hírcsatorna megnyitása",
@ -146,12 +167,13 @@
"HeaderPasswordAuthentication": "Jelszó hitelesítés", "HeaderPasswordAuthentication": "Jelszó hitelesítés",
"HeaderPermissions": "Engedélyek", "HeaderPermissions": "Engedélyek",
"HeaderPlayerQueue": "Lejátszó sor", "HeaderPlayerQueue": "Lejátszó sor",
"HeaderPlayerSettings": "Lejátszó beállításai",
"HeaderPlaylist": "Lejátszási lista", "HeaderPlaylist": "Lejátszási lista",
"HeaderPlaylistItems": "Lejátszási lista elemek", "HeaderPlaylistItems": "Lejátszási lista elemek",
"HeaderPodcastsToAdd": "Hozzáadandó podcastok", "HeaderPodcastsToAdd": "Hozzáadandó podcastok",
"HeaderPreviewCover": "Borító előnézete", "HeaderPreviewCover": "Borító előnézete",
"HeaderRSSFeedGeneral": "RSS részletek", "HeaderRSSFeedGeneral": "RSS részletek",
"HeaderRSSFeedIsOpen": "RSS hírcsatorna nyitva", "HeaderRSSFeedIsOpen": "RSS hírcsatorna nyitva van",
"HeaderRSSFeeds": "RSS hírcsatornák", "HeaderRSSFeeds": "RSS hírcsatornák",
"HeaderRemoveEpisode": "Epizód eltávolítása", "HeaderRemoveEpisode": "Epizód eltávolítása",
"HeaderRemoveEpisodes": "{0} epizód eltávolítása", "HeaderRemoveEpisodes": "{0} epizód eltávolítása",
@ -168,7 +190,7 @@
"HeaderSleepTimer": "Alvásidőzítő", "HeaderSleepTimer": "Alvásidőzítő",
"HeaderStatsLargestItems": "Legnagyobb elemek", "HeaderStatsLargestItems": "Legnagyobb elemek",
"HeaderStatsLongestItems": "Leghosszabb elemek (órákban)", "HeaderStatsLongestItems": "Leghosszabb elemek (órákban)",
"HeaderStatsMinutesListeningChart": "Hallgatási percek (az utolsó 7 napban)", "HeaderStatsMinutesListeningChart": "Hallgatási grafikon percekben (az elmúlt 7 napból)",
"HeaderStatsRecentSessions": "Legutóbbi munkamenetek", "HeaderStatsRecentSessions": "Legutóbbi munkamenetek",
"HeaderStatsTop10Authors": "Top 10 szerzők", "HeaderStatsTop10Authors": "Top 10 szerzők",
"HeaderStatsTop5Genres": "Top 5 műfajok", "HeaderStatsTop5Genres": "Top 5 műfajok",
@ -179,9 +201,14 @@
"HeaderUpdateDetails": "Részletek frissítése", "HeaderUpdateDetails": "Részletek frissítése",
"HeaderUpdateLibrary": "Könyvtár frissítése", "HeaderUpdateLibrary": "Könyvtár frissítése",
"HeaderUsers": "Felhasználók", "HeaderUsers": "Felhasználók",
"HeaderYearReview": "{0} év áttekintése",
"HeaderYourStats": "Saját statisztikák", "HeaderYourStats": "Saját statisztikák",
"LabelAbridged": "Tömörített", "LabelAbridged": "Tömörített",
"LabelAbridgedChecked": "Rövidített (ellenőrizve)",
"LabelAbridgedUnchecked": "Teljes (nem ellenőrzött)",
"LabelAccessibleBy": "Hozzáférhető",
"LabelAccountType": "Fióktípus", "LabelAccountType": "Fióktípus",
"LabelAccountTypeAdmin": "Adminisztrátor",
"LabelAccountTypeGuest": "Vendég", "LabelAccountTypeGuest": "Vendég",
"LabelAccountTypeUser": "Felhasználó", "LabelAccountTypeUser": "Felhasználó",
"LabelActivity": "Tevékenység", "LabelActivity": "Tevékenység",
@ -190,8 +217,9 @@
"LabelAddToPlaylist": "Hozzáadás a lejátszási listához", "LabelAddToPlaylist": "Hozzáadás a lejátszási listához",
"LabelAddToPlaylistBatch": "{0} elem hozzáadása a lejátszási listához", "LabelAddToPlaylistBatch": "{0} elem hozzáadása a lejátszási listához",
"LabelAddedAt": "Hozzáadás ideje", "LabelAddedAt": "Hozzáadás ideje",
"LabelAddedDate": "{0} Hozzáadva",
"LabelAdminUsersOnly": "Csak admin felhasználók", "LabelAdminUsersOnly": "Csak admin felhasználók",
"LabelAll": "Minden", "LabelAll": "Összes",
"LabelAllUsers": "Minden felhasználó", "LabelAllUsers": "Minden felhasználó",
"LabelAllUsersExcludingGuests": "Minden felhasználó, vendégek kivételével", "LabelAllUsersExcludingGuests": "Minden felhasználó, vendégek kivételével",
"LabelAllUsersIncludingGuests": "Minden felhasználó, beleértve a vendégeket is", "LabelAllUsersIncludingGuests": "Minden felhasználó, beleértve a vendégeket is",
@ -212,13 +240,14 @@
"LabelBackupLocation": "Biztonsági másolat helye", "LabelBackupLocation": "Biztonsági másolat helye",
"LabelBackupsEnableAutomaticBackups": "Automatikus biztonsági másolatok engedélyezése", "LabelBackupsEnableAutomaticBackups": "Automatikus biztonsági másolatok engedélyezése",
"LabelBackupsEnableAutomaticBackupsHelp": "Biztonsági másolatok mentése a /metadata/backups mappába", "LabelBackupsEnableAutomaticBackupsHelp": "Biztonsági másolatok mentése a /metadata/backups mappába",
"LabelBackupsMaxBackupSize": "Maximális biztonsági másolat méret (GB-ban)", "LabelBackupsMaxBackupSize": "Maximális biztonsági másolat méret (GB-ban) (0-tól végtelenig)",
"LabelBackupsMaxBackupSizeHelp": "A rossz konfiguráció elleni védelem érdekében a biztonsági másolatok meghiúsulnak, ha meghaladják a beállított méretet.", "LabelBackupsMaxBackupSizeHelp": "A rossz konfiguráció elleni védelem érdekében a biztonsági másolatok meghiúsulnak, ha meghaladják a beállított méretet.",
"LabelBackupsNumberToKeep": "Megtartandó biztonsági másolatok száma", "LabelBackupsNumberToKeep": "Megtartandó biztonsági másolatok száma",
"LabelBackupsNumberToKeepHelp": "Egyszerre csak 1 biztonsági másolat kerül eltávolításra, tehát ha már több biztonsági másolat van, mint ez a szám, akkor manuálisan kell eltávolítani őket.", "LabelBackupsNumberToKeepHelp": "Egyszerre csak 1 biztonsági másolat kerül eltávolításra, tehát ha már több biztonsági másolat van, mint ez a szám, akkor manuálisan kell eltávolítani őket.",
"LabelBitrate": "Bitráta", "LabelBitrate": "Bitráta",
"LabelBooks": "Könyvek", "LabelBooks": "Könyvek",
"LabelButtonText": "Gomb szövege", "LabelButtonText": "Gomb szövege",
"LabelByAuthor": "{} által",
"LabelChangePassword": "Jelszó megváltoztatása", "LabelChangePassword": "Jelszó megváltoztatása",
"LabelChannels": "Csatornák", "LabelChannels": "Csatornák",
"LabelChapterTitle": "Fejezet címe", "LabelChapterTitle": "Fejezet címe",
@ -228,9 +257,10 @@
"LabelClosePlayer": "Lejátszó bezárása", "LabelClosePlayer": "Lejátszó bezárása",
"LabelCodec": "Kodek", "LabelCodec": "Kodek",
"LabelCollapseSeries": "Sorozat összecsukása", "LabelCollapseSeries": "Sorozat összecsukása",
"LabelCollapseSubSeries": "Alszéria összecsukása",
"LabelCollection": "Gyűjtemény", "LabelCollection": "Gyűjtemény",
"LabelCollections": "Gyűjtemények", "LabelCollections": "Gyűjtemények",
"LabelComplete": "Teljes", "LabelComplete": "Kész",
"LabelConfirmPassword": "Jelszó megerősítése", "LabelConfirmPassword": "Jelszó megerősítése",
"LabelContinueListening": "Hallgatás folytatása", "LabelContinueListening": "Hallgatás folytatása",
"LabelContinueReading": "Olvasás folytatása", "LabelContinueReading": "Olvasás folytatása",
@ -243,6 +273,7 @@
"LabelCurrently": "Jelenleg:", "LabelCurrently": "Jelenleg:",
"LabelCustomCronExpression": "Egyéni Cron kifejezés:", "LabelCustomCronExpression": "Egyéni Cron kifejezés:",
"LabelDatetime": "Dátumidő", "LabelDatetime": "Dátumidő",
"LabelDays": "Napok",
"LabelDeleteFromFileSystemCheckbox": "Törlés a fájlrendszerről (ne jelölje be, ha csak az adatbázisból szeretné eltávolítani)", "LabelDeleteFromFileSystemCheckbox": "Törlés a fájlrendszerről (ne jelölje be, ha csak az adatbázisból szeretné eltávolítani)",
"LabelDescription": "Leírás", "LabelDescription": "Leírás",
"LabelDeselectAll": "Minden kijelölés megszüntetése", "LabelDeselectAll": "Minden kijelölés megszüntetése",
@ -256,27 +287,42 @@
"LabelDownload": "Letöltés", "LabelDownload": "Letöltés",
"LabelDownloadNEpisodes": "{0} epizód letöltése", "LabelDownloadNEpisodes": "{0} epizód letöltése",
"LabelDuration": "Időtartam", "LabelDuration": "Időtartam",
"LabelDurationComparisonExactMatch": "(pontos egyezés)",
"LabelDurationComparisonLonger": "({0}-val hosszabb)",
"LabelDurationComparisonShorter": "({0}-val rövidebb)",
"LabelDurationFound": "Megtalált időtartam:", "LabelDurationFound": "Megtalált időtartam:",
"LabelEbook": "E-könyv", "LabelEbook": "E-könyv",
"LabelEbooks": "E-könyvek", "LabelEbooks": "E-könyvek",
"LabelEdit": "Szerkesztés", "LabelEdit": "Szerkesztés",
"LabelEmail": "E-mail", "LabelEmail": "E-mail",
"LabelEmailSettingsFromAddress": "Feladó címe", "LabelEmailSettingsFromAddress": "Feladó címe",
"LabelEmailSettingsRejectUnauthorized": "Nem hitelesített tanúsítványok elutasítása",
"LabelEmailSettingsRejectUnauthorizedHelp": "Az SSL tanúsítványok érvényesítésének letiltása biztonsági kockázatoknak, például man-in-the-middle támadásoknak teheti ki a kapcsolatot. Csak akkor tiltsd le ezt az opciót, ha tisztában vagy a következményekkel, és megbízol az e-mail szerverben, amelyhez csatlakozol.",
"LabelEmailSettingsSecure": "Biztonságos", "LabelEmailSettingsSecure": "Biztonságos",
"LabelEmailSettingsSecureHelp": "Ha igaz, a kapcsolat TLS-t használ a szerverhez való csatlakozáskor. Ha hamis, akkor TLS-t használ, ha a szerver támogatja a STARTTLS kiterjesztést. A legtöbb esetben állítsa ezt az értéket igazra, ha a 465-ös portra csatlakozik. A 587-es vagy 25-ös port esetében tartsa hamis értéken. (a nodemailer.com/smtp/#authentication oldalról)", "LabelEmailSettingsSecureHelp": "Ha igaz, a kapcsolat TLS-t használ a szerverhez való csatlakozáskor. Ha hamis, akkor TLS-t használ, ha a szerver támogatja a STARTTLS kiterjesztést. A legtöbb esetben állítsa ezt az értéket igazra, ha a 465-ös portra csatlakozik. A 587-es vagy 25-ös port esetében tartsa hamis értéken. (a nodemailer.com/smtp/#authentication oldalról)",
"LabelEmailSettingsTestAddress": "Teszt cím", "LabelEmailSettingsTestAddress": "Teszt cím",
"LabelEmbeddedCover": "Beágyazott borító", "LabelEmbeddedCover": "Beágyazott borító",
"LabelEnable": "Engedélyezés", "LabelEnable": "Engedélyezés",
"LabelEnd": "Vége", "LabelEnd": "Vége",
"LabelEndOfChapter": "Fejezet vége",
"LabelEpisode": "Epizód", "LabelEpisode": "Epizód",
"LabelEpisodeTitle": "Epizód címe", "LabelEpisodeTitle": "Epizód címe",
"LabelEpisodeType": "Epizód típusa", "LabelEpisodeType": "Epizód típusa",
"LabelEpisodes": "Epizódok",
"LabelExample": "Példa", "LabelExample": "Példa",
"LabelExpandSeries": "Sorozat kinyitása",
"LabelExpandSubSeries": "Alsorozat kinyitása",
"LabelExplicit": "Explicit",
"LabelExplicitChecked": "Explicit (ellenőrizve)",
"LabelExplicitUnchecked": "Nem explicit (nem ellenőrzött)",
"LabelExportOPML": "OPML exportálása",
"LabelFeedURL": "Hírcsatorna URL", "LabelFeedURL": "Hírcsatorna URL",
"LabelFetchingMetadata": "Metaadatok lekérése", "LabelFetchingMetadata": "Metaadatok lekérése",
"LabelFile": "Fájl", "LabelFile": "Fájl",
"LabelFileBirthtime": "Fájl létrehozásának ideje", "LabelFileBirthtime": "Fájl létrehozásának ideje",
"LabelFileBornDate": "Született {0}",
"LabelFileModified": "Fájl módosításának ideje", "LabelFileModified": "Fájl módosításának ideje",
"LabelFileModifiedDate": "Módosítva {0}",
"LabelFilename": "Fájlnév", "LabelFilename": "Fájlnév",
"LabelFilterByUser": "Szűrés felhasználó szerint", "LabelFilterByUser": "Szűrés felhasználó szerint",
"LabelFindEpisodes": "Epizódok keresése", "LabelFindEpisodes": "Epizódok keresése",
@ -284,6 +330,7 @@
"LabelFolder": "Mappa", "LabelFolder": "Mappa",
"LabelFolders": "Mappák", "LabelFolders": "Mappák",
"LabelFontBold": "Félkövér", "LabelFontBold": "Félkövér",
"LabelFontBoldness": "Betű vastagság",
"LabelFontFamily": "Betűtípus család", "LabelFontFamily": "Betűtípus család",
"LabelFontItalic": "Dőlt", "LabelFontItalic": "Dőlt",
"LabelFontScale": "Betűméret skála", "LabelFontScale": "Betűméret skála",
@ -294,9 +341,11 @@
"LabelHardDeleteFile": "Fájl végleges törlése", "LabelHardDeleteFile": "Fájl végleges törlése",
"LabelHasEbook": "Van e-könyve", "LabelHasEbook": "Van e-könyve",
"LabelHasSupplementaryEbook": "Van kiegészítő e-könyve", "LabelHasSupplementaryEbook": "Van kiegészítő e-könyve",
"LabelHideSubtitles": "Alcím elrejtése",
"LabelHighestPriority": "Legmagasabb prioritás", "LabelHighestPriority": "Legmagasabb prioritás",
"LabelHost": "Hoszt", "LabelHost": "Házigazda",
"LabelHour": "Óra", "LabelHour": "Óra",
"LabelHours": "Órák",
"LabelIcon": "Ikon", "LabelIcon": "Ikon",
"LabelImageURLFromTheWeb": "Kép URL a weben", "LabelImageURLFromTheWeb": "Kép URL a weben",
"LabelInProgress": "Folyamatban", "LabelInProgress": "Folyamatban",
@ -313,8 +362,11 @@
"LabelIntervalEveryHour": "Minden órában", "LabelIntervalEveryHour": "Minden órában",
"LabelInvert": "Megfordítás", "LabelInvert": "Megfordítás",
"LabelItem": "Elem", "LabelItem": "Elem",
"LabelJumpBackwardAmount": "Visszafelé ugrás mennyisége",
"LabelJumpForwardAmount": "Előre ugrás mennyisége",
"LabelLanguage": "Nyelv", "LabelLanguage": "Nyelv",
"LabelLanguageDefaultServer": "Szerver alapértelmezett nyelve", "LabelLanguageDefaultServer": "Szerver alapértelmezett nyelve",
"LabelLanguages": "Nyelvek",
"LabelLastBookAdded": "Utolsó hozzáadott könyv", "LabelLastBookAdded": "Utolsó hozzáadott könyv",
"LabelLastBookUpdated": "Utolsó frissített könyv", "LabelLastBookUpdated": "Utolsó frissített könyv",
"LabelLastSeen": "Utolsó látogatás", "LabelLastSeen": "Utolsó látogatás",
@ -326,11 +378,13 @@
"LabelLess": "Kevesebb", "LabelLess": "Kevesebb",
"LabelLibrariesAccessibleToUser": "A felhasználó számára elérhető könyvtárak", "LabelLibrariesAccessibleToUser": "A felhasználó számára elérhető könyvtárak",
"LabelLibrary": "Könyvtár", "LabelLibrary": "Könyvtár",
"LabelLibraryFilterSublistEmpty": "Nem {0}",
"LabelLibraryItem": "Könyvtári elem", "LabelLibraryItem": "Könyvtári elem",
"LabelLibraryName": "Könyvtár neve", "LabelLibraryName": "Könyvtár neve",
"LabelLimit": "Korlát", "LabelLimit": "Korlát",
"LabelLineSpacing": "Sorköz", "LabelLineSpacing": "Sorköz",
"LabelListenAgain": "Újrahallgatás", "LabelListenAgain": "Újrahallgatás",
"LabelLogLevelDebug": "Hibakeresés",
"LabelLogLevelInfo": "Információ", "LabelLogLevelInfo": "Információ",
"LabelLogLevelWarn": "Figyelmeztetés", "LabelLogLevelWarn": "Figyelmeztetés",
"LabelLookForNewEpisodesAfterDate": "Új epizódok keresése ezen a dátum után", "LabelLookForNewEpisodesAfterDate": "Új epizódok keresése ezen a dátum után",
@ -344,7 +398,10 @@
"LabelMetadataOrderOfPrecedenceDescription": "A magasabb prioritású metaadat-források felülírják az alacsonyabb prioritásúakat", "LabelMetadataOrderOfPrecedenceDescription": "A magasabb prioritású metaadat-források felülírják az alacsonyabb prioritásúakat",
"LabelMetadataProvider": "Metaadat-szolgáltató", "LabelMetadataProvider": "Metaadat-szolgáltató",
"LabelMinute": "Perc", "LabelMinute": "Perc",
"LabelMinutes": "Percek",
"LabelMissing": "Hiányzó", "LabelMissing": "Hiányzó",
"LabelMissingEbook": "Nincs e-könyve",
"LabelMissingSupplementaryEbook": "Nincs kiegészítő e-könyve",
"LabelMobileRedirectURIs": "Engedélyezett mobil átirányítási URI-k", "LabelMobileRedirectURIs": "Engedélyezett mobil átirányítási URI-k",
"LabelMobileRedirectURIsDescription": "Ez egy fehérlista az érvényes mobilalkalmazás-átirányítási URI-k számára. Az alapértelmezett <code>audiobookshelf://oauth</code>, amely eltávolítható vagy kiegészíthető további URI-kkal harmadik féltől származó alkalmazásintegráció érdekében. Ha az egyetlen bejegyzés egy csillag (<code>*</code>), akkor bármely URI engedélyezett.", "LabelMobileRedirectURIsDescription": "Ez egy fehérlista az érvényes mobilalkalmazás-átirányítási URI-k számára. Az alapértelmezett <code>audiobookshelf://oauth</code>, amely eltávolítható vagy kiegészíthető további URI-kkal harmadik féltől származó alkalmazásintegráció érdekében. Ha az egyetlen bejegyzés egy csillag (<code>*</code>), akkor bármely URI engedélyezett.",
"LabelMore": "Több", "LabelMore": "Több",
@ -358,6 +415,7 @@
"LabelNewestEpisodes": "Legújabb epizódok", "LabelNewestEpisodes": "Legújabb epizódok",
"LabelNextBackupDate": "Következő biztonsági másolat dátuma", "LabelNextBackupDate": "Következő biztonsági másolat dátuma",
"LabelNextScheduledRun": "Következő ütemezett futtatás", "LabelNextScheduledRun": "Következő ütemezett futtatás",
"LabelNoCustomMetadataProviders": "Nincsenek egyedi metaadat szolgáltatók",
"LabelNoEpisodesSelected": "Nincsenek kiválasztott epizódok", "LabelNoEpisodesSelected": "Nincsenek kiválasztott epizódok",
"LabelNotFinished": "Nem befejezett", "LabelNotFinished": "Nem befejezett",
"LabelNotStarted": "Nem indult el", "LabelNotStarted": "Nem indult el",
@ -373,10 +431,14 @@
"LabelNotificationsMaxQueueSizeHelp": "Az események korlátozva vannak, hogy másodpercenként 1-szer történjenek. Ha a sor maximális méretű, akkor az események figyelmen kívül lesznek hagyva. Ez megakadályozza az értesítések spamelését.", "LabelNotificationsMaxQueueSizeHelp": "Az események korlátozva vannak, hogy másodpercenként 1-szer történjenek. Ha a sor maximális méretű, akkor az események figyelmen kívül lesznek hagyva. Ez megakadályozza az értesítések spamelését.",
"LabelNumberOfBooks": "Könyvek száma", "LabelNumberOfBooks": "Könyvek száma",
"LabelNumberOfEpisodes": "Epizódok száma", "LabelNumberOfEpisodes": "Epizódok száma",
"LabelOpenIDAdvancedPermsClaimDescription": "Az OpenID-igény neve, amely a felhasználói műveletekre vonatkozó haladó jogosultságokat tartalmazza az alkalmazáson belül, és amely a nem adminisztrátori szerepkörökre vonatkozik (<b>ha konfigurálva van</b>). Ha az igény hiányzik a válaszból, az ABS-hez való hozzáférés megtagadásra kerül. Ha egyetlen opció hiányzik, azt <code>false</code>-ként fogja kezelni. Győződj meg arról, hogy az identitásszolgáltató igénye megfelel a várt struktúrának:",
"LabelOpenIDClaims": "Hagyd üresen a következő opciókat, hogy letiltsd a haladó csoport- és jogosultság-hozzárendelést, ekkor automatikusan a Felhasználó csoport kerül hozzárendelésre.",
"LabelOpenIDGroupClaimDescription": "Az OpenID-igény neve, amely a felhasználó csoportjainak listáját tartalmazza. Általában groups néven hivatkoznak rá. Ha konfigurálva van, az alkalmazás automatikusan hozzárendeli a szerepköröket a felhasználó csoporttagságai alapján, feltéve, hogy ezek a csoportok az igényben kis- és nagybetűkre érzéketlenül admin, user vagy guest néven szerepelnek. Az igénynek egy listát kell tartalmaznia, és ha egy felhasználó több csoport tagja, az alkalmazás a legmagasabb szintű hozzáféréssel rendelkező szerepkört rendeli hozzá. Ha egyetlen csoport sem felel meg, a hozzáférés megtagadásra kerül.",
"LabelOpenRSSFeed": "RSS hírcsatorna megnyitása", "LabelOpenRSSFeed": "RSS hírcsatorna megnyitása",
"LabelOverwrite": "Felülírás", "LabelOverwrite": "Felülírás",
"LabelPassword": "Jelszó", "LabelPassword": "Jelszó",
"LabelPath": "Útvonal", "LabelPath": "Útvonal",
"LabelPermanent": "Végleges",
"LabelPermissionsAccessAllLibraries": "Hozzáférhet az összes könyvtárhoz", "LabelPermissionsAccessAllLibraries": "Hozzáférhet az összes könyvtárhoz",
"LabelPermissionsAccessAllTags": "Hozzáférhet az összes címkéhez", "LabelPermissionsAccessAllTags": "Hozzáférhet az összes címkéhez",
"LabelPermissionsAccessExplicitContent": "Hozzáférhet explicit tartalomhoz", "LabelPermissionsAccessExplicitContent": "Hozzáférhet explicit tartalomhoz",
@ -384,26 +446,34 @@
"LabelPermissionsDownload": "Letölthet", "LabelPermissionsDownload": "Letölthet",
"LabelPermissionsUpdate": "Frissíthet", "LabelPermissionsUpdate": "Frissíthet",
"LabelPermissionsUpload": "Feltölthet", "LabelPermissionsUpload": "Feltölthet",
"LabelPersonalYearReview": "Az éved áttekintése ({0})",
"LabelPhotoPathURL": "Fénykép útvonal/URL", "LabelPhotoPathURL": "Fénykép útvonal/URL",
"LabelPlayMethod": "Lejátszási módszer", "LabelPlayMethod": "Lejátszási módszer",
"LabelPlayerChapterNumberMarker": "{0} a {1} -ből",
"LabelPlaylists": "Lejátszási listák", "LabelPlaylists": "Lejátszási listák",
"LabelPodcast": "Podcast",
"LabelPodcastSearchRegion": "Podcast keresési régió", "LabelPodcastSearchRegion": "Podcast keresési régió",
"LabelPodcastType": "Podcast típus", "LabelPodcastType": "Podcast típus",
"LabelPodcasts": "Podcastok", "LabelPodcasts": "Podcastok",
"LabelPort": "Port",
"LabelPrefixesToIgnore": "Figyelmen kívül hagyandó előtagok (nem érzékeny a kis- és nagybetűkre)", "LabelPrefixesToIgnore": "Figyelmen kívül hagyandó előtagok (nem érzékeny a kis- és nagybetűkre)",
"LabelPreventIndexing": "A hírcsatorna indexelésének megakadályozása az iTunes és a Google podcast könyvtáraiban", "LabelPreventIndexing": "Megakadályozza a hírcsatornájának indexelését az iTunes és a Google podcast könyvtárakban",
"LabelPrimaryEbook": "Elsődleges e-könyv", "LabelPrimaryEbook": "Elsődleges e-könyv",
"LabelProgress": "Haladás", "LabelProgress": "Haladás",
"LabelProvider": "Szolgáltató", "LabelProvider": "Szolgáltató",
"LabelProviderAuthorizationValue": "Authorization fejléc értéke",
"LabelPubDate": "Kiadás dátuma", "LabelPubDate": "Kiadás dátuma",
"LabelPublishYear": "Kiadás éve", "LabelPublishYear": "Kiadás éve",
"LabelPublishedDate": "Kiadva {0}",
"LabelPublisher": "Kiadó", "LabelPublisher": "Kiadó",
"LabelPublishers": "Kiadók",
"LabelRSSFeedCustomOwnerEmail": "Egyéni tulajdonos e-mail", "LabelRSSFeedCustomOwnerEmail": "Egyéni tulajdonos e-mail",
"LabelRSSFeedCustomOwnerName": "Egyéni tulajdonos neve", "LabelRSSFeedCustomOwnerName": "Egyéni tulajdonos neve",
"LabelRSSFeedOpen": "RSS hírcsatorna nyitva", "LabelRSSFeedOpen": "RSS hírcsatorna nyitva",
"LabelRSSFeedPreventIndexing": "Indexelés megakadályozása", "LabelRSSFeedPreventIndexing": "Indexelés megakadályozása",
"LabelRSSFeedSlug": "RSS hírcsatorna slug", "LabelRSSFeedSlug": "RSS hírcsatorna slug",
"LabelRSSFeedURL": "RSS hírcsatorna URL", "LabelRSSFeedURL": "RSS hírcsatorna URL",
"LabelRandomly": "Véletlenszerűen",
"LabelRead": "Olvasás", "LabelRead": "Olvasás",
"LabelReadAgain": "Újraolvasás", "LabelReadAgain": "Újraolvasás",
"LabelReadEbookWithoutProgress": "E-könyv olvasása haladás nélkül", "LabelReadEbookWithoutProgress": "E-könyv olvasása haladás nélkül",
@ -592,9 +662,9 @@
"MessageDownloadingEpisode": "Epizód letöltése", "MessageDownloadingEpisode": "Epizód letöltése",
"MessageDragFilesIntoTrackOrder": "Húzza a fájlokat a helyes sávrendbe", "MessageDragFilesIntoTrackOrder": "Húzza a fájlokat a helyes sávrendbe",
"MessageEmbedFinished": "Beágyazás befejeződött!", "MessageEmbedFinished": "Beágyazás befejeződött!",
"MessageEpisodesQueuedForDownload": "{0} Epizód letöltésre várakozik", "MessageEpisodesQueuedForDownload": "{0} epizód letöltésre vár",
"MessageFeedURLWillBe": "A hírcsatorna URL-je {0} lesz", "MessageFeedURLWillBe": "A hírcsatorna URL-je {0} lesz",
"MessageFetching": "Lekérés...", "MessageFetching": "Lekérdezés...",
"MessageForceReScanDescription": "minden fájlt újra szkennel, mint egy friss szkennelés. Az audiofájlok ID3 címkéi, OPF fájlok és szövegfájlok újként lesznek szkennelve.", "MessageForceReScanDescription": "minden fájlt újra szkennel, mint egy friss szkennelés. Az audiofájlok ID3 címkéi, OPF fájlok és szövegfájlok újként lesznek szkennelve.",
"MessageImportantNotice": "Fontos közlemény!", "MessageImportantNotice": "Fontos közlemény!",
"MessageInsertChapterBelow": "Fejezet beszúrása alulra", "MessageInsertChapterBelow": "Fejezet beszúrása alulra",
@ -628,7 +698,7 @@
"MessageNoGenres": "Nincsenek műfajok", "MessageNoGenres": "Nincsenek műfajok",
"MessageNoIssues": "Nincsenek problémák", "MessageNoIssues": "Nincsenek problémák",
"MessageNoItems": "Nincsenek elemek", "MessageNoItems": "Nincsenek elemek",
"MessageNoItemsFound": "Nem találhatóak elemek", "MessageNoItemsFound": "Nincs találat",
"MessageNoListeningSessions": "Nincsenek hallgatási munkamenetek", "MessageNoListeningSessions": "Nincsenek hallgatási munkamenetek",
"MessageNoLogs": "Nincsenek naplók", "MessageNoLogs": "Nincsenek naplók",
"MessageNoMediaProgress": "Nincs előrehaladás a médialejátszásban", "MessageNoMediaProgress": "Nincs előrehaladás a médialejátszásban",
@ -683,10 +753,8 @@
"PlaceholderNewPlaylist": "Új lejátszási lista neve", "PlaceholderNewPlaylist": "Új lejátszási lista neve",
"PlaceholderSearch": "Keresés..", "PlaceholderSearch": "Keresés..",
"PlaceholderSearchEpisode": "Epizód keresése..", "PlaceholderSearchEpisode": "Epizód keresése..",
"ToastAccountUpdateFailed": "A fiók frissítése sikertelen",
"ToastAccountUpdateSuccess": "Fiók frissítve", "ToastAccountUpdateSuccess": "Fiók frissítve",
"ToastAuthorImageRemoveSuccess": "Szerző képe eltávolítva", "ToastAuthorImageRemoveSuccess": "Szerző képe eltávolítva",
"ToastAuthorUpdateFailed": "A szerző frissítése sikertelen",
"ToastAuthorUpdateMerged": "Szerző összevonva", "ToastAuthorUpdateMerged": "Szerző összevonva",
"ToastAuthorUpdateSuccess": "Szerző frissítve", "ToastAuthorUpdateSuccess": "Szerző frissítve",
"ToastAuthorUpdateSuccessNoImageFound": "Szerző frissítve (nem található kép)", "ToastAuthorUpdateSuccessNoImageFound": "Szerző frissítve (nem található kép)",
@ -702,21 +770,17 @@
"ToastBookmarkCreateFailed": "Könyvjelző létrehozása sikertelen", "ToastBookmarkCreateFailed": "Könyvjelző létrehozása sikertelen",
"ToastBookmarkCreateSuccess": "Könyvjelző hozzáadva", "ToastBookmarkCreateSuccess": "Könyvjelző hozzáadva",
"ToastBookmarkRemoveSuccess": "Könyvjelző eltávolítva", "ToastBookmarkRemoveSuccess": "Könyvjelző eltávolítva",
"ToastBookmarkUpdateFailed": "Könyvjelző frissítése sikertelen",
"ToastBookmarkUpdateSuccess": "Könyvjelző frissítve", "ToastBookmarkUpdateSuccess": "Könyvjelző frissítve",
"ToastChaptersHaveErrors": "A fejezetek hibákat tartalmaznak", "ToastChaptersHaveErrors": "A fejezetek hibákat tartalmaznak",
"ToastChaptersMustHaveTitles": "A fejezeteknek címekkel kell rendelkezniük", "ToastChaptersMustHaveTitles": "A fejezeteknek címekkel kell rendelkezniük",
"ToastCollectionItemsRemoveSuccess": "Elem(ek) eltávolítva a gyűjteményből", "ToastCollectionItemsRemoveSuccess": "Elem(ek) eltávolítva a gyűjteményből",
"ToastCollectionRemoveSuccess": "Gyűjtemény eltávolítva", "ToastCollectionRemoveSuccess": "Gyűjtemény eltávolítva",
"ToastCollectionUpdateFailed": "Gyűjtemény frissítése sikertelen",
"ToastCollectionUpdateSuccess": "Gyűjtemény frissítve", "ToastCollectionUpdateSuccess": "Gyűjtemény frissítve",
"ToastItemCoverUpdateFailed": "Elem borítójának frissítése sikertelen",
"ToastItemCoverUpdateSuccess": "Elem borítója frissítve", "ToastItemCoverUpdateSuccess": "Elem borítója frissítve",
"ToastItemDetailsUpdateFailed": "Elem részleteinek frissítése sikertelen",
"ToastItemDetailsUpdateSuccess": "Elem részletei frissítve", "ToastItemDetailsUpdateSuccess": "Elem részletei frissítve",
"ToastItemMarkedAsFinishedFailed": "Megjelölés Befejezettként sikertelen", "ToastItemMarkedAsFinishedFailed": "Megjelölés Befejezettként sikertelen",
"ToastItemMarkedAsFinishedSuccess": "Elem megjelölve Befejezettként", "ToastItemMarkedAsFinishedSuccess": "Elem megjelölve Befejezettként",
"ToastItemMarkedAsNotFinishedFailed": "Nem sikerült Nem Befejezettként megjelölni az elemet", "ToastItemMarkedAsNotFinishedFailed": "Az elem befejezetlennek jelölése sikertelen",
"ToastItemMarkedAsNotFinishedSuccess": "Elem megjelölve Nem Befejezettként", "ToastItemMarkedAsNotFinishedSuccess": "Elem megjelölve Nem Befejezettként",
"ToastLibraryCreateFailed": "Könyvtár létrehozása sikertelen", "ToastLibraryCreateFailed": "Könyvtár létrehozása sikertelen",
"ToastLibraryCreateSuccess": "\"{0}\" könyvtár létrehozva", "ToastLibraryCreateSuccess": "\"{0}\" könyvtár létrehozva",
@ -724,16 +788,14 @@
"ToastLibraryDeleteSuccess": "Könyvtár törölve", "ToastLibraryDeleteSuccess": "Könyvtár törölve",
"ToastLibraryScanFailedToStart": "A beolvasás elindítása sikertelen", "ToastLibraryScanFailedToStart": "A beolvasás elindítása sikertelen",
"ToastLibraryScanStarted": "Könyvtár beolvasása elindítva", "ToastLibraryScanStarted": "Könyvtár beolvasása elindítva",
"ToastLibraryUpdateFailed": "Könyvtár frissítése sikertelen",
"ToastLibraryUpdateSuccess": "\"{0}\" könyvtár frissítve", "ToastLibraryUpdateSuccess": "\"{0}\" könyvtár frissítve",
"ToastPlaylistCreateFailed": "Lejátszási lista létrehozása sikertelen", "ToastPlaylistCreateFailed": "Lejátszási lista létrehozása sikertelen",
"ToastPlaylistCreateSuccess": "Lejátszási lista létrehozva", "ToastPlaylistCreateSuccess": "Lejátszási lista létrehozva",
"ToastPlaylistRemoveSuccess": "Lejátszási lista eltávolítva", "ToastPlaylistRemoveSuccess": "Lejátszási lista eltávolítva",
"ToastPlaylistUpdateFailed": "Lejátszási lista frissítése sikertelen",
"ToastPlaylistUpdateSuccess": "Lejátszási lista frissítve", "ToastPlaylistUpdateSuccess": "Lejátszási lista frissítve",
"ToastPodcastCreateFailed": "Podcast létrehozása sikertelen", "ToastPodcastCreateFailed": "Podcast létrehozása sikertelen",
"ToastPodcastCreateSuccess": "Podcast sikeresen létrehozva", "ToastPodcastCreateSuccess": "A podcast sikeresen létrehozva",
"ToastRSSFeedCloseFailed": "RSS feed bezárása sikertelen", "ToastRSSFeedCloseFailed": "Az RSS hírcsatorna bezárása sikertelen",
"ToastRSSFeedCloseSuccess": "RSS feed bezárva", "ToastRSSFeedCloseSuccess": "RSS feed bezárva",
"ToastRemoveItemFromCollectionFailed": "Tétel eltávolítása a gyűjteményből sikertelen", "ToastRemoveItemFromCollectionFailed": "Tétel eltávolítása a gyűjteményből sikertelen",
"ToastRemoveItemFromCollectionSuccess": "Tétel eltávolítva a gyűjteményből", "ToastRemoveItemFromCollectionSuccess": "Tétel eltávolítva a gyűjteményből",

View file

@ -30,6 +30,8 @@
"ButtonEditChapters": "Modifica Capitoli", "ButtonEditChapters": "Modifica Capitoli",
"ButtonEditPodcast": "Modifica Podcast", "ButtonEditPodcast": "Modifica Podcast",
"ButtonEnable": "Abilita", "ButtonEnable": "Abilita",
"ButtonFireAndFail": "Fire and Fail",
"ButtonFireOnTest": "Fire onTest event",
"ButtonForceReScan": "Forza Re-Scan", "ButtonForceReScan": "Forza Re-Scan",
"ButtonFullPath": "Percorso Completo", "ButtonFullPath": "Percorso Completo",
"ButtonHide": "Nascondi", "ButtonHide": "Nascondi",
@ -54,6 +56,7 @@
"ButtonOpenManager": "Apri Manager", "ButtonOpenManager": "Apri Manager",
"ButtonPause": "Pausa", "ButtonPause": "Pausa",
"ButtonPlay": "Riproduci", "ButtonPlay": "Riproduci",
"ButtonPlayAll": "Riproduci tutto",
"ButtonPlaying": "In riproduzione", "ButtonPlaying": "In riproduzione",
"ButtonPlaylists": "Playlist", "ButtonPlaylists": "Playlist",
"ButtonPrevious": "Precendente", "ButtonPrevious": "Precendente",
@ -96,6 +99,7 @@
"ButtonStats": "Statistische", "ButtonStats": "Statistische",
"ButtonSubmit": "Invia", "ButtonSubmit": "Invia",
"ButtonTest": "Test", "ButtonTest": "Test",
"ButtonUnlinkOpenId": "Disattiva OpenID",
"ButtonUpload": "Carica", "ButtonUpload": "Carica",
"ButtonUploadBackup": "Carica il backup", "ButtonUploadBackup": "Carica il backup",
"ButtonUploadCover": "Carica una copertina", "ButtonUploadCover": "Carica una copertina",
@ -184,7 +188,7 @@
"HeaderSettingsGeneral": "Generale", "HeaderSettingsGeneral": "Generale",
"HeaderSettingsScanner": "Scanner", "HeaderSettingsScanner": "Scanner",
"HeaderSleepTimer": "Sveglia", "HeaderSleepTimer": "Sveglia",
"HeaderStatsLargestItems": "Oggetti Grandi", "HeaderStatsLargestItems": "File pesanti",
"HeaderStatsLongestItems": "libri più lunghi (ore)", "HeaderStatsLongestItems": "libri più lunghi (ore)",
"HeaderStatsMinutesListeningChart": "Minuti ascoltati (Ultimi 7 Giorni)", "HeaderStatsMinutesListeningChart": "Minuti ascoltati (Ultimi 7 Giorni)",
"HeaderStatsRecentSessions": "Sessioni Recenti", "HeaderStatsRecentSessions": "Sessioni Recenti",
@ -253,6 +257,7 @@
"LabelClosePlayer": "Chiudi player", "LabelClosePlayer": "Chiudi player",
"LabelCodec": "Codec", "LabelCodec": "Codec",
"LabelCollapseSeries": "Comprimi Serie", "LabelCollapseSeries": "Comprimi Serie",
"LabelCollapseSubSeries": "Comprimi subserie",
"LabelCollection": "Raccolta", "LabelCollection": "Raccolta",
"LabelCollections": "Raccolte", "LabelCollections": "Raccolte",
"LabelComplete": "Completo", "LabelComplete": "Completo",
@ -293,7 +298,7 @@
"LabelEmailSettingsFromAddress": "Da Indirizzo", "LabelEmailSettingsFromAddress": "Da Indirizzo",
"LabelEmailSettingsRejectUnauthorized": "Rifiuta i certificati non autorizzati", "LabelEmailSettingsRejectUnauthorized": "Rifiuta i certificati non autorizzati",
"LabelEmailSettingsRejectUnauthorizedHelp": "La disattivazione della convalida del certificato SSL può esporre la tua connessione a rischi per la sicurezza, come attacchi man-in-the-middle. Disattiva questa opzione solo se ne comprendi le implicazioni e ti fidi del server di posta a cui ti stai connettendo.", "LabelEmailSettingsRejectUnauthorizedHelp": "La disattivazione della convalida del certificato SSL può esporre la tua connessione a rischi per la sicurezza, come attacchi man-in-the-middle. Disattiva questa opzione solo se ne comprendi le implicazioni e ti fidi del server di posta a cui ti stai connettendo.",
"LabelEmailSettingsSecure": "Sicuro", "LabelEmailSettingsSecure": "SSL",
"LabelEmailSettingsSecureHelp": "Se vero, la connessione utilizzerà TLS durante la connessione al server. Se false, viene utilizzato TLS se il server supporta l'estensione STARTTLS. Nella maggior parte dei casi impostare questo valore su true se ci si connette alla porta 465. Per la porta 587 o 25 mantenerlo false. (da nodemailer.com/smtp/#authentication)", "LabelEmailSettingsSecureHelp": "Se vero, la connessione utilizzerà TLS durante la connessione al server. Se false, viene utilizzato TLS se il server supporta l'estensione STARTTLS. Nella maggior parte dei casi impostare questo valore su true se ci si connette alla porta 465. Per la porta 587 o 25 mantenerlo false. (da nodemailer.com/smtp/#authentication)",
"LabelEmailSettingsTestAddress": "Indirizzo di test", "LabelEmailSettingsTestAddress": "Indirizzo di test",
"LabelEmbeddedCover": "Cover Integrata", "LabelEmbeddedCover": "Cover Integrata",
@ -306,6 +311,7 @@
"LabelEpisodes": "Episodi", "LabelEpisodes": "Episodi",
"LabelExample": "Esempio", "LabelExample": "Esempio",
"LabelExpandSeries": "Espandi Serie", "LabelExpandSeries": "Espandi Serie",
"LabelExpandSubSeries": "Espandi Sub Serie",
"LabelExplicit": "Esplicito", "LabelExplicit": "Esplicito",
"LabelExplicitChecked": "Esplicito (selezionato)", "LabelExplicitChecked": "Esplicito (selezionato)",
"LabelExplicitUnchecked": "Non Esplicito (selezionato)", "LabelExplicitUnchecked": "Non Esplicito (selezionato)",
@ -798,27 +804,25 @@
"StatsBooksAdditional": "Alcune aggiunte includono…", "StatsBooksAdditional": "Alcune aggiunte includono…",
"StatsBooksFinished": "Libri Finiti", "StatsBooksFinished": "Libri Finiti",
"StatsBooksFinishedThisYear": "Alcuni libri terminati quest'anno…", "StatsBooksFinishedThisYear": "Alcuni libri terminati quest'anno…",
"StatsBooksListenedTo": "libri ascoltati", "StatsBooksListenedTo": "Libri ascoltati",
"StatsCollectionGrewTo": "La tua collezione di libri è cresciuta fino a…", "StatsCollectionGrewTo": "La tua collezione è aumentata di…",
"StatsSessions": "sessioni", "StatsSessions": "Sessioni",
"StatsSpentListening": "trascorso ad ascoltare", "StatsSpentListening": "Tempo di Ascolto",
"StatsTopAuthor": "MIGLIOR AUTORE", "StatsTopAuthor": "MIGLIOR AUTORE",
"StatsTopAuthors": "MIGLIORI AUTORI", "StatsTopAuthors": "AUTORI MIGLIORI",
"StatsTopGenre": "MIGLIOR GENERE", "StatsTopGenre": "MIGLIOR GENERE",
"StatsTopGenres": "MIGLIORI GENERI", "StatsTopGenres": "GENERI MIGLIORI",
"StatsTopMonth": "MIGLIOR MESE", "StatsTopMonth": "MIGLIOR MESE",
"StatsTopNarrator": "MIGLIOR NARRATORE", "StatsTopNarrator": "MIGLIOR NARRATORE",
"StatsTopNarrators": "MIGLIORI NARRATORI", "StatsTopNarrators": "NARRATORI MIGLIORI",
"StatsTotalDuration": "Con una durata totale di…", "StatsTotalDuration": "Per una durata totale di…",
"StatsYearInReview": "ANNO IN RASSEGNA", "StatsYearInReview": "ANNO IN RASSEGNA",
"ToastAccountUpdateFailed": "Aggiornamento Account Fallito",
"ToastAccountUpdateSuccess": "Account Aggiornato", "ToastAccountUpdateSuccess": "Account Aggiornato",
"ToastAppriseUrlRequired": "È necessario immettere un indirizzo Apprise", "ToastAppriseUrlRequired": "È necessario immettere un indirizzo Apprise",
"ToastAuthorImageRemoveSuccess": "Immagine Autore Rimossa", "ToastAuthorImageRemoveSuccess": "Immagine Autore Rimossa",
"ToastAuthorNotFound": "Autore\"{0}\" non trovato", "ToastAuthorNotFound": "Autore\"{0}\" non trovato",
"ToastAuthorRemoveSuccess": "Autore rimosso", "ToastAuthorRemoveSuccess": "Autore rimosso",
"ToastAuthorSearchNotFound": "Autore non trovato", "ToastAuthorSearchNotFound": "Autore non trovato",
"ToastAuthorUpdateFailed": "Aggiornamento Autore Fallito",
"ToastAuthorUpdateMerged": "Autore unito", "ToastAuthorUpdateMerged": "Autore unito",
"ToastAuthorUpdateSuccess": "Autore aggiornato", "ToastAuthorUpdateSuccess": "Autore aggiornato",
"ToastAuthorUpdateSuccessNoImageFound": "Autore aggiornato (nessuna immagine trovata)", "ToastAuthorUpdateSuccessNoImageFound": "Autore aggiornato (nessuna immagine trovata)",
@ -829,7 +833,6 @@
"ToastBackupDeleteSuccess": "backup Eliminato", "ToastBackupDeleteSuccess": "backup Eliminato",
"ToastBackupInvalidMaxKeep": "Numero non valido di backup da conservare", "ToastBackupInvalidMaxKeep": "Numero non valido di backup da conservare",
"ToastBackupInvalidMaxSize": "Dimensione massima del backup non valida", "ToastBackupInvalidMaxSize": "Dimensione massima del backup non valida",
"ToastBackupPathUpdateFailed": "Impossibile aggiornare il percorso di backup",
"ToastBackupRestoreFailed": "Ripristino fallito", "ToastBackupRestoreFailed": "Ripristino fallito",
"ToastBackupUploadFailed": "Caricamento backup fallito", "ToastBackupUploadFailed": "Caricamento backup fallito",
"ToastBackupUploadSuccess": "Backup caricato", "ToastBackupUploadSuccess": "Backup caricato",
@ -840,7 +843,6 @@
"ToastBookmarkCreateFailed": "Creazione segnalibro fallita", "ToastBookmarkCreateFailed": "Creazione segnalibro fallita",
"ToastBookmarkCreateSuccess": "Segnalibro creato", "ToastBookmarkCreateSuccess": "Segnalibro creato",
"ToastBookmarkRemoveSuccess": "Segnalibro Rimosso", "ToastBookmarkRemoveSuccess": "Segnalibro Rimosso",
"ToastBookmarkUpdateFailed": "Aggiornamento segnalibro fallito",
"ToastBookmarkUpdateSuccess": "Segnalibro aggiornato", "ToastBookmarkUpdateSuccess": "Segnalibro aggiornato",
"ToastCachePurgeFailed": "Impossibile eliminare la cache", "ToastCachePurgeFailed": "Impossibile eliminare la cache",
"ToastCachePurgeSuccess": "Cache eliminata correttamente", "ToastCachePurgeSuccess": "Cache eliminata correttamente",
@ -851,7 +853,6 @@
"ToastCollectionItemsAddSuccess": "L'aggiunta dell'elemento(i) alla raccolta è riuscito", "ToastCollectionItemsAddSuccess": "L'aggiunta dell'elemento(i) alla raccolta è riuscito",
"ToastCollectionItemsRemoveSuccess": "Oggetto(i) rimossi dalla Raccolta", "ToastCollectionItemsRemoveSuccess": "Oggetto(i) rimossi dalla Raccolta",
"ToastCollectionRemoveSuccess": "Collezione rimossa", "ToastCollectionRemoveSuccess": "Collezione rimossa",
"ToastCollectionUpdateFailed": "Errore aggiornamento Raccolta",
"ToastCollectionUpdateSuccess": "Raccolta aggiornata", "ToastCollectionUpdateSuccess": "Raccolta aggiornata",
"ToastCoverUpdateFailed": "Aggiornamento cover fallito", "ToastCoverUpdateFailed": "Aggiornamento cover fallito",
"ToastDeleteFileFailed": "Impossibile eliminare il file", "ToastDeleteFileFailed": "Impossibile eliminare il file",
@ -860,49 +861,99 @@
"ToastDeviceNameAlreadyExists": "Esiste già un dispositivo e-reader con quel nome", "ToastDeviceNameAlreadyExists": "Esiste già un dispositivo e-reader con quel nome",
"ToastDeviceTestEmailFailed": "Impossibile inviare l'e-mail di prova", "ToastDeviceTestEmailFailed": "Impossibile inviare l'e-mail di prova",
"ToastDeviceTestEmailSuccess": "Test invio mail completato", "ToastDeviceTestEmailSuccess": "Test invio mail completato",
"ToastEmailSettingsUpdateSuccess": "Impostazioni e-mail aggiornate",
"ToastEncodeCancelFailed": "Impossibile annullare la codifica",
"ToastEncodeCancelSucces": "Codifica annullata",
"ToastEpisodeDownloadQueueClearFailed": "Impossibile cancellare la coda",
"ToastEpisodeDownloadQueueClearSuccess": "Coda di download degli episodi cancellata",
"ToastErrorCannotShare": "Impossibile condividere in modo nativo su questo dispositivo", "ToastErrorCannotShare": "Impossibile condividere in modo nativo su questo dispositivo",
"ToastFailedToLoadData": "Impossibile caricare i dati", "ToastFailedToLoadData": "Impossibile caricare i dati",
"ToastItemCoverUpdateFailed": "Errore Aggiornamento cover", "ToastFailedToShare": "Impossibile condividere",
"ToastInvalidImageUrl": "URL dell'immagine non valido",
"ToastInvalidUrl": "URL non valido",
"ToastItemCoverUpdateSuccess": "Cover aggiornata", "ToastItemCoverUpdateSuccess": "Cover aggiornata",
"ToastItemDetailsUpdateFailed": "Errore Aggiornamento dettagli file", "ToastItemDeletedFailed": "Impossibile eliminare l'elemento",
"ToastItemDeletedSuccess": "Elemento eliminato",
"ToastItemDetailsUpdateSuccess": "Dettagli file Aggiornata", "ToastItemDetailsUpdateSuccess": "Dettagli file Aggiornata",
"ToastItemMarkedAsFinishedFailed": "Errore nel segnare il file come finito", "ToastItemMarkedAsFinishedFailed": "Errore nel segnare il file come finito",
"ToastItemMarkedAsFinishedSuccess": "File segnato come finito", "ToastItemMarkedAsFinishedSuccess": "File segnato come finito",
"ToastItemMarkedAsNotFinishedFailed": "Errore nel segnare il file come non completo", "ToastItemMarkedAsNotFinishedFailed": "Errore nel segnare il file come non completo",
"ToastItemMarkedAsNotFinishedSuccess": "File segnato come non completo", "ToastItemMarkedAsNotFinishedSuccess": "File segnato come non completo",
"ToastItemUpdateSuccess": "Articolo aggiornato",
"ToastLibraryCreateFailed": "Errore creazione libreria", "ToastLibraryCreateFailed": "Errore creazione libreria",
"ToastLibraryCreateSuccess": "Libreria \"{0}\" creata", "ToastLibraryCreateSuccess": "Libreria \"{0}\" creata",
"ToastLibraryDeleteFailed": "Errore cancellazione libreria", "ToastLibraryDeleteFailed": "Errore cancellazione libreria",
"ToastLibraryDeleteSuccess": "Libreria Cancellata", "ToastLibraryDeleteSuccess": "Libreria Cancellata",
"ToastLibraryScanFailedToStart": "Errore inizio scansione", "ToastLibraryScanFailedToStart": "Errore inizio scansione",
"ToastLibraryScanStarted": "Scansione Libreria iniziata", "ToastLibraryScanStarted": "Scansione Libreria iniziata",
"ToastLibraryUpdateFailed": "Errore Aggiornamento libreria",
"ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata", "ToastLibraryUpdateSuccess": "Libreria \"{0}\" aggiornata",
"ToastNameEmailRequired": "Nome ed email sono obbligatori",
"ToastNameRequired": "Il nome è obbligatorio",
"ToastNewUserCreatedFailed": "Impossibile creare l'account: \"{0}\"",
"ToastNewUserCreatedSuccess": "Nuovo account creato",
"ToastNewUserLibraryError": "È necessario selezionare almeno una libreria",
"ToastNewUserPasswordError": "Deve avere una password, solo l'utente root può avere una password vuota",
"ToastNewUserTagError": "Devi selezionare almeno un tag",
"ToastNewUserUsernameError": "Inserisci un nome utente",
"ToastNoUpdatesNecessary": "Nessun aggiornamento necessario",
"ToastNotificationCreateFailed": "Impossibile creare la notifica",
"ToastNotificationDeleteFailed": "Impossibile eliminare la notifica",
"ToastNotificationFailedMaximum": "Il numero massimo di tentativi falliti deve essere >= 0",
"ToastNotificationQueueMaximum": "La coda di notifica massima deve essere >= 0",
"ToastNotificationSettingsUpdateSuccess": "Impostazioni di notifica aggiornate",
"ToastNotificationTestTriggerFailed": "Impossibile attivare la notifica del test",
"ToastNotificationTestTriggerSuccess": "Notifica di test attivata",
"ToastNotificationUpdateSuccess": "Notifica aggiornata",
"ToastPlaylistCreateFailed": "Errore creazione playlist", "ToastPlaylistCreateFailed": "Errore creazione playlist",
"ToastPlaylistCreateSuccess": "Playlist creata", "ToastPlaylistCreateSuccess": "Playlist creata",
"ToastPlaylistRemoveSuccess": "Playlist rimossa", "ToastPlaylistRemoveSuccess": "Playlist rimossa",
"ToastPlaylistUpdateFailed": "Aggiornamento Playlist Fallita",
"ToastPlaylistUpdateSuccess": "Playlist Aggiornata", "ToastPlaylistUpdateSuccess": "Playlist Aggiornata",
"ToastPodcastCreateFailed": "Errore creazione podcast", "ToastPodcastCreateFailed": "Errore creazione podcast",
"ToastPodcastCreateSuccess": "Podcast creato correttamente", "ToastPodcastCreateSuccess": "Podcast creato correttamente",
"ToastPodcastGetFeedFailed": "Impossibile ottenere il feed del podcast",
"ToastPodcastNoEpisodesInFeed": "Nessun episodio trovato nel feed RSS",
"ToastPodcastNoRssFeed": "Il podcast non ha un feed RSS",
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
"ToastProviderNameAndUrlRequired": "Nome e URL richiesti",
"ToastProviderRemoveSuccess": "Provider rimosso",
"ToastRSSFeedCloseFailed": "Errore chiusura flusso RSS", "ToastRSSFeedCloseFailed": "Errore chiusura flusso RSS",
"ToastRSSFeedCloseSuccess": "Flusso RSS chiuso", "ToastRSSFeedCloseSuccess": "Flusso RSS chiuso",
"ToastRemoveFailed": "Impossibile rimuovere",
"ToastRemoveItemFromCollectionFailed": "Errore rimozione file dalla Raccolta", "ToastRemoveItemFromCollectionFailed": "Errore rimozione file dalla Raccolta",
"ToastRemoveItemFromCollectionSuccess": "Oggetto rimosso dalla Raccolta", "ToastRemoveItemFromCollectionSuccess": "Oggetto rimosso dalla Raccolta",
"ToastRemoveItemsWithIssuesFailed": "Impossibile rimuovere gli elementi della libreria con problemi",
"ToastRemoveItemsWithIssuesSuccess": "Rimossi gli elementi della libreria con problemi",
"ToastRenameFailed": "Impossibile rinominare",
"ToastRescanFailed": "Nuova scansione non riuscita per {0}",
"ToastRescanRemoved": "L'articolo completo di Re-Scan è stato rimosso",
"ToastRescanUpToDate": "La nuova scansione dell'articolo completo è stata aggiornata",
"ToastRescanUpdated": "L'articolo completo di Re-Scan è stato aggiornato",
"ToastScanFailed": "Impossibile eseguire la scansione dell'elemento della libreria",
"ToastSelectAtLeastOneUser": "Seleziona almeno un utente",
"ToastSendEbookToDeviceFailed": "Impossibile inviare il libro al dispositivo", "ToastSendEbookToDeviceFailed": "Impossibile inviare il libro al dispositivo",
"ToastSendEbookToDeviceSuccess": "Libro inviato al dispositivo «{0}»", "ToastSendEbookToDeviceSuccess": "Libro inviato al dispositivo «{0}»",
"ToastSeriesUpdateFailed": "Aggiornamento Serie Fallito", "ToastSeriesUpdateFailed": "Aggiornamento Serie Fallito",
"ToastSeriesUpdateSuccess": "Serie Aggiornate", "ToastSeriesUpdateSuccess": "Serie Aggiornate",
"ToastServerSettingsUpdateFailed": "Impossibile aggiornare le impostazioni del server",
"ToastServerSettingsUpdateSuccess": "Impostazioni del server aggiornate", "ToastServerSettingsUpdateSuccess": "Impostazioni del server aggiornate",
"ToastSessionCloseFailed": "Disconnessione Fallita",
"ToastSessionDeleteFailed": "Errore eliminazione sessione", "ToastSessionDeleteFailed": "Errore eliminazione sessione",
"ToastSessionDeleteSuccess": "Sessione cancellata", "ToastSessionDeleteSuccess": "Sessione cancellata",
"ToastSlugMustChange": "Lo slug contiene caratteri non validi",
"ToastSlugRequired": "È richiesto lo slug",
"ToastSocketConnected": "Socket connesso", "ToastSocketConnected": "Socket connesso",
"ToastSocketDisconnected": "Socket disconnesso", "ToastSocketDisconnected": "Socket disconnesso",
"ToastSocketFailedToConnect": "Socket non riesce a connettersi", "ToastSocketFailedToConnect": "Socket non riesce a connettersi",
"ToastSortingPrefixesEmptyError": "Deve avere almeno 1 prefisso di ordinamento", "ToastSortingPrefixesEmptyError": "Deve avere almeno 1 prefisso di ordinamento",
"ToastSortingPrefixesUpdateFailed": "Impossibile aggiornare i prefissi di ordinamento",
"ToastSortingPrefixesUpdateSuccess": "Prefissi di ordinamento aggiornati ({0} items)", "ToastSortingPrefixesUpdateSuccess": "Prefissi di ordinamento aggiornati ({0} items)",
"ToastTitleRequired": "Il titolo è obbligatorio",
"ToastUnknownError": "Errore sconosciuto",
"ToastUnlinkOpenIdFailed": "Impossibile scollegare l'utente da OpenID",
"ToastUnlinkOpenIdSuccess": "Utente scollegato da OpenID",
"ToastUserDeleteFailed": "Errore eliminazione utente", "ToastUserDeleteFailed": "Errore eliminazione utente",
"ToastUserDeleteSuccess": "Utente eliminato" "ToastUserDeleteSuccess": "Utente eliminato",
"ToastUserPasswordChangeSuccess": "Password modificata con successo",
"ToastUserPasswordMismatch": "Le password non corrispondono",
"ToastUserPasswordMustChange": "La nuova password non può corrispondere alla vecchia password",
"ToastUserRootRequireName": "È necessario immettere un nome utente root"
} }

View file

@ -622,10 +622,8 @@
"PlaceholderNewPlaylist": "Naujas grojaraščio pavadinimas", "PlaceholderNewPlaylist": "Naujas grojaraščio pavadinimas",
"PlaceholderSearch": "Ieškoti..", "PlaceholderSearch": "Ieškoti..",
"PlaceholderSearchEpisode": "Ieškoti epizodo..", "PlaceholderSearchEpisode": "Ieškoti epizodo..",
"ToastAccountUpdateFailed": "Paskyros atnaujinimas nepavyko",
"ToastAccountUpdateSuccess": "Paskyra atnaujinta", "ToastAccountUpdateSuccess": "Paskyra atnaujinta",
"ToastAuthorImageRemoveSuccess": "Autoriaus paveiksliukas pašalintas", "ToastAuthorImageRemoveSuccess": "Autoriaus paveiksliukas pašalintas",
"ToastAuthorUpdateFailed": "Nepavyko atnaujinti autoriaus",
"ToastAuthorUpdateMerged": "Autorius sujungtas", "ToastAuthorUpdateMerged": "Autorius sujungtas",
"ToastAuthorUpdateSuccess": "Autorius atnaujintas", "ToastAuthorUpdateSuccess": "Autorius atnaujintas",
"ToastAuthorUpdateSuccessNoImageFound": "Autorius atnaujintas (paveiksliukas nerastas)", "ToastAuthorUpdateSuccessNoImageFound": "Autorius atnaujintas (paveiksliukas nerastas)",
@ -641,17 +639,13 @@
"ToastBookmarkCreateFailed": "Žymos sukurti nepavyko", "ToastBookmarkCreateFailed": "Žymos sukurti nepavyko",
"ToastBookmarkCreateSuccess": "Žyma pridėta", "ToastBookmarkCreateSuccess": "Žyma pridėta",
"ToastBookmarkRemoveSuccess": "Žyma pašalinta", "ToastBookmarkRemoveSuccess": "Žyma pašalinta",
"ToastBookmarkUpdateFailed": "Žymos atnaujinti nepavyko",
"ToastBookmarkUpdateSuccess": "Žyma atnaujinta", "ToastBookmarkUpdateSuccess": "Žyma atnaujinta",
"ToastChaptersHaveErrors": "Skyriai turi klaidų", "ToastChaptersHaveErrors": "Skyriai turi klaidų",
"ToastChaptersMustHaveTitles": "Skyriai turi turėti pavadinimus", "ToastChaptersMustHaveTitles": "Skyriai turi turėti pavadinimus",
"ToastCollectionItemsRemoveSuccess": "Elementai pašalinti iš kolekcijos", "ToastCollectionItemsRemoveSuccess": "Elementai pašalinti iš kolekcijos",
"ToastCollectionRemoveSuccess": "Kolekcija pašalinta", "ToastCollectionRemoveSuccess": "Kolekcija pašalinta",
"ToastCollectionUpdateFailed": "Kolekcijos atnaujinti nepavyko",
"ToastCollectionUpdateSuccess": "Kolekcija atnaujinta", "ToastCollectionUpdateSuccess": "Kolekcija atnaujinta",
"ToastItemCoverUpdateFailed": "Elemento viršelio atnaujinti nepavyko",
"ToastItemCoverUpdateSuccess": "Elemento viršelis atnaujintas", "ToastItemCoverUpdateSuccess": "Elemento viršelis atnaujintas",
"ToastItemDetailsUpdateFailed": "Elemento detalių atnaujinti nepavyko",
"ToastItemDetailsUpdateSuccess": "Elemento detalės atnaujintos", "ToastItemDetailsUpdateSuccess": "Elemento detalės atnaujintos",
"ToastItemMarkedAsFinishedFailed": "Pažymėti kaip Baigta nepavyko", "ToastItemMarkedAsFinishedFailed": "Pažymėti kaip Baigta nepavyko",
"ToastItemMarkedAsFinishedSuccess": "Elementas pažymėtas kaip Baigta", "ToastItemMarkedAsFinishedSuccess": "Elementas pažymėtas kaip Baigta",
@ -663,12 +657,10 @@
"ToastLibraryDeleteSuccess": "Biblioteka ištrinta", "ToastLibraryDeleteSuccess": "Biblioteka ištrinta",
"ToastLibraryScanFailedToStart": "Nepavyko pradėti bibliotekos skenavimo", "ToastLibraryScanFailedToStart": "Nepavyko pradėti bibliotekos skenavimo",
"ToastLibraryScanStarted": "Bibliotekos skenavimas pradėtas", "ToastLibraryScanStarted": "Bibliotekos skenavimas pradėtas",
"ToastLibraryUpdateFailed": "Bibliotekos atnaujinti nepavyko",
"ToastLibraryUpdateSuccess": "Biblioteka \"{0}\" atnaujinta", "ToastLibraryUpdateSuccess": "Biblioteka \"{0}\" atnaujinta",
"ToastPlaylistCreateFailed": "Grojaraščio sukurti nepavyko", "ToastPlaylistCreateFailed": "Grojaraščio sukurti nepavyko",
"ToastPlaylistCreateSuccess": "Grojaraštis sukurtas", "ToastPlaylistCreateSuccess": "Grojaraštis sukurtas",
"ToastPlaylistRemoveSuccess": "Grojaraštis pašalintas", "ToastPlaylistRemoveSuccess": "Grojaraštis pašalintas",
"ToastPlaylistUpdateFailed": "Grojaraščio atnaujinti nepavyko",
"ToastPlaylistUpdateSuccess": "Grojaraštis atnaujintas", "ToastPlaylistUpdateSuccess": "Grojaraštis atnaujintas",
"ToastPodcastCreateFailed": "Tinklalaidės sukurti nepavyko", "ToastPodcastCreateFailed": "Tinklalaidės sukurti nepavyko",
"ToastPodcastCreateSuccess": "Tinklalaidė sėkmingai sukurta", "ToastPodcastCreateSuccess": "Tinklalaidė sėkmingai sukurta",

View file

@ -614,10 +614,8 @@
"PlaceholderNewPlaylist": "Nieuwe naam afspeellijst", "PlaceholderNewPlaylist": "Nieuwe naam afspeellijst",
"PlaceholderSearch": "Zoeken..", "PlaceholderSearch": "Zoeken..",
"PlaceholderSearchEpisode": "Aflevering zoeken..", "PlaceholderSearchEpisode": "Aflevering zoeken..",
"ToastAccountUpdateFailed": "Bijwerken account mislukt",
"ToastAccountUpdateSuccess": "Account bijgewerkt", "ToastAccountUpdateSuccess": "Account bijgewerkt",
"ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd", "ToastAuthorImageRemoveSuccess": "Afbeelding auteur verwijderd",
"ToastAuthorUpdateFailed": "Bijwerken auteur mislukt",
"ToastAuthorUpdateMerged": "Auteur samengevoegd", "ToastAuthorUpdateMerged": "Auteur samengevoegd",
"ToastAuthorUpdateSuccess": "Auteur bijgewerkt", "ToastAuthorUpdateSuccess": "Auteur bijgewerkt",
"ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)", "ToastAuthorUpdateSuccessNoImageFound": "Auteur bijgewerkt (geen afbeelding gevonden)",
@ -633,17 +631,13 @@
"ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt", "ToastBookmarkCreateFailed": "Aanmaken boekwijzer mislukt",
"ToastBookmarkCreateSuccess": "boekwijzer toegevoegd", "ToastBookmarkCreateSuccess": "boekwijzer toegevoegd",
"ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd", "ToastBookmarkRemoveSuccess": "Boekwijzer verwijderd",
"ToastBookmarkUpdateFailed": "Bijwerken boekwijzer mislukt",
"ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt", "ToastBookmarkUpdateSuccess": "Boekwijzer bijgewerkt",
"ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten", "ToastChaptersHaveErrors": "Hoofdstukken bevatten fouten",
"ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben", "ToastChaptersMustHaveTitles": "Hoofdstukken moeten titels hebben",
"ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie", "ToastCollectionItemsRemoveSuccess": "Onderdeel (of onderdelen) verwijderd uit collectie",
"ToastCollectionRemoveSuccess": "Collectie verwijderd", "ToastCollectionRemoveSuccess": "Collectie verwijderd",
"ToastCollectionUpdateFailed": "Bijwerken collectie mislukt",
"ToastCollectionUpdateSuccess": "Collectie bijgewerkt", "ToastCollectionUpdateSuccess": "Collectie bijgewerkt",
"ToastItemCoverUpdateFailed": "Bijwerken cover onderdeel mislukt",
"ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt", "ToastItemCoverUpdateSuccess": "Cover onderdeel bijgewerkt",
"ToastItemDetailsUpdateFailed": "Bijwerken details onderdeel mislukt",
"ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt", "ToastItemDetailsUpdateSuccess": "Details onderdeel bijgewerkt",
"ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt", "ToastItemMarkedAsFinishedFailed": "Markeren als Voltooid mislukt",
"ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid", "ToastItemMarkedAsFinishedSuccess": "Onderdeel gemarkeerd als Voltooid",
@ -655,12 +649,10 @@
"ToastLibraryDeleteSuccess": "Bibliotheek verwijderd", "ToastLibraryDeleteSuccess": "Bibliotheek verwijderd",
"ToastLibraryScanFailedToStart": "Starten scan mislukt", "ToastLibraryScanFailedToStart": "Starten scan mislukt",
"ToastLibraryScanStarted": "Scannen bibliotheek gestart", "ToastLibraryScanStarted": "Scannen bibliotheek gestart",
"ToastLibraryUpdateFailed": "Bijwerken bibliotheek mislukt",
"ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt", "ToastLibraryUpdateSuccess": "Bibliotheek \"{0}\" bijgewerkt",
"ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt", "ToastPlaylistCreateFailed": "Aanmaken afspeellijst mislukt",
"ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt", "ToastPlaylistCreateSuccess": "Afspeellijst aangemaakt",
"ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd", "ToastPlaylistRemoveSuccess": "Afspeellijst verwijderd",
"ToastPlaylistUpdateFailed": "Afspeellijst bijwerken mislukt",
"ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt", "ToastPlaylistUpdateSuccess": "Afspeellijst bijgewerkt",
"ToastPodcastCreateFailed": "Podcast aanmaken mislukt", "ToastPodcastCreateFailed": "Podcast aanmaken mislukt",
"ToastPodcastCreateSuccess": "Podcast aangemaakt", "ToastPodcastCreateSuccess": "Podcast aangemaakt",

View file

@ -641,10 +641,8 @@
"PlaceholderNewPlaylist": "Ny spillelistenavn", "PlaceholderNewPlaylist": "Ny spillelistenavn",
"PlaceholderSearch": "Søk..", "PlaceholderSearch": "Søk..",
"PlaceholderSearchEpisode": "Søk episode..", "PlaceholderSearchEpisode": "Søk episode..",
"ToastAccountUpdateFailed": "Mislykkes å oppdatere konto",
"ToastAccountUpdateSuccess": "Konto oppdatert", "ToastAccountUpdateSuccess": "Konto oppdatert",
"ToastAuthorImageRemoveSuccess": "Forfatter bilde fjernet", "ToastAuthorImageRemoveSuccess": "Forfatter bilde fjernet",
"ToastAuthorUpdateFailed": "Mislykkes å oppdatere forfatter",
"ToastAuthorUpdateMerged": "Forfatter slått sammen", "ToastAuthorUpdateMerged": "Forfatter slått sammen",
"ToastAuthorUpdateSuccess": "Forfatter oppdatert", "ToastAuthorUpdateSuccess": "Forfatter oppdatert",
"ToastAuthorUpdateSuccessNoImageFound": "Forfatter oppdater (ingen bilde funnet)", "ToastAuthorUpdateSuccessNoImageFound": "Forfatter oppdater (ingen bilde funnet)",
@ -660,17 +658,13 @@
"ToastBookmarkCreateFailed": "Misslykkes å opprette bokmerke", "ToastBookmarkCreateFailed": "Misslykkes å opprette bokmerke",
"ToastBookmarkCreateSuccess": "Bokmerke lagt til", "ToastBookmarkCreateSuccess": "Bokmerke lagt til",
"ToastBookmarkRemoveSuccess": "Bokmerke fjernet", "ToastBookmarkRemoveSuccess": "Bokmerke fjernet",
"ToastBookmarkUpdateFailed": "Misslykkes å oppdatere bokmerke",
"ToastBookmarkUpdateSuccess": "Bokmerke oppdatert", "ToastBookmarkUpdateSuccess": "Bokmerke oppdatert",
"ToastChaptersHaveErrors": "Kapittel har feil", "ToastChaptersHaveErrors": "Kapittel har feil",
"ToastChaptersMustHaveTitles": "Kapittel må ha titler", "ToastChaptersMustHaveTitles": "Kapittel må ha titler",
"ToastCollectionItemsRemoveSuccess": "Gjenstand(er) fjernet fra samling", "ToastCollectionItemsRemoveSuccess": "Gjenstand(er) fjernet fra samling",
"ToastCollectionRemoveSuccess": "Samling fjernet", "ToastCollectionRemoveSuccess": "Samling fjernet",
"ToastCollectionUpdateFailed": "Misslykkes å oppdatere samling",
"ToastCollectionUpdateSuccess": "samlingupdated", "ToastCollectionUpdateSuccess": "samlingupdated",
"ToastItemCoverUpdateFailed": "Misslykkes å oppdatere omslag",
"ToastItemCoverUpdateSuccess": "Omslag oppdatert", "ToastItemCoverUpdateSuccess": "Omslag oppdatert",
"ToastItemDetailsUpdateFailed": "Misslykkes å oppdatere detaljer",
"ToastItemDetailsUpdateSuccess": "Detaljer oppdatert", "ToastItemDetailsUpdateSuccess": "Detaljer oppdatert",
"ToastItemMarkedAsFinishedFailed": "Misslykkes å markere som Fullført", "ToastItemMarkedAsFinishedFailed": "Misslykkes å markere som Fullført",
"ToastItemMarkedAsFinishedSuccess": "Gjenstand marker som Fullført", "ToastItemMarkedAsFinishedSuccess": "Gjenstand marker som Fullført",
@ -682,12 +676,10 @@
"ToastLibraryDeleteSuccess": "Bibliotek slettet", "ToastLibraryDeleteSuccess": "Bibliotek slettet",
"ToastLibraryScanFailedToStart": "Misslykkes å starte skann", "ToastLibraryScanFailedToStart": "Misslykkes å starte skann",
"ToastLibraryScanStarted": "Bibliotek skann startet", "ToastLibraryScanStarted": "Bibliotek skann startet",
"ToastLibraryUpdateFailed": "Misslykkes å oppdatere bibiliotek",
"ToastLibraryUpdateSuccess": "Bibliotek \"{0}\" oppdatert", "ToastLibraryUpdateSuccess": "Bibliotek \"{0}\" oppdatert",
"ToastPlaylistCreateFailed": "Misslykkes å opprette spilleliste", "ToastPlaylistCreateFailed": "Misslykkes å opprette spilleliste",
"ToastPlaylistCreateSuccess": "Spilleliste opprettet", "ToastPlaylistCreateSuccess": "Spilleliste opprettet",
"ToastPlaylistRemoveSuccess": "Spilleliste fjernet", "ToastPlaylistRemoveSuccess": "Spilleliste fjernet",
"ToastPlaylistUpdateFailed": "Misslykkes å oppdatere spilleliste",
"ToastPlaylistUpdateSuccess": "Spilleliste oppdatert", "ToastPlaylistUpdateSuccess": "Spilleliste oppdatert",
"ToastPodcastCreateFailed": "Misslykkes å opprette podcast", "ToastPodcastCreateFailed": "Misslykkes å opprette podcast",
"ToastPodcastCreateSuccess": "Podcast opprettet", "ToastPodcastCreateSuccess": "Podcast opprettet",

View file

@ -54,10 +54,12 @@
"ButtonOpenManager": "Otwórz menadżera", "ButtonOpenManager": "Otwórz menadżera",
"ButtonPause": "Wstrzymaj", "ButtonPause": "Wstrzymaj",
"ButtonPlay": "Odtwarzaj", "ButtonPlay": "Odtwarzaj",
"ButtonPlayAll": "Odtwórz wszystko",
"ButtonPlaying": "Odtwarzane", "ButtonPlaying": "Odtwarzane",
"ButtonPlaylists": "Listy odtwarzania", "ButtonPlaylists": "Listy odtwarzania",
"ButtonPrevious": "Poprzedni", "ButtonPrevious": "Poprzedni",
"ButtonPreviousChapter": "Poprzedni rozdział", "ButtonPreviousChapter": "Poprzedni rozdział",
"ButtonProbeAudioFile": "Próbka audio",
"ButtonPurgeAllCache": "Wyczyść dane tymczasowe", "ButtonPurgeAllCache": "Wyczyść dane tymczasowe",
"ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji", "ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji",
"ButtonQueueAddItem": "Dodaj do kolejki", "ButtonQueueAddItem": "Dodaj do kolejki",
@ -95,6 +97,7 @@
"ButtonStats": "Statystyki", "ButtonStats": "Statystyki",
"ButtonSubmit": "Zaloguj", "ButtonSubmit": "Zaloguj",
"ButtonTest": "Test", "ButtonTest": "Test",
"ButtonUnlinkOpenId": "Odłącz OpenID",
"ButtonUpload": "Wgraj", "ButtonUpload": "Wgraj",
"ButtonUploadBackup": "Wgraj kopię zapasową", "ButtonUploadBackup": "Wgraj kopię zapasową",
"ButtonUploadCover": "Wgraj okładkę", "ButtonUploadCover": "Wgraj okładkę",
@ -355,7 +358,8 @@
"LabelIntervalEveryHour": "Każdej godziny", "LabelIntervalEveryHour": "Każdej godziny",
"LabelInvert": "Inversja", "LabelInvert": "Inversja",
"LabelItem": "Pozycja", "LabelItem": "Pozycja",
"LabelJumpBackwardAmount": "Rozmiar skoku do przodu", "LabelJumpBackwardAmount": "Przeskocz do tyłu o:",
"LabelJumpForwardAmount": "Przeskocz do przodu o:",
"LabelLanguage": "Język", "LabelLanguage": "Język",
"LabelLanguageDefaultServer": "Domyślny język serwera", "LabelLanguageDefaultServer": "Domyślny język serwera",
"LabelLanguages": "Języki", "LabelLanguages": "Języki",
@ -738,10 +742,8 @@
"StatsTopNarrator": "TOPOWY NARRATOR", "StatsTopNarrator": "TOPOWY NARRATOR",
"StatsTopNarrators": "TOPOWI NARRATORZY", "StatsTopNarrators": "TOPOWI NARRATORZY",
"StatsYearInReview": "PRZEGLĄD ROKU", "StatsYearInReview": "PRZEGLĄD ROKU",
"ToastAccountUpdateFailed": "Nie udało się zaktualizować konta",
"ToastAccountUpdateSuccess": "Zaktualizowano konto", "ToastAccountUpdateSuccess": "Zaktualizowano konto",
"ToastAuthorImageRemoveSuccess": "Zdjęcie autora usunięte", "ToastAuthorImageRemoveSuccess": "Zdjęcie autora usunięte",
"ToastAuthorUpdateFailed": "nie udało się zaktualizować autora",
"ToastAuthorUpdateMerged": "Autor scalony", "ToastAuthorUpdateMerged": "Autor scalony",
"ToastAuthorUpdateSuccess": "Autor zaktualizowany", "ToastAuthorUpdateSuccess": "Autor zaktualizowany",
"ToastAuthorUpdateSuccessNoImageFound": "Autor zaktualizowany (nie znaleziono obrazu)", "ToastAuthorUpdateSuccessNoImageFound": "Autor zaktualizowany (nie znaleziono obrazu)",
@ -757,15 +759,11 @@
"ToastBookmarkCreateFailed": "Nie udało się utworzyć zakładki", "ToastBookmarkCreateFailed": "Nie udało się utworzyć zakładki",
"ToastBookmarkCreateSuccess": "Dodano zakładkę", "ToastBookmarkCreateSuccess": "Dodano zakładkę",
"ToastBookmarkRemoveSuccess": "Zakładka została usunięta", "ToastBookmarkRemoveSuccess": "Zakładka została usunięta",
"ToastBookmarkUpdateFailed": "Nie udało się zaktualizować zakładki",
"ToastBookmarkUpdateSuccess": "Zaktualizowano zakładkę", "ToastBookmarkUpdateSuccess": "Zaktualizowano zakładkę",
"ToastCollectionItemsRemoveSuccess": "Przedmiot(y) zostały usunięte z kolekcji", "ToastCollectionItemsRemoveSuccess": "Przedmiot(y) zostały usunięte z kolekcji",
"ToastCollectionRemoveSuccess": "Kolekcja usunięta", "ToastCollectionRemoveSuccess": "Kolekcja usunięta",
"ToastCollectionUpdateFailed": "Nie udało się zaktualizować kolekcji",
"ToastCollectionUpdateSuccess": "Zaktualizowano kolekcję", "ToastCollectionUpdateSuccess": "Zaktualizowano kolekcję",
"ToastItemCoverUpdateFailed": "Nie udało się zaktualizować okładki",
"ToastItemCoverUpdateSuccess": "Zaktualizowano okładkę", "ToastItemCoverUpdateSuccess": "Zaktualizowano okładkę",
"ToastItemDetailsUpdateFailed": "Nie udało się zaktualizować szczegółów",
"ToastItemDetailsUpdateSuccess": "Zaktualizowano szczegóły", "ToastItemDetailsUpdateSuccess": "Zaktualizowano szczegóły",
"ToastItemMarkedAsFinishedFailed": "Nie udało się oznaczyć jako ukończone", "ToastItemMarkedAsFinishedFailed": "Nie udało się oznaczyć jako ukończone",
"ToastItemMarkedAsFinishedSuccess": "Pozycja oznaczona jako ukończona", "ToastItemMarkedAsFinishedSuccess": "Pozycja oznaczona jako ukończona",
@ -777,12 +775,10 @@
"ToastLibraryDeleteSuccess": "Biblioteka usunięta", "ToastLibraryDeleteSuccess": "Biblioteka usunięta",
"ToastLibraryScanFailedToStart": "Nie udało się rozpocząć skanowania", "ToastLibraryScanFailedToStart": "Nie udało się rozpocząć skanowania",
"ToastLibraryScanStarted": "Rozpoczęto skanowanie biblioteki", "ToastLibraryScanStarted": "Rozpoczęto skanowanie biblioteki",
"ToastLibraryUpdateFailed": "Nie udało się zaktualizować biblioteki",
"ToastLibraryUpdateSuccess": "Zaktualizowano \"{0}\" pozycji", "ToastLibraryUpdateSuccess": "Zaktualizowano \"{0}\" pozycji",
"ToastPlaylistCreateFailed": "Nie udało się utworzyć playlisty", "ToastPlaylistCreateFailed": "Nie udało się utworzyć playlisty",
"ToastPlaylistCreateSuccess": "Playlista utworzona", "ToastPlaylistCreateSuccess": "Playlista utworzona",
"ToastPlaylistRemoveSuccess": "Playlista usunięta", "ToastPlaylistRemoveSuccess": "Playlista usunięta",
"ToastPlaylistUpdateFailed": "Nie udało się zaktualizować playlisty",
"ToastPlaylistUpdateSuccess": "Playlista zaktualizowana", "ToastPlaylistUpdateSuccess": "Playlista zaktualizowana",
"ToastPodcastCreateFailed": "Nie udało się utworzyć podcastu", "ToastPodcastCreateFailed": "Nie udało się utworzyć podcastu",
"ToastPodcastCreateSuccess": "Podcast został pomyślnie utworzony", "ToastPodcastCreateSuccess": "Podcast został pomyślnie utworzony",

View file

@ -710,10 +710,8 @@
"PlaceholderNewPlaylist": "Novo nome da lista de reprodução", "PlaceholderNewPlaylist": "Novo nome da lista de reprodução",
"PlaceholderSearch": "Buscar..", "PlaceholderSearch": "Buscar..",
"PlaceholderSearchEpisode": "Buscar Episódio..", "PlaceholderSearchEpisode": "Buscar Episódio..",
"ToastAccountUpdateFailed": "Falha ao atualizar a conta",
"ToastAccountUpdateSuccess": "Conta atualizada", "ToastAccountUpdateSuccess": "Conta atualizada",
"ToastAuthorImageRemoveSuccess": "Imagem do autor removida", "ToastAuthorImageRemoveSuccess": "Imagem do autor removida",
"ToastAuthorUpdateFailed": "Falha ao atualizar o autor",
"ToastAuthorUpdateMerged": "Autor combinado", "ToastAuthorUpdateMerged": "Autor combinado",
"ToastAuthorUpdateSuccess": "Autor atualizado", "ToastAuthorUpdateSuccess": "Autor atualizado",
"ToastAuthorUpdateSuccessNoImageFound": "Autor atualizado (nenhuma imagem encontrada)", "ToastAuthorUpdateSuccessNoImageFound": "Autor atualizado (nenhuma imagem encontrada)",
@ -729,7 +727,6 @@
"ToastBookmarkCreateFailed": "Falha ao criar marcador", "ToastBookmarkCreateFailed": "Falha ao criar marcador",
"ToastBookmarkCreateSuccess": "Marcador adicionado", "ToastBookmarkCreateSuccess": "Marcador adicionado",
"ToastBookmarkRemoveSuccess": "Marcador removido", "ToastBookmarkRemoveSuccess": "Marcador removido",
"ToastBookmarkUpdateFailed": "Falha ao atualizar o marcador",
"ToastBookmarkUpdateSuccess": "Marcador atualizado", "ToastBookmarkUpdateSuccess": "Marcador atualizado",
"ToastCachePurgeFailed": "Falha ao apagar o cache", "ToastCachePurgeFailed": "Falha ao apagar o cache",
"ToastCachePurgeSuccess": "Cache apagado com sucesso", "ToastCachePurgeSuccess": "Cache apagado com sucesso",
@ -737,14 +734,11 @@
"ToastChaptersMustHaveTitles": "Capítulos precisam ter títulos", "ToastChaptersMustHaveTitles": "Capítulos precisam ter títulos",
"ToastCollectionItemsRemoveSuccess": "Item(ns) removidos da coleção", "ToastCollectionItemsRemoveSuccess": "Item(ns) removidos da coleção",
"ToastCollectionRemoveSuccess": "Coleção removida", "ToastCollectionRemoveSuccess": "Coleção removida",
"ToastCollectionUpdateFailed": "Falha ao atualizar coleção",
"ToastCollectionUpdateSuccess": "Coleção atualizada", "ToastCollectionUpdateSuccess": "Coleção atualizada",
"ToastDeleteFileFailed": "Falha ao apagar arquivo", "ToastDeleteFileFailed": "Falha ao apagar arquivo",
"ToastDeleteFileSuccess": "Arquivo apagado", "ToastDeleteFileSuccess": "Arquivo apagado",
"ToastFailedToLoadData": "Falha ao carregar dados", "ToastFailedToLoadData": "Falha ao carregar dados",
"ToastItemCoverUpdateFailed": "Falha ao atualizar capa do item",
"ToastItemCoverUpdateSuccess": "Capa do item atualizada", "ToastItemCoverUpdateSuccess": "Capa do item atualizada",
"ToastItemDetailsUpdateFailed": "Falha ao atualizar detalhes do item",
"ToastItemDetailsUpdateSuccess": "Detalhes do item atualizados", "ToastItemDetailsUpdateSuccess": "Detalhes do item atualizados",
"ToastItemMarkedAsFinishedFailed": "Falha ao marcar como Concluído", "ToastItemMarkedAsFinishedFailed": "Falha ao marcar como Concluído",
"ToastItemMarkedAsFinishedSuccess": "Item marcado como Concluído", "ToastItemMarkedAsFinishedSuccess": "Item marcado como Concluído",
@ -756,12 +750,10 @@
"ToastLibraryDeleteSuccess": "Biblioteca apagada", "ToastLibraryDeleteSuccess": "Biblioteca apagada",
"ToastLibraryScanFailedToStart": "Falha ao iniciar verificação", "ToastLibraryScanFailedToStart": "Falha ao iniciar verificação",
"ToastLibraryScanStarted": "Verificação da biblioteca iniciada", "ToastLibraryScanStarted": "Verificação da biblioteca iniciada",
"ToastLibraryUpdateFailed": "Falha ao atualizar a biblioteca",
"ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" atualizada", "ToastLibraryUpdateSuccess": "Biblioteca \"{0}\" atualizada",
"ToastPlaylistCreateFailed": "Falha ao criar lista de reprodução", "ToastPlaylistCreateFailed": "Falha ao criar lista de reprodução",
"ToastPlaylistCreateSuccess": "Lista de reprodução criada", "ToastPlaylistCreateSuccess": "Lista de reprodução criada",
"ToastPlaylistRemoveSuccess": "Lista de reprodução removida", "ToastPlaylistRemoveSuccess": "Lista de reprodução removida",
"ToastPlaylistUpdateFailed": "Falha ao atualizar lista de reprodução",
"ToastPlaylistUpdateSuccess": "Lista de reprodução atualizada", "ToastPlaylistUpdateSuccess": "Lista de reprodução atualizada",
"ToastPodcastCreateFailed": "Falha ao criar podcast", "ToastPodcastCreateFailed": "Falha ao criar podcast",
"ToastPodcastCreateSuccess": "Podcast criado", "ToastPodcastCreateSuccess": "Podcast criado",
@ -773,7 +765,6 @@
"ToastSendEbookToDeviceSuccess": "Ebook enviado para o dispositivo \"{0}\"", "ToastSendEbookToDeviceSuccess": "Ebook enviado para o dispositivo \"{0}\"",
"ToastSeriesUpdateFailed": "Falha ao atualizar série", "ToastSeriesUpdateFailed": "Falha ao atualizar série",
"ToastSeriesUpdateSuccess": "Série atualizada", "ToastSeriesUpdateSuccess": "Série atualizada",
"ToastServerSettingsUpdateFailed": "Falha ao atualizar configurações do servidor",
"ToastServerSettingsUpdateSuccess": "Configurações do servidor atualizadas", "ToastServerSettingsUpdateSuccess": "Configurações do servidor atualizadas",
"ToastSessionDeleteFailed": "Falha ao apagar sessão", "ToastSessionDeleteFailed": "Falha ao apagar sessão",
"ToastSessionDeleteSuccess": "Sessão apagada", "ToastSessionDeleteSuccess": "Sessão apagada",
@ -781,7 +772,6 @@
"ToastSocketDisconnected": "Socket desconectado", "ToastSocketDisconnected": "Socket desconectado",
"ToastSocketFailedToConnect": "Falha na conexão do socket", "ToastSocketFailedToConnect": "Falha na conexão do socket",
"ToastSortingPrefixesEmptyError": "É preciso ter pelo menos um prefixo de ordenação", "ToastSortingPrefixesEmptyError": "É preciso ter pelo menos um prefixo de ordenação",
"ToastSortingPrefixesUpdateFailed": "Falha ao atualizar prefixos de ordenação",
"ToastSortingPrefixesUpdateSuccess": "Prefixos de ordenação atualizados ({0} item(ns))", "ToastSortingPrefixesUpdateSuccess": "Prefixos de ordenação atualizados ({0} item(ns))",
"ToastUserDeleteFailed": "Falha ao apagar usuário", "ToastUserDeleteFailed": "Falha ao apagar usuário",
"ToastUserDeleteSuccess": "Usuário apagado" "ToastUserDeleteSuccess": "Usuário apagado"

View file

@ -56,6 +56,7 @@
"ButtonOpenManager": "Открыть менеджер", "ButtonOpenManager": "Открыть менеджер",
"ButtonPause": "Пауза", "ButtonPause": "Пауза",
"ButtonPlay": "Слушать", "ButtonPlay": "Слушать",
"ButtonPlayAll": "Играть все",
"ButtonPlaying": "Проигрывается", "ButtonPlaying": "Проигрывается",
"ButtonPlaylists": "Плейлисты", "ButtonPlaylists": "Плейлисты",
"ButtonPrevious": "Предыдущий", "ButtonPrevious": "Предыдущий",
@ -816,14 +817,12 @@
"StatsTopNarrators": "ТОП ЧТЕЦЫ", "StatsTopNarrators": "ТОП ЧТЕЦЫ",
"StatsTotalDuration": "С общей продолжительностью…", "StatsTotalDuration": "С общей продолжительностью…",
"StatsYearInReview": "ИТОГИ ГОДА", "StatsYearInReview": "ИТОГИ ГОДА",
"ToastAccountUpdateFailed": "Не удалось обновить учетную запись",
"ToastAccountUpdateSuccess": "Учетная запись обновлена", "ToastAccountUpdateSuccess": "Учетная запись обновлена",
"ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise", "ToastAppriseUrlRequired": "Необходимо ввести URL-адрес Apprise",
"ToastAuthorImageRemoveSuccess": "Изображение автора удалено", "ToastAuthorImageRemoveSuccess": "Изображение автора удалено",
"ToastAuthorNotFound": "Автор \"{0}\" не найден", "ToastAuthorNotFound": "Автор \"{0}\" не найден",
"ToastAuthorRemoveSuccess": "Автор удален", "ToastAuthorRemoveSuccess": "Автор удален",
"ToastAuthorSearchNotFound": "Автор не найден", "ToastAuthorSearchNotFound": "Автор не найден",
"ToastAuthorUpdateFailed": "Не удалось обновить автора",
"ToastAuthorUpdateMerged": "Автор объединен", "ToastAuthorUpdateMerged": "Автор объединен",
"ToastAuthorUpdateSuccess": "Автор обновлен", "ToastAuthorUpdateSuccess": "Автор обновлен",
"ToastAuthorUpdateSuccessNoImageFound": "Автор обновлен (изображение не найдено)", "ToastAuthorUpdateSuccessNoImageFound": "Автор обновлен (изображение не найдено)",
@ -834,7 +833,6 @@
"ToastBackupDeleteSuccess": "Бэкап удален", "ToastBackupDeleteSuccess": "Бэкап удален",
"ToastBackupInvalidMaxKeep": "Недопустимое количество резервных копий для хранения", "ToastBackupInvalidMaxKeep": "Недопустимое количество резервных копий для хранения",
"ToastBackupInvalidMaxSize": "Недопустимый максимальный размер резервной копии", "ToastBackupInvalidMaxSize": "Недопустимый максимальный размер резервной копии",
"ToastBackupPathUpdateFailed": "Не удалось обновить путь к резервному копированию",
"ToastBackupRestoreFailed": "Не удалось восстановить из бэкапа", "ToastBackupRestoreFailed": "Не удалось восстановить из бэкапа",
"ToastBackupUploadFailed": "Не удалось загрузить бэкап", "ToastBackupUploadFailed": "Не удалось загрузить бэкап",
"ToastBackupUploadSuccess": "Бэкап загружен", "ToastBackupUploadSuccess": "Бэкап загружен",
@ -845,7 +843,6 @@
"ToastBookmarkCreateFailed": "Не удалось создать закладку", "ToastBookmarkCreateFailed": "Не удалось создать закладку",
"ToastBookmarkCreateSuccess": "Добавлена закладка", "ToastBookmarkCreateSuccess": "Добавлена закладка",
"ToastBookmarkRemoveSuccess": "Закладка удалена", "ToastBookmarkRemoveSuccess": "Закладка удалена",
"ToastBookmarkUpdateFailed": "Не удалось обновить закладку",
"ToastBookmarkUpdateSuccess": "Закладка обновлена", "ToastBookmarkUpdateSuccess": "Закладка обновлена",
"ToastCachePurgeFailed": "Не удалось очистить кэш", "ToastCachePurgeFailed": "Не удалось очистить кэш",
"ToastCachePurgeSuccess": "Кэш успешно очищен", "ToastCachePurgeSuccess": "Кэш успешно очищен",
@ -856,7 +853,6 @@
"ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию", "ToastCollectionItemsAddSuccess": "Элемент(ы) добавлены в коллекцию",
"ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции", "ToastCollectionItemsRemoveSuccess": "Элемент(ы), удалены из коллекции",
"ToastCollectionRemoveSuccess": "Коллекция удалена", "ToastCollectionRemoveSuccess": "Коллекция удалена",
"ToastCollectionUpdateFailed": "Не удалось обновить коллекцию",
"ToastCollectionUpdateSuccess": "Коллекция обновлена", "ToastCollectionUpdateSuccess": "Коллекция обновлена",
"ToastCoverUpdateFailed": "Не удалось обновить обложку", "ToastCoverUpdateFailed": "Не удалось обновить обложку",
"ToastDeleteFileFailed": "Не удалось удалить файл", "ToastDeleteFileFailed": "Не удалось удалить файл",
@ -865,8 +861,6 @@
"ToastDeviceNameAlreadyExists": "Устройство для чтения электронных книг с таким именем уже существует", "ToastDeviceNameAlreadyExists": "Устройство для чтения электронных книг с таким именем уже существует",
"ToastDeviceTestEmailFailed": "Не удалось отправить тестовое электронное письмо", "ToastDeviceTestEmailFailed": "Не удалось отправить тестовое электронное письмо",
"ToastDeviceTestEmailSuccess": "Тестовое письмо отправлено", "ToastDeviceTestEmailSuccess": "Тестовое письмо отправлено",
"ToastDeviceUpdateFailed": "Не удалось обновить устройство",
"ToastEmailSettingsUpdateFailed": "Не удалось обновить настройки электронной почты",
"ToastEmailSettingsUpdateSuccess": "Обновлены настройки электронной почты", "ToastEmailSettingsUpdateSuccess": "Обновлены настройки электронной почты",
"ToastEncodeCancelFailed": "Не удалось отменить кодирование", "ToastEncodeCancelFailed": "Не удалось отменить кодирование",
"ToastEncodeCancelSucces": "Кодирование отменено", "ToastEncodeCancelSucces": "Кодирование отменено",
@ -875,21 +869,16 @@
"ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве", "ToastErrorCannotShare": "Невозможно предоставить общий доступ на этом устройстве",
"ToastFailedToLoadData": "Не удалось загрузить данные", "ToastFailedToLoadData": "Не удалось загрузить данные",
"ToastFailedToShare": "Не удалось поделиться", "ToastFailedToShare": "Не удалось поделиться",
"ToastFailedToUpdateAccount": "Не удалось обновить учетную запись",
"ToastFailedToUpdateUser": "Не удалось обновить пользователя",
"ToastInvalidImageUrl": "Неверный URL изображения", "ToastInvalidImageUrl": "Неверный URL изображения",
"ToastInvalidUrl": "Неверный URL", "ToastInvalidUrl": "Неверный URL",
"ToastItemCoverUpdateFailed": "Не удалось обновить обложку элемента",
"ToastItemCoverUpdateSuccess": "Обложка элемента обновлена", "ToastItemCoverUpdateSuccess": "Обложка элемента обновлена",
"ToastItemDeletedFailed": "Не удалось удалить элемент", "ToastItemDeletedFailed": "Не удалось удалить элемент",
"ToastItemDeletedSuccess": "Удаленный элемент", "ToastItemDeletedSuccess": "Удаленный элемент",
"ToastItemDetailsUpdateFailed": "Не удалось обновить сведения об элементе",
"ToastItemDetailsUpdateSuccess": "Обновлены сведения об элементе", "ToastItemDetailsUpdateSuccess": "Обновлены сведения об элементе",
"ToastItemMarkedAsFinishedFailed": "Не удалось пометить как Завершенный", "ToastItemMarkedAsFinishedFailed": "Не удалось пометить как Завершенный",
"ToastItemMarkedAsFinishedSuccess": "Элемент помечен как Завершенный", "ToastItemMarkedAsFinishedSuccess": "Элемент помечен как Завершенный",
"ToastItemMarkedAsNotFinishedFailed": "Не удалось пометить как Незавершенный", "ToastItemMarkedAsNotFinishedFailed": "Не удалось пометить как Незавершенный",
"ToastItemMarkedAsNotFinishedSuccess": "Элемент помечен как Незавершенный", "ToastItemMarkedAsNotFinishedSuccess": "Элемент помечен как Незавершенный",
"ToastItemUpdateFailed": "Не удалось обновить элемент",
"ToastItemUpdateSuccess": "Элемент обновлен", "ToastItemUpdateSuccess": "Элемент обновлен",
"ToastLibraryCreateFailed": "Не удалось создать библиотеку", "ToastLibraryCreateFailed": "Не удалось создать библиотеку",
"ToastLibraryCreateSuccess": "Библиотека \"{0}\" создана", "ToastLibraryCreateSuccess": "Библиотека \"{0}\" создана",
@ -897,7 +886,6 @@
"ToastLibraryDeleteSuccess": "Библиотека удалена", "ToastLibraryDeleteSuccess": "Библиотека удалена",
"ToastLibraryScanFailedToStart": "Не удалось запустить сканирование", "ToastLibraryScanFailedToStart": "Не удалось запустить сканирование",
"ToastLibraryScanStarted": "Запущено сканирование библиотеки", "ToastLibraryScanStarted": "Запущено сканирование библиотеки",
"ToastLibraryUpdateFailed": "Не удалось обновить библиотеку",
"ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена", "ToastLibraryUpdateSuccess": "Библиотека \"{0}\" обновлена",
"ToastNameEmailRequired": "Имя и адрес электронной почты обязательны", "ToastNameEmailRequired": "Имя и адрес электронной почты обязательны",
"ToastNameRequired": "Имя обязательно для заполнения", "ToastNameRequired": "Имя обязательно для заполнения",
@ -912,16 +900,13 @@
"ToastNotificationDeleteFailed": "Не удалось удалить уведомление", "ToastNotificationDeleteFailed": "Не удалось удалить уведомление",
"ToastNotificationFailedMaximum": "Максимальное количество неудачных попыток должно быть >= 0", "ToastNotificationFailedMaximum": "Максимальное количество неудачных попыток должно быть >= 0",
"ToastNotificationQueueMaximum": "Максимальная очередь уведомлений должна быть >= 0", "ToastNotificationQueueMaximum": "Максимальная очередь уведомлений должна быть >= 0",
"ToastNotificationSettingsUpdateFailed": "Не удалось обновить настройки уведомлений",
"ToastNotificationSettingsUpdateSuccess": "Обновлены настройки уведомлений", "ToastNotificationSettingsUpdateSuccess": "Обновлены настройки уведомлений",
"ToastNotificationTestTriggerFailed": "Не удалось активировать тестовое уведомление", "ToastNotificationTestTriggerFailed": "Не удалось активировать тестовое уведомление",
"ToastNotificationTestTriggerSuccess": "Сработавшее уведомление о тестировании", "ToastNotificationTestTriggerSuccess": "Сработавшее уведомление о тестировании",
"ToastNotificationUpdateFailed": "Не удалось обновить уведомление",
"ToastNotificationUpdateSuccess": "Уведомление обновлено", "ToastNotificationUpdateSuccess": "Уведомление обновлено",
"ToastPlaylistCreateFailed": "Не удалось создать плейлист", "ToastPlaylistCreateFailed": "Не удалось создать плейлист",
"ToastPlaylistCreateSuccess": "Плейлист создан", "ToastPlaylistCreateSuccess": "Плейлист создан",
"ToastPlaylistRemoveSuccess": "Плейлист удален", "ToastPlaylistRemoveSuccess": "Плейлист удален",
"ToastPlaylistUpdateFailed": "Не удалось обновить плейлист",
"ToastPlaylistUpdateSuccess": "Плейлист обновлен", "ToastPlaylistUpdateSuccess": "Плейлист обновлен",
"ToastPodcastCreateFailed": "Не удалось создать подкаст", "ToastPodcastCreateFailed": "Не удалось создать подкаст",
"ToastPodcastCreateSuccess": "Подкаст успешно создан", "ToastPodcastCreateSuccess": "Подкаст успешно создан",
@ -950,7 +935,6 @@
"ToastSendEbookToDeviceSuccess": "E-книга отправлена на устройство \"{0}\"", "ToastSendEbookToDeviceSuccess": "E-книга отправлена на устройство \"{0}\"",
"ToastSeriesUpdateFailed": "Не удалось обновить серию", "ToastSeriesUpdateFailed": "Не удалось обновить серию",
"ToastSeriesUpdateSuccess": "Успешное обновление серии", "ToastSeriesUpdateSuccess": "Успешное обновление серии",
"ToastServerSettingsUpdateFailed": "Не удалось обновить настройки сервера",
"ToastServerSettingsUpdateSuccess": "Обновлены настройки сервера", "ToastServerSettingsUpdateSuccess": "Обновлены настройки сервера",
"ToastSessionCloseFailed": "Не удалось закрыть сеанс", "ToastSessionCloseFailed": "Не удалось закрыть сеанс",
"ToastSessionDeleteFailed": "Не удалось удалить сеанс", "ToastSessionDeleteFailed": "Не удалось удалить сеанс",
@ -961,7 +945,6 @@
"ToastSocketDisconnected": "Сокет отключен", "ToastSocketDisconnected": "Сокет отключен",
"ToastSocketFailedToConnect": "Не удалось подключить сокет", "ToastSocketFailedToConnect": "Не удалось подключить сокет",
"ToastSortingPrefixesEmptyError": "Должен быть хотя бы 1 префикс сортировки", "ToastSortingPrefixesEmptyError": "Должен быть хотя бы 1 префикс сортировки",
"ToastSortingPrefixesUpdateFailed": "Не удалось обновить префиксы сортировки",
"ToastSortingPrefixesUpdateSuccess": "Обновлены префиксы сортировки ({0} элементов)", "ToastSortingPrefixesUpdateSuccess": "Обновлены префиксы сортировки ({0} элементов)",
"ToastTitleRequired": "Название обязательно", "ToastTitleRequired": "Название обязательно",
"ToastUnknownError": "Неизвестная ошибка", "ToastUnknownError": "Неизвестная ошибка",

View file

@ -56,6 +56,7 @@
"ButtonOpenManager": "Odpri upravljanje", "ButtonOpenManager": "Odpri upravljanje",
"ButtonPause": "Premor", "ButtonPause": "Premor",
"ButtonPlay": "Predvajaj", "ButtonPlay": "Predvajaj",
"ButtonPlayAll": "Predvajaj vse",
"ButtonPlaying": "Predvajam", "ButtonPlaying": "Predvajam",
"ButtonPlaylists": "Seznami predvajanj", "ButtonPlaylists": "Seznami predvajanj",
"ButtonPrevious": "Prejšnje", "ButtonPrevious": "Prejšnje",
@ -96,7 +97,7 @@
"ButtonStartM4BEncode": "Zaženi M4B prekodiranje", "ButtonStartM4BEncode": "Zaženi M4B prekodiranje",
"ButtonStartMetadataEmbed": "Začni vdelavo metapodatkov", "ButtonStartMetadataEmbed": "Začni vdelavo metapodatkov",
"ButtonStats": "Statistika", "ButtonStats": "Statistika",
"ButtonSubmit": "Posreduj", "ButtonSubmit": "Potrdi",
"ButtonTest": "Test", "ButtonTest": "Test",
"ButtonUnlinkOpenId": "Prekini povezavo OpenID", "ButtonUnlinkOpenId": "Prekini povezavo OpenID",
"ButtonUpload": "Naloži", "ButtonUpload": "Naloži",
@ -776,6 +777,38 @@
"MessageShareExpiresIn": "Poteče čez {0}", "MessageShareExpiresIn": "Poteče čez {0}",
"MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>", "MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "Začni predvajanje za \"{0}\" ob {1}?", "MessageStartPlaybackAtTime": "Začni predvajanje za \"{0}\" ob {1}?",
"MessageTaskAudioFileNotWritable": "Zvočna datoteka \"{0}\" ni zapisljiva",
"MessageTaskCanceledByUser": "Nalogo je preklical uporabnik",
"MessageTaskDownloadingEpisodeDescription": "Prenašanje epizode \"{0}\"",
"MessageTaskEmbeddingMetadata": "Vdelujem metapodatke",
"MessageTaskEmbeddingMetadataDescription": "Vdelujem metapodatke v zvočno knjigo \"{0}\"",
"MessageTaskEncodingM4b": "Enkodiranje M4B",
"MessageTaskEncodingM4bDescription": "Enkodiranje zvočne knjige \"{0}\" v samo eno datoteko m4b",
"MessageTaskFailed": "Neuspešno",
"MessageTaskFailedToBackupAudioFile": "Varnostno kopiranje zvočne datoteke \"{0}\" ni uspelo",
"MessageTaskFailedToCreateCacheDirectory": "Imenika predpomnilnika ni bilo mogoče ustvariti",
"MessageTaskFailedToEmbedMetadataInFile": "Metapodatkov ni bilo mogoče vdelati v datoteko \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "Zvočnih datotek ni bilo mogoče združiti",
"MessageTaskFailedToMoveM4bFile": "Datoteke m4b ni bilo mogoče premakniti",
"MessageTaskFailedToWriteMetadataFile": "Metapodatke ni bilo mogoče zapisati v datoteke",
"MessageTaskMatchingBooksInLibrary": "Ujemam knjige v knjižnici \"{0}\"",
"MessageTaskNoFilesToScan": "Ni datotek za pregledovanje",
"MessageTaskOpmlImport": "Uvoz OPML",
"MessageTaskOpmlImportDescription": "Ustvarjanje podcastov iz {0} virov RSS",
"MessageTaskOpmlImportFeed": "Vir za uvoz OPML",
"MessageTaskOpmlImportFeedDescription": "Uvažanje vira RSS \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "Vira podcasta ni bilo mogoče pridobiti",
"MessageTaskOpmlImportFeedPodcastDescription": "Ustvarjanje podcasta \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "Podcast že obstaja na tej poti",
"MessageTaskOpmlImportFeedPodcastFailed": "Podcasta ni bilo mogoče ustvariti",
"MessageTaskOpmlImportFinished": "Dodanih {0} podcastov",
"MessageTaskScanItemsAdded": "{0} dodano",
"MessageTaskScanItemsMissing": "{0} manjka",
"MessageTaskScanItemsUpdated": "{0} posodobljeno",
"MessageTaskScanNoChangesNeeded": "Spremembe niso potrebne",
"MessageTaskScanningFileChanges": "Pregledovanje sprememb v datoteki \"{0}\"",
"MessageTaskScanningLibrary": "Pregled knjižnice \"{0}\"",
"MessageTaskTargetDirectoryNotWritable": "Ciljni imenik ni zapisljiv",
"MessageThinking": "Razmišljam...", "MessageThinking": "Razmišljam...",
"MessageUploaderItemFailed": "Nalaganje ni uspelo", "MessageUploaderItemFailed": "Nalaganje ni uspelo",
"MessageUploaderItemSuccess": "Uspešno naloženo!", "MessageUploaderItemSuccess": "Uspešno naloženo!",
@ -816,14 +849,12 @@
"StatsTopNarrators": "TOP BRALCI", "StatsTopNarrators": "TOP BRALCI",
"StatsTotalDuration": "S skupnim trajanjem…", "StatsTotalDuration": "S skupnim trajanjem…",
"StatsYearInReview": "PREGLED LETA", "StatsYearInReview": "PREGLED LETA",
"ToastAccountUpdateFailed": "Računa ni bilo mogoče posodobiti",
"ToastAccountUpdateSuccess": "Račun posodobljen", "ToastAccountUpdateSuccess": "Račun posodobljen",
"ToastAppriseUrlRequired": "Vnesti morate Apprise URL", "ToastAppriseUrlRequired": "Vnesti morate Apprise URL",
"ToastAuthorImageRemoveSuccess": "Slika avtorja je odstranjena", "ToastAuthorImageRemoveSuccess": "Slika avtorja je odstranjena",
"ToastAuthorNotFound": "Avtor \"{0}\" ni bil najden", "ToastAuthorNotFound": "Avtor \"{0}\" ni bil najden",
"ToastAuthorRemoveSuccess": "Avtor odstranjen", "ToastAuthorRemoveSuccess": "Avtor odstranjen",
"ToastAuthorSearchNotFound": "Ne najdem avtorja", "ToastAuthorSearchNotFound": "Ne najdem avtorja",
"ToastAuthorUpdateFailed": "Avtorja ni bilo mogoče posodobiti",
"ToastAuthorUpdateMerged": "Avtor združen", "ToastAuthorUpdateMerged": "Avtor združen",
"ToastAuthorUpdateSuccess": "Avtor posodobljen", "ToastAuthorUpdateSuccess": "Avtor posodobljen",
"ToastAuthorUpdateSuccessNoImageFound": "Avtor posodobljen (ne najdem slike)", "ToastAuthorUpdateSuccessNoImageFound": "Avtor posodobljen (ne najdem slike)",
@ -834,7 +865,6 @@
"ToastBackupDeleteSuccess": "Varnostna kopija izbrisana", "ToastBackupDeleteSuccess": "Varnostna kopija izbrisana",
"ToastBackupInvalidMaxKeep": "Neveljavno število varnostnih kopij za ohranjanje", "ToastBackupInvalidMaxKeep": "Neveljavno število varnostnih kopij za ohranjanje",
"ToastBackupInvalidMaxSize": "Neveljavna največja velikost varnostne kopije", "ToastBackupInvalidMaxSize": "Neveljavna največja velikost varnostne kopije",
"ToastBackupPathUpdateFailed": "Posodobitev poti varnostnih kopij ni uspela",
"ToastBackupRestoreFailed": "Varnostne kopije ni bilo mogoče obnoviti", "ToastBackupRestoreFailed": "Varnostne kopije ni bilo mogoče obnoviti",
"ToastBackupUploadFailed": "Nalaganje varnostne kopije ni uspelo", "ToastBackupUploadFailed": "Nalaganje varnostne kopije ni uspelo",
"ToastBackupUploadSuccess": "Varnostna kopija je naložena", "ToastBackupUploadSuccess": "Varnostna kopija je naložena",
@ -845,7 +875,6 @@
"ToastBookmarkCreateFailed": "Zaznamka ni bilo mogoče ustvariti", "ToastBookmarkCreateFailed": "Zaznamka ni bilo mogoče ustvariti",
"ToastBookmarkCreateSuccess": "Zaznamek dodan", "ToastBookmarkCreateSuccess": "Zaznamek dodan",
"ToastBookmarkRemoveSuccess": "Zaznamek odstranjen", "ToastBookmarkRemoveSuccess": "Zaznamek odstranjen",
"ToastBookmarkUpdateFailed": "Zaznamka ni bilo mogoče posodobiti",
"ToastBookmarkUpdateSuccess": "Zaznamek posodobljen", "ToastBookmarkUpdateSuccess": "Zaznamek posodobljen",
"ToastCachePurgeFailed": "Čiščenje predpomnilnika ni uspelo", "ToastCachePurgeFailed": "Čiščenje predpomnilnika ni uspelo",
"ToastCachePurgeSuccess": "Predpomnilnik je bil uspešno očiščen", "ToastCachePurgeSuccess": "Predpomnilnik je bil uspešno očiščen",
@ -856,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "Dodajanje elementov v zbirko je bilo uspešno", "ToastCollectionItemsAddSuccess": "Dodajanje elementov v zbirko je bilo uspešno",
"ToastCollectionItemsRemoveSuccess": "Elementi so bili odstranjeni iz zbirke", "ToastCollectionItemsRemoveSuccess": "Elementi so bili odstranjeni iz zbirke",
"ToastCollectionRemoveSuccess": "Zbirka je bila odstranjena", "ToastCollectionRemoveSuccess": "Zbirka je bila odstranjena",
"ToastCollectionUpdateFailed": "Zbirke ni bilo mogoče posodobiti",
"ToastCollectionUpdateSuccess": "Zbirka je bila posodobljena", "ToastCollectionUpdateSuccess": "Zbirka je bila posodobljena",
"ToastCoverUpdateFailed": "Posodobitev naslovnice ni uspela", "ToastCoverUpdateFailed": "Posodobitev naslovnice ni uspela",
"ToastDeleteFileFailed": "Brisanje datoteke ni uspelo", "ToastDeleteFileFailed": "Brisanje datoteke ni uspelo",
@ -865,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "Elektronska naprava s tem imenom že obstaja", "ToastDeviceNameAlreadyExists": "Elektronska naprava s tem imenom že obstaja",
"ToastDeviceTestEmailFailed": "Pošiljanje testnega e-poštnega sporočila ni uspelo", "ToastDeviceTestEmailFailed": "Pošiljanje testnega e-poštnega sporočila ni uspelo",
"ToastDeviceTestEmailSuccess": "Testno e-poštno sporočilo je poslano", "ToastDeviceTestEmailSuccess": "Testno e-poštno sporočilo je poslano",
"ToastDeviceUpdateFailed": "Naprave ni bilo mogoče posodobiti",
"ToastEmailSettingsUpdateFailed": "E-poštnih nastavitev ni bilo mogoče posodobiti",
"ToastEmailSettingsUpdateSuccess": "E-poštne nastavitve so bile posodobljene", "ToastEmailSettingsUpdateSuccess": "E-poštne nastavitve so bile posodobljene",
"ToastEncodeCancelFailed": "Napaka pri preklicu prekodiranja", "ToastEncodeCancelFailed": "Napaka pri preklicu prekodiranja",
"ToastEncodeCancelSucces": "Prekodiranje prekinjeno", "ToastEncodeCancelSucces": "Prekodiranje prekinjeno",
@ -875,21 +901,17 @@
"ToastErrorCannotShare": "V tej napravi ni mogoče dati v skupno rabo", "ToastErrorCannotShare": "V tej napravi ni mogoče dati v skupno rabo",
"ToastFailedToLoadData": "Podatkov ni bilo mogoče naložiti", "ToastFailedToLoadData": "Podatkov ni bilo mogoče naložiti",
"ToastFailedToShare": "Skupna raba ni uspela", "ToastFailedToShare": "Skupna raba ni uspela",
"ToastFailedToUpdateAccount": "Računa ni bilo mogoče posodobiti", "ToastFailedToUpdate": "Napaka pri posodobitvi",
"ToastFailedToUpdateUser": "Uporabnika ni bilo mogoče posodobiti",
"ToastInvalidImageUrl": "Neveljaven URL slike", "ToastInvalidImageUrl": "Neveljaven URL slike",
"ToastInvalidUrl": "Neveljaven URL", "ToastInvalidUrl": "Neveljaven URL",
"ToastItemCoverUpdateFailed": "Naslovnice elementa ni bilo mogoče posodobiti",
"ToastItemCoverUpdateSuccess": "Naslovnica elementa je bila posodobljena", "ToastItemCoverUpdateSuccess": "Naslovnica elementa je bila posodobljena",
"ToastItemDeletedFailed": "Elementa ni bilo mogoče izbrisati", "ToastItemDeletedFailed": "Elementa ni bilo mogoče izbrisati",
"ToastItemDeletedSuccess": "Element je bil izbrisan", "ToastItemDeletedSuccess": "Element je bil izbrisan",
"ToastItemDetailsUpdateFailed": "Posodobitev podrobnosti elementa ni uspela",
"ToastItemDetailsUpdateSuccess": "Podrobnosti elementa so bile posodobjene", "ToastItemDetailsUpdateSuccess": "Podrobnosti elementa so bile posodobjene",
"ToastItemMarkedAsFinishedFailed": "Označevanje kot dokončano ni uspelo", "ToastItemMarkedAsFinishedFailed": "Označevanje kot dokončano ni uspelo",
"ToastItemMarkedAsFinishedSuccess": "Element je označen kot dokončan", "ToastItemMarkedAsFinishedSuccess": "Element je označen kot dokončan",
"ToastItemMarkedAsNotFinishedFailed": "Ni bilo mogoče označiti kot nedokončano", "ToastItemMarkedAsNotFinishedFailed": "Ni bilo mogoče označiti kot nedokončano",
"ToastItemMarkedAsNotFinishedSuccess": "Element označen kot nedokončan", "ToastItemMarkedAsNotFinishedSuccess": "Element označen kot nedokončan",
"ToastItemUpdateFailed": "Elementa ni bilo mogoče posodobiti",
"ToastItemUpdateSuccess": "Element je bil posodobljen", "ToastItemUpdateSuccess": "Element je bil posodobljen",
"ToastLibraryCreateFailed": "Knjižnice ni bilo mogoče ustvariti", "ToastLibraryCreateFailed": "Knjižnice ni bilo mogoče ustvariti",
"ToastLibraryCreateSuccess": "Knjižnica \"{0}\" je bila ustvarjena", "ToastLibraryCreateSuccess": "Knjižnica \"{0}\" je bila ustvarjena",
@ -897,7 +919,6 @@
"ToastLibraryDeleteSuccess": "Knjižnica je bila izbrisana", "ToastLibraryDeleteSuccess": "Knjižnica je bila izbrisana",
"ToastLibraryScanFailedToStart": "Pregleda ni bilo mogoče začeti", "ToastLibraryScanFailedToStart": "Pregleda ni bilo mogoče začeti",
"ToastLibraryScanStarted": "Pregled knjižnice se je začel", "ToastLibraryScanStarted": "Pregled knjižnice se je začel",
"ToastLibraryUpdateFailed": "Knjižnice ni bilo mogoče posodobiti",
"ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" je bila posodobljena", "ToastLibraryUpdateSuccess": "Knjižnica \"{0}\" je bila posodobljena",
"ToastNameEmailRequired": "Ime in e-pošta sta obvezna", "ToastNameEmailRequired": "Ime in e-pošta sta obvezna",
"ToastNameRequired": "Ime je obvezno", "ToastNameRequired": "Ime je obvezno",
@ -912,16 +933,13 @@
"ToastNotificationDeleteFailed": "Brisanje obvestila ni uspelo", "ToastNotificationDeleteFailed": "Brisanje obvestila ni uspelo",
"ToastNotificationFailedMaximum": "Največje število neuspelih poskusov mora biti >= 0", "ToastNotificationFailedMaximum": "Največje število neuspelih poskusov mora biti >= 0",
"ToastNotificationQueueMaximum": "Največja čakalna vrsta obvestil mora biti >= 0", "ToastNotificationQueueMaximum": "Največja čakalna vrsta obvestil mora biti >= 0",
"ToastNotificationSettingsUpdateFailed": "Nastavitev obvestil ni bilo mogoče posodobiti",
"ToastNotificationSettingsUpdateSuccess": "Nastavitve obvestil so bile posodobljene", "ToastNotificationSettingsUpdateSuccess": "Nastavitve obvestil so bile posodobljene",
"ToastNotificationTestTriggerFailed": "Sprožitev testnega obvestila ni uspela", "ToastNotificationTestTriggerFailed": "Sprožitev testnega obvestila ni uspela",
"ToastNotificationTestTriggerSuccess": "Sproženo testno obvestilo", "ToastNotificationTestTriggerSuccess": "Sproženo testno obvestilo",
"ToastNotificationUpdateFailed": "Obvestila ni bilo mogoče posodobiti",
"ToastNotificationUpdateSuccess": "Obvestilo posodobljeno", "ToastNotificationUpdateSuccess": "Obvestilo posodobljeno",
"ToastPlaylistCreateFailed": "Seznama predvajanja ni bilo mogoče ustvariti", "ToastPlaylistCreateFailed": "Seznama predvajanja ni bilo mogoče ustvariti",
"ToastPlaylistCreateSuccess": "Seznam predvajanja je bil ustvarjen", "ToastPlaylistCreateSuccess": "Seznam predvajanja je bil ustvarjen",
"ToastPlaylistRemoveSuccess": "Seznam predvajanja odstranjen", "ToastPlaylistRemoveSuccess": "Seznam predvajanja odstranjen",
"ToastPlaylistUpdateFailed": "Seznama predvajanja ni bilo mogoče posodobiti",
"ToastPlaylistUpdateSuccess": "Seznam predvajanja je bil posodobljen", "ToastPlaylistUpdateSuccess": "Seznam predvajanja je bil posodobljen",
"ToastPodcastCreateFailed": "Podcasta ni bilo mogoče ustvariti", "ToastPodcastCreateFailed": "Podcasta ni bilo mogoče ustvariti",
"ToastPodcastCreateSuccess": "Podcast je bil uspešno ustvarjen", "ToastPodcastCreateSuccess": "Podcast je bil uspešno ustvarjen",
@ -950,7 +968,6 @@
"ToastSendEbookToDeviceSuccess": "E-knjiga je bila poslana v napravo \"{0}\"", "ToastSendEbookToDeviceSuccess": "E-knjiga je bila poslana v napravo \"{0}\"",
"ToastSeriesUpdateFailed": "Posodobitev serije ni uspela", "ToastSeriesUpdateFailed": "Posodobitev serije ni uspela",
"ToastSeriesUpdateSuccess": "Uspešna posodobitev serije", "ToastSeriesUpdateSuccess": "Uspešna posodobitev serije",
"ToastServerSettingsUpdateFailed": "Nastavitev strežnika ni bilo mogoče posodobiti",
"ToastServerSettingsUpdateSuccess": "Nastavitve strežnika so bile posodobljene", "ToastServerSettingsUpdateSuccess": "Nastavitve strežnika so bile posodobljene",
"ToastSessionCloseFailed": "Seje ni bilo mogoče zapreti", "ToastSessionCloseFailed": "Seje ni bilo mogoče zapreti",
"ToastSessionDeleteFailed": "Brisanje seje ni uspelo", "ToastSessionDeleteFailed": "Brisanje seje ni uspelo",
@ -961,7 +978,6 @@
"ToastSocketDisconnected": "Omrežna povezava je odklopljena", "ToastSocketDisconnected": "Omrežna povezava je odklopljena",
"ToastSocketFailedToConnect": "Omrežna povezava ni uspela vzpostaviti priklopa", "ToastSocketFailedToConnect": "Omrežna povezava ni uspela vzpostaviti priklopa",
"ToastSortingPrefixesEmptyError": "Imeti mora vsaj 1 predpono za razvrščanje", "ToastSortingPrefixesEmptyError": "Imeti mora vsaj 1 predpono za razvrščanje",
"ToastSortingPrefixesUpdateFailed": "Posodobitev predpon za razvrščanje ni uspela",
"ToastSortingPrefixesUpdateSuccess": "Predpone za razvrščanje so bile posodobljene ({0} elementov)", "ToastSortingPrefixesUpdateSuccess": "Predpone za razvrščanje so bile posodobljene ({0} elementov)",
"ToastTitleRequired": "Naslov je obvezen", "ToastTitleRequired": "Naslov je obvezen",
"ToastUnknownError": "Neznana napaka", "ToastUnknownError": "Neznana napaka",

View file

@ -45,6 +45,7 @@
"ButtonOk": "Okej", "ButtonOk": "Okej",
"ButtonOpenFeed": "Öppna flöde", "ButtonOpenFeed": "Öppna flöde",
"ButtonOpenManager": "Öppna Manager", "ButtonOpenManager": "Öppna Manager",
"ButtonPause": "Pausa",
"ButtonPlay": "Spela", "ButtonPlay": "Spela",
"ButtonPlaying": "Spelar", "ButtonPlaying": "Spelar",
"ButtonPlaylists": "Spellistor", "ButtonPlaylists": "Spellistor",
@ -263,8 +264,10 @@
"LabelFinished": "Avslutad", "LabelFinished": "Avslutad",
"LabelFolder": "Mapp", "LabelFolder": "Mapp",
"LabelFolders": "Mappar", "LabelFolders": "Mappar",
"LabelFontBoldness": "Fetstil",
"LabelFontFamily": "Teckensnittsfamilj", "LabelFontFamily": "Teckensnittsfamilj",
"LabelFontScale": "Teckensnittsskala", "LabelFontScale": "Teckensnittsskala",
"LabelGenre": "Genre",
"LabelGenres": "Genrer", "LabelGenres": "Genrer",
"LabelHardDeleteFile": "Hård radering av fil", "LabelHardDeleteFile": "Hård radering av fil",
"LabelHasEbook": "Har E-bok", "LabelHasEbook": "Har E-bok",
@ -294,6 +297,7 @@
"LabelLastSeen": "Senast sedd", "LabelLastSeen": "Senast sedd",
"LabelLastTime": "Senaste gången", "LabelLastTime": "Senaste gången",
"LabelLastUpdate": "Senaste uppdatering", "LabelLastUpdate": "Senaste uppdatering",
"LabelLayout": "Layout",
"LabelLayoutSinglePage": "En sida", "LabelLayoutSinglePage": "En sida",
"LabelLayoutSplitPage": "Dela sida", "LabelLayoutSplitPage": "Dela sida",
"LabelLess": "Mindre", "LabelLess": "Mindre",
@ -322,8 +326,8 @@
"LabelNarrators": "Berättare", "LabelNarrators": "Berättare",
"LabelNew": "Ny", "LabelNew": "Ny",
"LabelNewPassword": "Nytt lösenord", "LabelNewPassword": "Nytt lösenord",
"LabelNewestAuthors": "Nyaste författare", "LabelNewestAuthors": "Senast tillagda författare",
"LabelNewestEpisodes": "Nyaste avsnitt", "LabelNewestEpisodes": "Senast tillagda avsnitt",
"LabelNextBackupDate": "Nästa säkerhetskopia datum", "LabelNextBackupDate": "Nästa säkerhetskopia datum",
"LabelNextScheduledRun": "Nästa schemalagda körning", "LabelNextScheduledRun": "Nästa schemalagda körning",
"LabelNoEpisodesSelected": "Inga avsnitt valda", "LabelNoEpisodesSelected": "Inga avsnitt valda",
@ -355,8 +359,10 @@
"LabelPhotoPathURL": "Bildsökväg/URL", "LabelPhotoPathURL": "Bildsökväg/URL",
"LabelPlayMethod": "Spelläge", "LabelPlayMethod": "Spelläge",
"LabelPlaylists": "Spellistor", "LabelPlaylists": "Spellistor",
"LabelPodcast": "Podcast",
"LabelPodcastSearchRegion": "Podcast-sökområde", "LabelPodcastSearchRegion": "Podcast-sökområde",
"LabelPodcastType": "Podcasttyp", "LabelPodcastType": "Podcasttyp",
"LabelPodcasts": "Podcasts",
"LabelPrefixesToIgnore": "Prefix att ignorera (skiftlägesokänsligt)", "LabelPrefixesToIgnore": "Prefix att ignorera (skiftlägesokänsligt)",
"LabelPreventIndexing": "Förhindra att ditt flöde indexeras av iTunes och Google-podcastsökmotorer", "LabelPreventIndexing": "Förhindra att ditt flöde indexeras av iTunes och Google-podcastsökmotorer",
"LabelPrimaryEbook": "Primär e-bok", "LabelPrimaryEbook": "Primär e-bok",
@ -371,6 +377,7 @@
"LabelRSSFeedPreventIndexing": "Förhindra indexering", "LabelRSSFeedPreventIndexing": "Förhindra indexering",
"LabelRSSFeedSlug": "RSS-flödesslag", "LabelRSSFeedSlug": "RSS-flödesslag",
"LabelRSSFeedURL": "RSS-flöde URL", "LabelRSSFeedURL": "RSS-flöde URL",
"LabelRandomly": "Slumpartat",
"LabelRead": "Läst", "LabelRead": "Läst",
"LabelReadAgain": "Läs igen", "LabelReadAgain": "Läs igen",
"LabelReadEbookWithoutProgress": "Läs e-bok utan att behålla framsteg", "LabelReadEbookWithoutProgress": "Läs e-bok utan att behålla framsteg",
@ -430,6 +437,7 @@
"LabelShowAll": "Visa alla", "LabelShowAll": "Visa alla",
"LabelSize": "Storlek", "LabelSize": "Storlek",
"LabelSleepTimer": "Sleeptimer", "LabelSleepTimer": "Sleeptimer",
"LabelStart": "Starta",
"LabelStartTime": "Starttid", "LabelStartTime": "Starttid",
"LabelStarted": "Startad", "LabelStarted": "Startad",
"LabelStartedAt": "Startad vid", "LabelStartedAt": "Startad vid",
@ -637,10 +645,8 @@
"PlaceholderNewPlaylist": "Nytt spellistanamn", "PlaceholderNewPlaylist": "Nytt spellistanamn",
"PlaceholderSearch": "Sök...", "PlaceholderSearch": "Sök...",
"PlaceholderSearchEpisode": "Sök avsnitt...", "PlaceholderSearchEpisode": "Sök avsnitt...",
"ToastAccountUpdateFailed": "Det gick inte att uppdatera kontot",
"ToastAccountUpdateSuccess": "Kontot uppdaterat", "ToastAccountUpdateSuccess": "Kontot uppdaterat",
"ToastAuthorImageRemoveSuccess": "Författarens bild borttagen", "ToastAuthorImageRemoveSuccess": "Författarens bild borttagen",
"ToastAuthorUpdateFailed": "Det gick inte att uppdatera författaren",
"ToastAuthorUpdateMerged": "Författaren sammanslagen", "ToastAuthorUpdateMerged": "Författaren sammanslagen",
"ToastAuthorUpdateSuccess": "Författaren uppdaterad", "ToastAuthorUpdateSuccess": "Författaren uppdaterad",
"ToastAuthorUpdateSuccessNoImageFound": "Författaren uppdaterad (ingen bild hittad)", "ToastAuthorUpdateSuccessNoImageFound": "Författaren uppdaterad (ingen bild hittad)",
@ -656,17 +662,13 @@
"ToastBookmarkCreateFailed": "Det gick inte att skapa bokmärket", "ToastBookmarkCreateFailed": "Det gick inte att skapa bokmärket",
"ToastBookmarkCreateSuccess": "Bokmärket tillagt", "ToastBookmarkCreateSuccess": "Bokmärket tillagt",
"ToastBookmarkRemoveSuccess": "Bokmärket borttaget", "ToastBookmarkRemoveSuccess": "Bokmärket borttaget",
"ToastBookmarkUpdateFailed": "Det gick inte att uppdatera bokmärket",
"ToastBookmarkUpdateSuccess": "Bokmärket uppdaterat", "ToastBookmarkUpdateSuccess": "Bokmärket uppdaterat",
"ToastChaptersHaveErrors": "Kapitlen har fel", "ToastChaptersHaveErrors": "Kapitlen har fel",
"ToastChaptersMustHaveTitles": "Kapitel måste ha titlar", "ToastChaptersMustHaveTitles": "Kapitel måste ha titlar",
"ToastCollectionItemsRemoveSuccess": "Objekt borttagna från samlingen", "ToastCollectionItemsRemoveSuccess": "Objekt borttagna från samlingen",
"ToastCollectionRemoveSuccess": "Samlingen borttagen", "ToastCollectionRemoveSuccess": "Samlingen borttagen",
"ToastCollectionUpdateFailed": "Det gick inte att uppdatera samlingen",
"ToastCollectionUpdateSuccess": "Samlingen uppdaterad", "ToastCollectionUpdateSuccess": "Samlingen uppdaterad",
"ToastItemCoverUpdateFailed": "Det gick inte att uppdatera objektets omslag",
"ToastItemCoverUpdateSuccess": "Objektets omslag uppdaterat", "ToastItemCoverUpdateSuccess": "Objektets omslag uppdaterat",
"ToastItemDetailsUpdateFailed": "Det gick inte att uppdatera objektdetaljerna",
"ToastItemDetailsUpdateSuccess": "Objektdetaljer uppdaterade", "ToastItemDetailsUpdateSuccess": "Objektdetaljer uppdaterade",
"ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera som färdig", "ToastItemMarkedAsFinishedFailed": "Misslyckades med att markera som färdig",
"ToastItemMarkedAsFinishedSuccess": "Objekt markerat som färdig", "ToastItemMarkedAsFinishedSuccess": "Objekt markerat som färdig",
@ -678,12 +680,10 @@
"ToastLibraryDeleteSuccess": "Biblioteket borttaget", "ToastLibraryDeleteSuccess": "Biblioteket borttaget",
"ToastLibraryScanFailedToStart": "Misslyckades med att starta skanningen", "ToastLibraryScanFailedToStart": "Misslyckades med att starta skanningen",
"ToastLibraryScanStarted": "Skanning av biblioteket påbörjad", "ToastLibraryScanStarted": "Skanning av biblioteket påbörjad",
"ToastLibraryUpdateFailed": "Det gick inte att uppdatera biblioteket",
"ToastLibraryUpdateSuccess": "Biblioteket \"{0}\" uppdaterat", "ToastLibraryUpdateSuccess": "Biblioteket \"{0}\" uppdaterat",
"ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan", "ToastPlaylistCreateFailed": "Det gick inte att skapa spellistan",
"ToastPlaylistCreateSuccess": "Spellistan skapad", "ToastPlaylistCreateSuccess": "Spellistan skapad",
"ToastPlaylistRemoveSuccess": "Spellistan borttagen", "ToastPlaylistRemoveSuccess": "Spellistan borttagen",
"ToastPlaylistUpdateFailed": "Det gick inte att uppdatera spellistan",
"ToastPlaylistUpdateSuccess": "Spellistan uppdaterad", "ToastPlaylistUpdateSuccess": "Spellistan uppdaterad",
"ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten", "ToastPodcastCreateFailed": "Misslyckades med att skapa podcasten",
"ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt", "ToastPodcastCreateSuccess": "Podcasten skapad framgångsrikt",

View file

@ -785,10 +785,8 @@
"StatsTopNarrators": "УЛЮБЛЕНІ ЧИТЦІ", "StatsTopNarrators": "УЛЮБЛЕНІ ЧИТЦІ",
"StatsTotalDuration": "Загальною довжиною…", "StatsTotalDuration": "Загальною довжиною…",
"StatsYearInReview": "ОГЛЯД РОКУ", "StatsYearInReview": "ОГЛЯД РОКУ",
"ToastAccountUpdateFailed": "Не вдалося оновити профіль",
"ToastAccountUpdateSuccess": "Профіль оновлено", "ToastAccountUpdateSuccess": "Профіль оновлено",
"ToastAuthorImageRemoveSuccess": "Фото автора видалено", "ToastAuthorImageRemoveSuccess": "Фото автора видалено",
"ToastAuthorUpdateFailed": "Не вдалося оновити автора",
"ToastAuthorUpdateMerged": "Автора об'єднано", "ToastAuthorUpdateMerged": "Автора об'єднано",
"ToastAuthorUpdateSuccess": "Автора оновлено", "ToastAuthorUpdateSuccess": "Автора оновлено",
"ToastAuthorUpdateSuccessNoImageFound": "Автора оновлено (фото не знайдено)", "ToastAuthorUpdateSuccessNoImageFound": "Автора оновлено (фото не знайдено)",
@ -804,7 +802,6 @@
"ToastBookmarkCreateFailed": "Не вдалося створити закладку", "ToastBookmarkCreateFailed": "Не вдалося створити закладку",
"ToastBookmarkCreateSuccess": "Закладку додано", "ToastBookmarkCreateSuccess": "Закладку додано",
"ToastBookmarkRemoveSuccess": "Закладку видалено", "ToastBookmarkRemoveSuccess": "Закладку видалено",
"ToastBookmarkUpdateFailed": "Не вдалося оновити закладку",
"ToastBookmarkUpdateSuccess": "Закладку оновлено", "ToastBookmarkUpdateSuccess": "Закладку оновлено",
"ToastCachePurgeFailed": "Не вдалося очистити кеш", "ToastCachePurgeFailed": "Не вдалося очистити кеш",
"ToastCachePurgeSuccess": "Кеш очищено", "ToastCachePurgeSuccess": "Кеш очищено",
@ -812,15 +809,12 @@
"ToastChaptersMustHaveTitles": "Глави повинні мати назви", "ToastChaptersMustHaveTitles": "Глави повинні мати назви",
"ToastCollectionItemsRemoveSuccess": "Елемент(и) видалено з добірки", "ToastCollectionItemsRemoveSuccess": "Елемент(и) видалено з добірки",
"ToastCollectionRemoveSuccess": "Добірку видалено", "ToastCollectionRemoveSuccess": "Добірку видалено",
"ToastCollectionUpdateFailed": "Не вдалося оновити добірку",
"ToastCollectionUpdateSuccess": "Добірку оновлено", "ToastCollectionUpdateSuccess": "Добірку оновлено",
"ToastDeleteFileFailed": "Не вдалося видалити файл", "ToastDeleteFileFailed": "Не вдалося видалити файл",
"ToastDeleteFileSuccess": "Файл видалено", "ToastDeleteFileSuccess": "Файл видалено",
"ToastErrorCannotShare": "Не можна типово поширити на цей пристрій", "ToastErrorCannotShare": "Не можна типово поширити на цей пристрій",
"ToastFailedToLoadData": "Не вдалося завантажити дані", "ToastFailedToLoadData": "Не вдалося завантажити дані",
"ToastItemCoverUpdateFailed": "Не вдалося оновити обкладинку",
"ToastItemCoverUpdateSuccess": "Обкладинку елемента оновлено", "ToastItemCoverUpdateSuccess": "Обкладинку елемента оновлено",
"ToastItemDetailsUpdateFailed": "Не вдалося оновити подробиці елемента",
"ToastItemDetailsUpdateSuccess": "Подробиці про елемент оновлено", "ToastItemDetailsUpdateSuccess": "Подробиці про елемент оновлено",
"ToastItemMarkedAsFinishedFailed": "Не вдалося позначити як завершене", "ToastItemMarkedAsFinishedFailed": "Не вдалося позначити як завершене",
"ToastItemMarkedAsFinishedSuccess": "Елемент позначено як завершений", "ToastItemMarkedAsFinishedSuccess": "Елемент позначено як завершений",
@ -832,12 +826,10 @@
"ToastLibraryDeleteSuccess": "Бібліотеку видалено", "ToastLibraryDeleteSuccess": "Бібліотеку видалено",
"ToastLibraryScanFailedToStart": "Не вдалося розпочати сканування", "ToastLibraryScanFailedToStart": "Не вдалося розпочати сканування",
"ToastLibraryScanStarted": "Почалося сканування бібліотеки", "ToastLibraryScanStarted": "Почалося сканування бібліотеки",
"ToastLibraryUpdateFailed": "Не вдалося оновити бібліотеку",
"ToastLibraryUpdateSuccess": "Бібліотеку \"{0}\" оновлено", "ToastLibraryUpdateSuccess": "Бібліотеку \"{0}\" оновлено",
"ToastPlaylistCreateFailed": "Не вдалося створити список", "ToastPlaylistCreateFailed": "Не вдалося створити список",
"ToastPlaylistCreateSuccess": "Список відтворення створено", "ToastPlaylistCreateSuccess": "Список відтворення створено",
"ToastPlaylistRemoveSuccess": "Список відтворення видалено", "ToastPlaylistRemoveSuccess": "Список відтворення видалено",
"ToastPlaylistUpdateFailed": "Не вдалося оновити список",
"ToastPlaylistUpdateSuccess": "Список відтворення оновлено", "ToastPlaylistUpdateSuccess": "Список відтворення оновлено",
"ToastPodcastCreateFailed": "Не вдалося створити подкаст", "ToastPodcastCreateFailed": "Не вдалося створити подкаст",
"ToastPodcastCreateSuccess": "Подкаст успішно створено", "ToastPodcastCreateSuccess": "Подкаст успішно створено",
@ -849,7 +841,6 @@
"ToastSendEbookToDeviceSuccess": "Електронну книгу надіслано на пристрій \"{0}\"", "ToastSendEbookToDeviceSuccess": "Електронну книгу надіслано на пристрій \"{0}\"",
"ToastSeriesUpdateFailed": "Не вдалося оновити серію", "ToastSeriesUpdateFailed": "Не вдалося оновити серію",
"ToastSeriesUpdateSuccess": "Серію успішно оновлено", "ToastSeriesUpdateSuccess": "Серію успішно оновлено",
"ToastServerSettingsUpdateFailed": "Не вдалося оновити налаштування сервера",
"ToastServerSettingsUpdateSuccess": "Налаштування сервера оновлено", "ToastServerSettingsUpdateSuccess": "Налаштування сервера оновлено",
"ToastSessionDeleteFailed": "Не вдалося видалити сесію", "ToastSessionDeleteFailed": "Не вдалося видалити сесію",
"ToastSessionDeleteSuccess": "Сесію видалено", "ToastSessionDeleteSuccess": "Сесію видалено",
@ -857,7 +848,6 @@
"ToastSocketDisconnected": "Сокет від'єднано", "ToastSocketDisconnected": "Сокет від'єднано",
"ToastSocketFailedToConnect": "Не вдалося під'єднатися до сокета", "ToastSocketFailedToConnect": "Не вдалося під'єднатися до сокета",
"ToastSortingPrefixesEmptyError": "Мусить мати хоча б 1 префікс сортування", "ToastSortingPrefixesEmptyError": "Мусить мати хоча б 1 префікс сортування",
"ToastSortingPrefixesUpdateFailed": "Не вдалося оновити префікси сортування",
"ToastSortingPrefixesUpdateSuccess": "Префікси сортування оновлено ({0})", "ToastSortingPrefixesUpdateSuccess": "Префікси сортування оновлено ({0})",
"ToastUserDeleteFailed": "Не вдалося видалити користувача", "ToastUserDeleteFailed": "Не вдалося видалити користувача",
"ToastUserDeleteSuccess": "Користувача видалено" "ToastUserDeleteSuccess": "Користувача видалено"

View file

@ -663,10 +663,8 @@
"PlaceholderNewPlaylist": "Tên danh sách phát mới", "PlaceholderNewPlaylist": "Tên danh sách phát mới",
"PlaceholderSearch": "Tìm kiếm..", "PlaceholderSearch": "Tìm kiếm..",
"PlaceholderSearchEpisode": "Tìm kiếm tập..", "PlaceholderSearchEpisode": "Tìm kiếm tập..",
"ToastAccountUpdateFailed": "Cập nhật tài khoản thất bại",
"ToastAccountUpdateSuccess": "Tài khoản đã được cập nhật", "ToastAccountUpdateSuccess": "Tài khoản đã được cập nhật",
"ToastAuthorImageRemoveSuccess": "Ảnh tác giả đã được xóa", "ToastAuthorImageRemoveSuccess": "Ảnh tác giả đã được xóa",
"ToastAuthorUpdateFailed": "Cập nhật tác giả thất bại",
"ToastAuthorUpdateMerged": "Tác giả đã được hợp nhất", "ToastAuthorUpdateMerged": "Tác giả đã được hợp nhất",
"ToastAuthorUpdateSuccess": "Cập nhật tác giả thành công", "ToastAuthorUpdateSuccess": "Cập nhật tác giả thành công",
"ToastAuthorUpdateSuccessNoImageFound": "Cập nhật tác giả thành công (không tìm thấy ảnh)", "ToastAuthorUpdateSuccessNoImageFound": "Cập nhật tác giả thành công (không tìm thấy ảnh)",
@ -682,17 +680,13 @@
"ToastBookmarkCreateFailed": "Tạo đánh dấu thất bại", "ToastBookmarkCreateFailed": "Tạo đánh dấu thất bại",
"ToastBookmarkCreateSuccess": "Đã thêm đánh dấu", "ToastBookmarkCreateSuccess": "Đã thêm đánh dấu",
"ToastBookmarkRemoveSuccess": "Đánh dấu đã được xóa", "ToastBookmarkRemoveSuccess": "Đánh dấu đã được xóa",
"ToastBookmarkUpdateFailed": "Cập nhật đánh dấu thất bại",
"ToastBookmarkUpdateSuccess": "Đánh dấu đã được cập nhật", "ToastBookmarkUpdateSuccess": "Đánh dấu đã được cập nhật",
"ToastChaptersHaveErrors": "Các chương có lỗi", "ToastChaptersHaveErrors": "Các chương có lỗi",
"ToastChaptersMustHaveTitles": "Các chương phải có tiêu đề", "ToastChaptersMustHaveTitles": "Các chương phải có tiêu đề",
"ToastCollectionItemsRemoveSuccess": "Mục đã được xóa khỏi bộ sưu tập", "ToastCollectionItemsRemoveSuccess": "Mục đã được xóa khỏi bộ sưu tập",
"ToastCollectionRemoveSuccess": "Bộ sưu tập đã được xóa", "ToastCollectionRemoveSuccess": "Bộ sưu tập đã được xóa",
"ToastCollectionUpdateFailed": "Cập nhật bộ sưu tập thất bại",
"ToastCollectionUpdateSuccess": "Bộ sưu tập đã được cập nhật", "ToastCollectionUpdateSuccess": "Bộ sưu tập đã được cập nhật",
"ToastItemCoverUpdateFailed": "Cập nhật ảnh bìa mục thất bại",
"ToastItemCoverUpdateSuccess": "Ảnh bìa mục đã được cập nhật", "ToastItemCoverUpdateSuccess": "Ảnh bìa mục đã được cập nhật",
"ToastItemDetailsUpdateFailed": "Cập nhật chi tiết mục thất bại",
"ToastItemDetailsUpdateSuccess": "Chi tiết mục đã được cập nhật", "ToastItemDetailsUpdateSuccess": "Chi tiết mục đã được cập nhật",
"ToastItemMarkedAsFinishedFailed": "Đánh dấu mục là Hoàn thành thất bại", "ToastItemMarkedAsFinishedFailed": "Đánh dấu mục là Hoàn thành thất bại",
"ToastItemMarkedAsFinishedSuccess": "Mục đã được đánh dấu là Hoàn thành", "ToastItemMarkedAsFinishedSuccess": "Mục đã được đánh dấu là Hoàn thành",
@ -704,12 +698,10 @@
"ToastLibraryDeleteSuccess": "Thư viện đã được xóa", "ToastLibraryDeleteSuccess": "Thư viện đã được xóa",
"ToastLibraryScanFailedToStart": "Không thể bắt đầu quét thư viện", "ToastLibraryScanFailedToStart": "Không thể bắt đầu quét thư viện",
"ToastLibraryScanStarted": "Quét thư viện đã được bắt đầu", "ToastLibraryScanStarted": "Quét thư viện đã được bắt đầu",
"ToastLibraryUpdateFailed": "Cập nhật thư viện thất bại",
"ToastLibraryUpdateSuccess": "Thư viện \"{0}\" đã được cập nhật", "ToastLibraryUpdateSuccess": "Thư viện \"{0}\" đã được cập nhật",
"ToastPlaylistCreateFailed": "Tạo danh sách phát thất bại", "ToastPlaylistCreateFailed": "Tạo danh sách phát thất bại",
"ToastPlaylistCreateSuccess": "Danh sách phát đã được tạo", "ToastPlaylistCreateSuccess": "Danh sách phát đã được tạo",
"ToastPlaylistRemoveSuccess": "Danh sách phát đã được xóa", "ToastPlaylistRemoveSuccess": "Danh sách phát đã được xóa",
"ToastPlaylistUpdateFailed": "Cập nhật danh sách phát thất bại",
"ToastPlaylistUpdateSuccess": "Danh sách phát đã được cập nhật", "ToastPlaylistUpdateSuccess": "Danh sách phát đã được cập nhật",
"ToastPodcastCreateFailed": "Tạo podcast thất bại", "ToastPodcastCreateFailed": "Tạo podcast thất bại",
"ToastPodcastCreateSuccess": "Podcast đã được tạo thành công", "ToastPodcastCreateSuccess": "Podcast đã được tạo thành công",

View file

@ -1,5 +1,5 @@
{ {
"ButtonAdd": "加", "ButtonAdd": "加",
"ButtonAddChapters": "添加章节", "ButtonAddChapters": "添加章节",
"ButtonAddDevice": "添加设备", "ButtonAddDevice": "添加设备",
"ButtonAddLibrary": "添加库", "ButtonAddLibrary": "添加库",
@ -47,7 +47,7 @@
"ButtonMapChapterTitles": "章节标题结构", "ButtonMapChapterTitles": "章节标题结构",
"ButtonMatchAllAuthors": "匹配所有作者", "ButtonMatchAllAuthors": "匹配所有作者",
"ButtonMatchBooks": "匹配图书", "ButtonMatchBooks": "匹配图书",
"ButtonNevermind": "没有关系", "ButtonNevermind": "取消",
"ButtonNext": "下一个", "ButtonNext": "下一个",
"ButtonNextChapter": "下一章节", "ButtonNextChapter": "下一章节",
"ButtonNextItemInQueue": "队列中的下一个项目", "ButtonNextItemInQueue": "队列中的下一个项目",
@ -56,6 +56,7 @@
"ButtonOpenManager": "打开管理器", "ButtonOpenManager": "打开管理器",
"ButtonPause": "暂停", "ButtonPause": "暂停",
"ButtonPlay": "播放", "ButtonPlay": "播放",
"ButtonPlayAll": "播放",
"ButtonPlaying": "正在播放", "ButtonPlaying": "正在播放",
"ButtonPlaylists": "播放列表", "ButtonPlaylists": "播放列表",
"ButtonPrevious": "上一个", "ButtonPrevious": "上一个",
@ -134,7 +135,7 @@
"HeaderEmailSettings": "邮箱设置", "HeaderEmailSettings": "邮箱设置",
"HeaderEpisodes": "剧集", "HeaderEpisodes": "剧集",
"HeaderEreaderDevices": "Ereader 设备", "HeaderEreaderDevices": "Ereader 设备",
"HeaderEreaderSettings": "Ereader 设置", "HeaderEreaderSettings": "电子阅读器设置",
"HeaderFiles": "文件", "HeaderFiles": "文件",
"HeaderFindChapters": "查找章节", "HeaderFindChapters": "查找章节",
"HeaderIgnoredFiles": "忽略的文件", "HeaderIgnoredFiles": "忽略的文件",
@ -776,6 +777,38 @@
"MessageShareExpiresIn": "到期时间 {0}", "MessageShareExpiresIn": "到期时间 {0}",
"MessageShareURLWillBe": "分享网址是 <strong>{0}</strong>", "MessageShareURLWillBe": "分享网址是 <strong>{0}</strong>",
"MessageStartPlaybackAtTime": "开始播放 \"{0}\" 在 {1}?", "MessageStartPlaybackAtTime": "开始播放 \"{0}\" 在 {1}?",
"MessageTaskAudioFileNotWritable": "音频文件 \"{0}\" 不可写",
"MessageTaskCanceledByUser": "任务已被用户取消",
"MessageTaskDownloadingEpisodeDescription": "正在下载剧集 \"{0}\"",
"MessageTaskEmbeddingMetadata": "嵌入元数据",
"MessageTaskEmbeddingMetadataDescription": "在有声读物 \"{0}\" 中嵌入元数据",
"MessageTaskEncodingM4b": "编码 M4B",
"MessageTaskEncodingM4bDescription": "将有声读物 \"{0}\" 编码为单个 m4b 文件",
"MessageTaskFailed": "失败",
"MessageTaskFailedToBackupAudioFile": "无法备份音频文件 \"{0}\"",
"MessageTaskFailedToCreateCacheDirectory": "无法创建缓存目录",
"MessageTaskFailedToEmbedMetadataInFile": "无法将元数据嵌入文件 \"{0}\"",
"MessageTaskFailedToMergeAudioFiles": "无法合并音频文件",
"MessageTaskFailedToMoveM4bFile": "无法移动 m4b 文件",
"MessageTaskFailedToWriteMetadataFile": "无法写入元数据文件",
"MessageTaskMatchingBooksInLibrary": "在库中匹配图书 \"{0}\"",
"MessageTaskNoFilesToScan": "没有要扫描的文件",
"MessageTaskOpmlImport": "OPML 导入",
"MessageTaskOpmlImportDescription": "通过 {0} RSS 源创建播客",
"MessageTaskOpmlImportFeed": "OPML 导入源",
"MessageTaskOpmlImportFeedDescription": "正在导入 RSS 源 \"{0}\"",
"MessageTaskOpmlImportFeedFailed": "无法获取播客信息",
"MessageTaskOpmlImportFeedPodcastDescription": "正在创建播客 \"{0}\"",
"MessageTaskOpmlImportFeedPodcastExists": "播客已存在于路径中",
"MessageTaskOpmlImportFeedPodcastFailed": "无法创建播客",
"MessageTaskOpmlImportFinished": "已添加 {0} 播客",
"MessageTaskScanItemsAdded": "{0} 已添加",
"MessageTaskScanItemsMissing": "{0} 已缺失",
"MessageTaskScanItemsUpdated": "{0} 已更新",
"MessageTaskScanNoChangesNeeded": "无需改变",
"MessageTaskScanningFileChanges": "正在扫描文件更改 \"{0}\"",
"MessageTaskScanningLibrary": "扫描 \"{0}\" 库",
"MessageTaskTargetDirectoryNotWritable": "目标目录不可写",
"MessageThinking": "正在查找...", "MessageThinking": "正在查找...",
"MessageUploaderItemFailed": "上传失败", "MessageUploaderItemFailed": "上传失败",
"MessageUploaderItemSuccess": "上传成功!", "MessageUploaderItemSuccess": "上传成功!",
@ -816,14 +849,12 @@
"StatsTopNarrators": "最佳叙述者", "StatsTopNarrators": "最佳叙述者",
"StatsTotalDuration": "总时长为…", "StatsTotalDuration": "总时长为…",
"StatsYearInReview": "年度回顾", "StatsYearInReview": "年度回顾",
"ToastAccountUpdateFailed": "账户更新失败",
"ToastAccountUpdateSuccess": "帐户已更新", "ToastAccountUpdateSuccess": "帐户已更新",
"ToastAppriseUrlRequired": "必须输入 Apprise URL", "ToastAppriseUrlRequired": "必须输入 Apprise URL",
"ToastAuthorImageRemoveSuccess": "作者图像已删除", "ToastAuthorImageRemoveSuccess": "作者图像已删除",
"ToastAuthorNotFound": "未找到作者 \"{0}\"", "ToastAuthorNotFound": "未找到作者 \"{0}\"",
"ToastAuthorRemoveSuccess": "作者已删除", "ToastAuthorRemoveSuccess": "作者已删除",
"ToastAuthorSearchNotFound": "未找到作者", "ToastAuthorSearchNotFound": "未找到作者",
"ToastAuthorUpdateFailed": "作者更新失败",
"ToastAuthorUpdateMerged": "作者已合并", "ToastAuthorUpdateMerged": "作者已合并",
"ToastAuthorUpdateSuccess": "作者已更新", "ToastAuthorUpdateSuccess": "作者已更新",
"ToastAuthorUpdateSuccessNoImageFound": "作者已更新 (未找到图像)", "ToastAuthorUpdateSuccessNoImageFound": "作者已更新 (未找到图像)",
@ -834,7 +865,6 @@
"ToastBackupDeleteSuccess": "备份已删除", "ToastBackupDeleteSuccess": "备份已删除",
"ToastBackupInvalidMaxKeep": "要保留的备份数无效", "ToastBackupInvalidMaxKeep": "要保留的备份数无效",
"ToastBackupInvalidMaxSize": "最大备份大小无效", "ToastBackupInvalidMaxSize": "最大备份大小无效",
"ToastBackupPathUpdateFailed": "无法更新备份路径",
"ToastBackupRestoreFailed": "备份还原失败", "ToastBackupRestoreFailed": "备份还原失败",
"ToastBackupUploadFailed": "上传备份失败", "ToastBackupUploadFailed": "上传备份失败",
"ToastBackupUploadSuccess": "备份已上传", "ToastBackupUploadSuccess": "备份已上传",
@ -845,7 +875,6 @@
"ToastBookmarkCreateFailed": "创建书签失败", "ToastBookmarkCreateFailed": "创建书签失败",
"ToastBookmarkCreateSuccess": "书签已添加", "ToastBookmarkCreateSuccess": "书签已添加",
"ToastBookmarkRemoveSuccess": "书签已删除", "ToastBookmarkRemoveSuccess": "书签已删除",
"ToastBookmarkUpdateFailed": "书签更新失败",
"ToastBookmarkUpdateSuccess": "书签已更新", "ToastBookmarkUpdateSuccess": "书签已更新",
"ToastCachePurgeFailed": "清除缓存失败", "ToastCachePurgeFailed": "清除缓存失败",
"ToastCachePurgeSuccess": "缓存清除成功", "ToastCachePurgeSuccess": "缓存清除成功",
@ -856,7 +885,6 @@
"ToastCollectionItemsAddSuccess": "项目添加到收藏夹成功", "ToastCollectionItemsAddSuccess": "项目添加到收藏夹成功",
"ToastCollectionItemsRemoveSuccess": "项目从收藏夹移除", "ToastCollectionItemsRemoveSuccess": "项目从收藏夹移除",
"ToastCollectionRemoveSuccess": "收藏夹已删除", "ToastCollectionRemoveSuccess": "收藏夹已删除",
"ToastCollectionUpdateFailed": "更新收藏夹失败",
"ToastCollectionUpdateSuccess": "收藏夹已更新", "ToastCollectionUpdateSuccess": "收藏夹已更新",
"ToastCoverUpdateFailed": "封面更新失败", "ToastCoverUpdateFailed": "封面更新失败",
"ToastDeleteFileFailed": "删除文件失败", "ToastDeleteFileFailed": "删除文件失败",
@ -865,8 +893,6 @@
"ToastDeviceNameAlreadyExists": "同名的电子阅读器设备已存在", "ToastDeviceNameAlreadyExists": "同名的电子阅读器设备已存在",
"ToastDeviceTestEmailFailed": "无法发送测试电子邮件", "ToastDeviceTestEmailFailed": "无法发送测试电子邮件",
"ToastDeviceTestEmailSuccess": "测试邮件已发送", "ToastDeviceTestEmailSuccess": "测试邮件已发送",
"ToastDeviceUpdateFailed": "无法更新设备",
"ToastEmailSettingsUpdateFailed": "无法更新电子邮件设置",
"ToastEmailSettingsUpdateSuccess": "电子邮件设置已更新", "ToastEmailSettingsUpdateSuccess": "电子邮件设置已更新",
"ToastEncodeCancelFailed": "取消编码失败", "ToastEncodeCancelFailed": "取消编码失败",
"ToastEncodeCancelSucces": "编码已取消", "ToastEncodeCancelSucces": "编码已取消",
@ -875,21 +901,17 @@
"ToastErrorCannotShare": "无法在此设备上本地共享", "ToastErrorCannotShare": "无法在此设备上本地共享",
"ToastFailedToLoadData": "加载数据失败", "ToastFailedToLoadData": "加载数据失败",
"ToastFailedToShare": "分享失败", "ToastFailedToShare": "分享失败",
"ToastFailedToUpdateAccount": "无法更新账户", "ToastFailedToUpdate": "更新失败",
"ToastFailedToUpdateUser": "无法更新用户",
"ToastInvalidImageUrl": "图片网址无效", "ToastInvalidImageUrl": "图片网址无效",
"ToastInvalidUrl": "网址无效", "ToastInvalidUrl": "网址无效",
"ToastItemCoverUpdateFailed": "更新项目封面失败",
"ToastItemCoverUpdateSuccess": "项目封面已更新", "ToastItemCoverUpdateSuccess": "项目封面已更新",
"ToastItemDeletedFailed": "删除项目失败", "ToastItemDeletedFailed": "删除项目失败",
"ToastItemDeletedSuccess": "已删除项目", "ToastItemDeletedSuccess": "已删除项目",
"ToastItemDetailsUpdateFailed": "更新项目详细信息失败",
"ToastItemDetailsUpdateSuccess": "项目详细信息已更新", "ToastItemDetailsUpdateSuccess": "项目详细信息已更新",
"ToastItemMarkedAsFinishedFailed": "无法标记为已听完", "ToastItemMarkedAsFinishedFailed": "无法标记为已听完",
"ToastItemMarkedAsFinishedSuccess": "标记为已听完的项目", "ToastItemMarkedAsFinishedSuccess": "标记为已听完的项目",
"ToastItemMarkedAsNotFinishedFailed": "无法标记为未听完", "ToastItemMarkedAsNotFinishedFailed": "无法标记为未听完",
"ToastItemMarkedAsNotFinishedSuccess": "标记为未听完的项目", "ToastItemMarkedAsNotFinishedSuccess": "标记为未听完的项目",
"ToastItemUpdateFailed": "更新项目失败",
"ToastItemUpdateSuccess": "项目已更新", "ToastItemUpdateSuccess": "项目已更新",
"ToastLibraryCreateFailed": "创建媒体库失败", "ToastLibraryCreateFailed": "创建媒体库失败",
"ToastLibraryCreateSuccess": "媒体库 \"{0}\" 创建成功", "ToastLibraryCreateSuccess": "媒体库 \"{0}\" 创建成功",
@ -897,7 +919,6 @@
"ToastLibraryDeleteSuccess": "媒体库已删除", "ToastLibraryDeleteSuccess": "媒体库已删除",
"ToastLibraryScanFailedToStart": "无法启动扫描", "ToastLibraryScanFailedToStart": "无法启动扫描",
"ToastLibraryScanStarted": "媒体库扫描已启动", "ToastLibraryScanStarted": "媒体库扫描已启动",
"ToastLibraryUpdateFailed": "更新图书库失败",
"ToastLibraryUpdateSuccess": "媒体库 \"{0}\" 已更新", "ToastLibraryUpdateSuccess": "媒体库 \"{0}\" 已更新",
"ToastNameEmailRequired": "姓名和电子邮件为必填项", "ToastNameEmailRequired": "姓名和电子邮件为必填项",
"ToastNameRequired": "姓名为必填项", "ToastNameRequired": "姓名为必填项",
@ -912,16 +933,13 @@
"ToastNotificationDeleteFailed": "删除通知失败", "ToastNotificationDeleteFailed": "删除通知失败",
"ToastNotificationFailedMaximum": "最大失败尝试次数必须 >= 0", "ToastNotificationFailedMaximum": "最大失败尝试次数必须 >= 0",
"ToastNotificationQueueMaximum": "最大通知队列必须 >= 0", "ToastNotificationQueueMaximum": "最大通知队列必须 >= 0",
"ToastNotificationSettingsUpdateFailed": "无法更新通知设置",
"ToastNotificationSettingsUpdateSuccess": "通知设置已更新", "ToastNotificationSettingsUpdateSuccess": "通知设置已更新",
"ToastNotificationTestTriggerFailed": "无法触发测试通知", "ToastNotificationTestTriggerFailed": "无法触发测试通知",
"ToastNotificationTestTriggerSuccess": "触发测试通知", "ToastNotificationTestTriggerSuccess": "触发测试通知",
"ToastNotificationUpdateFailed": "更新通知失败",
"ToastNotificationUpdateSuccess": "通知已更新", "ToastNotificationUpdateSuccess": "通知已更新",
"ToastPlaylistCreateFailed": "创建播放列表失败", "ToastPlaylistCreateFailed": "创建播放列表失败",
"ToastPlaylistCreateSuccess": "已成功创建播放列表", "ToastPlaylistCreateSuccess": "已成功创建播放列表",
"ToastPlaylistRemoveSuccess": "播放列表已删除", "ToastPlaylistRemoveSuccess": "播放列表已删除",
"ToastPlaylistUpdateFailed": "更新播放列表失败",
"ToastPlaylistUpdateSuccess": "播放列表已更新", "ToastPlaylistUpdateSuccess": "播放列表已更新",
"ToastPodcastCreateFailed": "创建播客失败", "ToastPodcastCreateFailed": "创建播客失败",
"ToastPodcastCreateSuccess": "已成功创建播客", "ToastPodcastCreateSuccess": "已成功创建播客",
@ -950,7 +968,6 @@
"ToastSendEbookToDeviceSuccess": "电子书已经发送到设备 \"{0}\"", "ToastSendEbookToDeviceSuccess": "电子书已经发送到设备 \"{0}\"",
"ToastSeriesUpdateFailed": "更新系列失败", "ToastSeriesUpdateFailed": "更新系列失败",
"ToastSeriesUpdateSuccess": "系列已更新", "ToastSeriesUpdateSuccess": "系列已更新",
"ToastServerSettingsUpdateFailed": "无法更新服务器设置",
"ToastServerSettingsUpdateSuccess": "服务器设置已更新", "ToastServerSettingsUpdateSuccess": "服务器设置已更新",
"ToastSessionCloseFailed": "关闭会话失败", "ToastSessionCloseFailed": "关闭会话失败",
"ToastSessionDeleteFailed": "删除会话失败", "ToastSessionDeleteFailed": "删除会话失败",
@ -961,7 +978,6 @@
"ToastSocketDisconnected": "网络已断开", "ToastSocketDisconnected": "网络已断开",
"ToastSocketFailedToConnect": "网络连接失败", "ToastSocketFailedToConnect": "网络连接失败",
"ToastSortingPrefixesEmptyError": "必须至少有 1 个排序前缀", "ToastSortingPrefixesEmptyError": "必须至少有 1 个排序前缀",
"ToastSortingPrefixesUpdateFailed": "无法更新排序前缀",
"ToastSortingPrefixesUpdateSuccess": "排序前缀已更新 ({0} 项)", "ToastSortingPrefixesUpdateSuccess": "排序前缀已更新 ({0} 项)",
"ToastTitleRequired": "标题为必填项", "ToastTitleRequired": "标题为必填项",
"ToastUnknownError": "未知错误", "ToastUnknownError": "未知错误",

View file

@ -9,6 +9,7 @@
"ButtonApply": "應用", "ButtonApply": "應用",
"ButtonApplyChapters": "應用到章節", "ButtonApplyChapters": "應用到章節",
"ButtonAuthors": "作者", "ButtonAuthors": "作者",
"ButtonBack": "返回",
"ButtonBrowseForFolder": "瀏覽資料夾", "ButtonBrowseForFolder": "瀏覽資料夾",
"ButtonCancel": "取消", "ButtonCancel": "取消",
"ButtonCancelEncode": "取消編碼", "ButtonCancelEncode": "取消編碼",
@ -18,6 +19,7 @@
"ButtonChooseFiles": "選擇檔案", "ButtonChooseFiles": "選擇檔案",
"ButtonClearFilter": "清除過濾器", "ButtonClearFilter": "清除過濾器",
"ButtonCloseFeed": "關閉源", "ButtonCloseFeed": "關閉源",
"ButtonCloseSession": "關閉開放會話",
"ButtonCollections": "收藏", "ButtonCollections": "收藏",
"ButtonConfigureScanner": "配置掃描", "ButtonConfigureScanner": "配置掃描",
"ButtonCreate": "創建", "ButtonCreate": "創建",
@ -27,6 +29,7 @@
"ButtonEdit": "編輯", "ButtonEdit": "編輯",
"ButtonEditChapters": "編輯章節", "ButtonEditChapters": "編輯章節",
"ButtonEditPodcast": "編輯播客", "ButtonEditPodcast": "編輯播客",
"ButtonEnable": "啟用",
"ButtonForceReScan": "強制重新掃描", "ButtonForceReScan": "強制重新掃描",
"ButtonFullPath": "完整路徑", "ButtonFullPath": "完整路徑",
"ButtonHide": "隱藏", "ButtonHide": "隱藏",
@ -688,10 +691,8 @@
"PlaceholderNewPlaylist": "輸入播放列表名稱", "PlaceholderNewPlaylist": "輸入播放列表名稱",
"PlaceholderSearch": "查找..", "PlaceholderSearch": "查找..",
"PlaceholderSearchEpisode": "搜尋劇集..", "PlaceholderSearchEpisode": "搜尋劇集..",
"ToastAccountUpdateFailed": "帳號更新失敗",
"ToastAccountUpdateSuccess": "帳號已更新", "ToastAccountUpdateSuccess": "帳號已更新",
"ToastAuthorImageRemoveSuccess": "作者圖像已刪除", "ToastAuthorImageRemoveSuccess": "作者圖像已刪除",
"ToastAuthorUpdateFailed": "作者更新失敗",
"ToastAuthorUpdateMerged": "作者已合併", "ToastAuthorUpdateMerged": "作者已合併",
"ToastAuthorUpdateSuccess": "作者已更新", "ToastAuthorUpdateSuccess": "作者已更新",
"ToastAuthorUpdateSuccessNoImageFound": "作者已更新 (未找到圖像)", "ToastAuthorUpdateSuccessNoImageFound": "作者已更新 (未找到圖像)",
@ -707,17 +708,13 @@
"ToastBookmarkCreateFailed": "創建書籤失敗", "ToastBookmarkCreateFailed": "創建書籤失敗",
"ToastBookmarkCreateSuccess": "書籤已新增", "ToastBookmarkCreateSuccess": "書籤已新增",
"ToastBookmarkRemoveSuccess": "書籤已刪除", "ToastBookmarkRemoveSuccess": "書籤已刪除",
"ToastBookmarkUpdateFailed": "書籤更新失敗",
"ToastBookmarkUpdateSuccess": "書籤已更新", "ToastBookmarkUpdateSuccess": "書籤已更新",
"ToastChaptersHaveErrors": "章節有錯誤", "ToastChaptersHaveErrors": "章節有錯誤",
"ToastChaptersMustHaveTitles": "章節必須有標題", "ToastChaptersMustHaveTitles": "章節必須有標題",
"ToastCollectionItemsRemoveSuccess": "項目從收藏夾移除", "ToastCollectionItemsRemoveSuccess": "項目從收藏夾移除",
"ToastCollectionRemoveSuccess": "收藏夾已刪除", "ToastCollectionRemoveSuccess": "收藏夾已刪除",
"ToastCollectionUpdateFailed": "更新收藏夾失敗",
"ToastCollectionUpdateSuccess": "收藏夾已更新", "ToastCollectionUpdateSuccess": "收藏夾已更新",
"ToastItemCoverUpdateFailed": "更新項目封面失敗",
"ToastItemCoverUpdateSuccess": "項目封面已更新", "ToastItemCoverUpdateSuccess": "項目封面已更新",
"ToastItemDetailsUpdateFailed": "更新項目詳細信息失敗",
"ToastItemDetailsUpdateSuccess": "項目詳細信息已更新", "ToastItemDetailsUpdateSuccess": "項目詳細信息已更新",
"ToastItemMarkedAsFinishedFailed": "標記為聽完失敗", "ToastItemMarkedAsFinishedFailed": "標記為聽完失敗",
"ToastItemMarkedAsFinishedSuccess": "標記為聽完的項目", "ToastItemMarkedAsFinishedSuccess": "標記為聽完的項目",
@ -729,12 +726,10 @@
"ToastLibraryDeleteSuccess": "媒體庫已刪除", "ToastLibraryDeleteSuccess": "媒體庫已刪除",
"ToastLibraryScanFailedToStart": "無法啟動掃描", "ToastLibraryScanFailedToStart": "無法啟動掃描",
"ToastLibraryScanStarted": "媒體庫掃描已啟動", "ToastLibraryScanStarted": "媒體庫掃描已啟動",
"ToastLibraryUpdateFailed": "更新圖書庫失敗",
"ToastLibraryUpdateSuccess": "媒體庫 \"{0}\" 已更新", "ToastLibraryUpdateSuccess": "媒體庫 \"{0}\" 已更新",
"ToastPlaylistCreateFailed": "創建播放列表失敗", "ToastPlaylistCreateFailed": "創建播放列表失敗",
"ToastPlaylistCreateSuccess": "已成功創建播放列表", "ToastPlaylistCreateSuccess": "已成功創建播放列表",
"ToastPlaylistRemoveSuccess": "播放列表已刪除", "ToastPlaylistRemoveSuccess": "播放列表已刪除",
"ToastPlaylistUpdateFailed": "更新播放列表失敗",
"ToastPlaylistUpdateSuccess": "播放列表已更新", "ToastPlaylistUpdateSuccess": "播放列表已更新",
"ToastPodcastCreateFailed": "創建播客失敗", "ToastPodcastCreateFailed": "創建播客失敗",
"ToastPodcastCreateSuccess": "已成功創建播客", "ToastPodcastCreateSuccess": "已成功創建播客",

View file

@ -9,6 +9,7 @@ if (isDev) {
if (devEnv.MetadataPath) process.env.METADATA_PATH = devEnv.MetadataPath if (devEnv.MetadataPath) process.env.METADATA_PATH = devEnv.MetadataPath
if (devEnv.FFmpegPath) process.env.FFMPEG_PATH = devEnv.FFmpegPath if (devEnv.FFmpegPath) process.env.FFMPEG_PATH = devEnv.FFmpegPath
if (devEnv.FFProbePath) process.env.FFPROBE_PATH = devEnv.FFProbePath if (devEnv.FFProbePath) process.env.FFPROBE_PATH = devEnv.FFProbePath
if (devEnv.NunicodePath) process.env.NUSQLITE3_PATH = devEnv.NunicodePath
if (devEnv.SkipBinariesCheck) process.env.SKIP_BINARIES_CHECK = '1' if (devEnv.SkipBinariesCheck) process.env.SKIP_BINARIES_CHECK = '1'
if (devEnv.BackupPath) process.env.BACKUP_PATH = devEnv.BackupPath if (devEnv.BackupPath) process.env.BACKUP_PATH = devEnv.BackupPath
process.env.SOURCE = 'local' process.env.SOURCE = 'local'

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.13.4", "version": "2.14.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "audiobookshelf", "name": "audiobookshelf",
"version": "2.13.4", "version": "2.14.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.13.4", "version": "2.14.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",

View file

@ -28,6 +28,9 @@ class Database {
this.notificationSettings = null this.notificationSettings = null
/** @type {import('./objects/settings/EmailSettings')} */ /** @type {import('./objects/settings/EmailSettings')} */
this.emailSettings = null this.emailSettings = null
this.supportsUnaccent = false
this.supportsUnicodeFoldings = false
} }
get models() { get models() {
@ -223,6 +226,12 @@ class Database {
try { try {
await this.sequelize.authenticate() await this.sequelize.authenticate()
if (process.env.NUSQLITE3_PATH) {
await this.loadExtension(process.env.NUSQLITE3_PATH)
Logger.info(`[Database] Db supports unaccent and unicode foldings`)
this.supportsUnaccent = true
this.supportsUnicodeFoldings = true
}
Logger.info(`[Database] Db connection was successful`) Logger.info(`[Database] Db connection was successful`)
return true return true
} catch (error) { } catch (error) {
@ -232,10 +241,9 @@ class Database {
} }
/** /**
* TODO: Temporarily disabled * @param {string} extension paths to extension binary
* @param {string[]} extensions paths to extension binaries
*/ */
async loadExtensions(extensions) { async loadExtension(extension) {
// This is a hack to get the db connection for loading extensions. // This is a hack to get the db connection for loading extensions.
// The proper way would be to use the 'afterConnect' hook, but that hook is never called for sqlite due to a bug in sequelize. // The proper way would be to use the 'afterConnect' hook, but that hook is never called for sqlite due to a bug in sequelize.
// See https://github.com/sequelize/sequelize/issues/12487 // See https://github.com/sequelize/sequelize/issues/12487
@ -243,20 +251,18 @@ class Database {
const db = await this.sequelize.dialect.connectionManager.getConnection() const db = await this.sequelize.dialect.connectionManager.getConnection()
if (typeof db?.loadExtension !== 'function') throw new Error('Failed to get db connection for loading extensions') if (typeof db?.loadExtension !== 'function') throw new Error('Failed to get db connection for loading extensions')
for (const ext of extensions) { Logger.info(`[Database] Loading extension ${extension}`)
Logger.info(`[Database] Loading extension ${ext}`) await new Promise((resolve, reject) => {
await new Promise((resolve, reject) => { db.loadExtension(extension, (err) => {
db.loadExtension(ext, (err) => { if (err) {
if (err) { Logger.error(`[Database] Failed to load extension ${extension}`, err)
Logger.error(`[Database] Failed to load extension ${ext}`, err) reject(err)
reject(err) return
return }
} Logger.info(`[Database] Successfully loaded extension ${extension}`)
Logger.info(`[Database] Successfully loaded extension ${ext}`) resolve()
resolve()
})
}) })
} })
} }
/** /**
@ -601,6 +607,11 @@ class Database {
this.libraryFilterData[libraryId].publishers.push(publisher) this.libraryFilterData[libraryId].publishers.push(publisher)
} }
addPublishedDecadeToFilterData(libraryId, decade) {
if (!this.libraryFilterData[libraryId] || !decade || this.libraryFilterData[libraryId].publishedDecades.includes(decade)) return
this.libraryFilterData[libraryId].publishedDecades.push(decade)
}
addLanguageToFilterData(libraryId, language) { addLanguageToFilterData(libraryId, language) {
if (!this.libraryFilterData[libraryId] || !language || this.libraryFilterData[libraryId].languages.includes(language)) return if (!this.libraryFilterData[libraryId] || !language || this.libraryFilterData[libraryId].languages.includes(language)) return
this.libraryFilterData[libraryId].languages.push(language) this.libraryFilterData[libraryId].languages.push(language)
@ -745,37 +756,57 @@ class Database {
} }
} }
/** async createTextSearchQuery(query) {
* TODO: Temporarily unused const textQuery = new this.TextSearchQuery(this.sequelize, this.supportsUnaccent, query)
* @param {string} value await textQuery.init()
* @returns {string} return textQuery
*/
normalize(value) {
return `lower(unaccent(${value}))`
} }
/** TextSearchQuery = class {
* TODO: Temporarily unused constructor(sequelize, supportsUnaccent, query) {
* @param {string} query this.sequelize = sequelize
* @returns {Promise<string>} this.supportsUnaccent = supportsUnaccent
*/ this.query = query
async getNormalizedQuery(query) { this.hasAccents = false
const escapedQuery = this.sequelize.escape(query) }
const normalizedQuery = this.normalize(escapedQuery)
const normalizedQueryResult = await this.sequelize.query(`SELECT ${normalizedQuery} as normalized_query`)
return normalizedQueryResult[0][0].normalized_query
}
/** /**
* * Returns a normalized (accents-removed) expression for the specified value.
* @param {string} column *
* @param {string} normalizedQuery * @param {string} value
* @returns {string} * @returns {string}
*/ */
matchExpression(column, normalizedQuery) { normalize(value) {
const normalizedPattern = this.sequelize.escape(`%${normalizedQuery}%`) return `unaccent(${value})`
const normalizedColumn = column }
return `${normalizedColumn} LIKE ${normalizedPattern}`
/**
* Initialize the text query.
*
*/
async init() {
if (!this.supportsUnaccent) return
const escapedQuery = this.sequelize.escape(this.query)
const normalizedQueryExpression = this.normalize(escapedQuery)
const normalizedQueryResult = await this.sequelize.query(`SELECT ${normalizedQueryExpression} as normalized_query`)
const normalizedQuery = normalizedQueryResult[0][0].normalized_query
this.hasAccents = escapedQuery !== this.sequelize.escape(normalizedQuery)
}
/**
* Get match expression for the specified column.
* If the query contains accents, match against the column as-is (case-insensitive exact match).
* otherwise match against a normalized column (case-insensitive match with accents removed).
*
* @param {string} column
* @returns {string}
*/
matchExpression(column) {
const pattern = this.sequelize.escape(`%${this.query}%`)
if (!this.supportsUnaccent) return `${column} LIKE ${pattern}`
const normalizedColumn = this.hasAccents ? column : this.normalize(column)
return `${normalizedColumn} LIKE ${pattern}`
}
} }
} }

View file

@ -23,7 +23,6 @@ const HlsRouter = require('./routers/HlsRouter')
const PublicRouter = require('./routers/PublicRouter') const PublicRouter = require('./routers/PublicRouter')
const LogManager = require('./managers/LogManager') const LogManager = require('./managers/LogManager')
const NotificationManager = require('./managers/NotificationManager')
const EmailManager = require('./managers/EmailManager') const EmailManager = require('./managers/EmailManager')
const AbMergeManager = require('./managers/AbMergeManager') const AbMergeManager = require('./managers/AbMergeManager')
const CacheManager = require('./managers/CacheManager') const CacheManager = require('./managers/CacheManager')
@ -67,12 +66,11 @@ class Server {
this.auth = new Auth() this.auth = new Auth()
// Managers // Managers
this.notificationManager = new NotificationManager()
this.emailManager = new EmailManager() this.emailManager = new EmailManager()
this.backupManager = new BackupManager(this.notificationManager) this.backupManager = new BackupManager()
this.abMergeManager = new AbMergeManager() this.abMergeManager = new AbMergeManager()
this.playbackSessionManager = new PlaybackSessionManager() this.playbackSessionManager = new PlaybackSessionManager()
this.podcastManager = new PodcastManager(this.watcher, this.notificationManager) this.podcastManager = new PodcastManager(this.watcher)
this.audioMetadataManager = new AudioMetadataMangaer() this.audioMetadataManager = new AudioMetadataMangaer()
this.rssFeedManager = new RssFeedManager() this.rssFeedManager = new RssFeedManager()
this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager) this.cronManager = new CronManager(this.podcastManager, this.playbackSessionManager)

View file

@ -301,7 +301,12 @@ class FolderWatcher extends EventEmitter {
libraryId, libraryId,
libraryName: libwatcher.name libraryName: libwatcher.name
} }
this.pendingTask = TaskManager.createAndAddTask('watcher-scan', `Scanning file changes in "${libwatcher.name}"`, null, true, taskData) const taskTitleString = {
text: `Scanning file changes in "${libwatcher.name}"`,
key: 'MessageTaskScanningFileChanges',
subs: [libwatcher.name]
}
this.pendingTask = TaskManager.createAndAddTask('watcher-scan', taskTitleString, null, true, taskData)
} }
this.pendingFileUpdates.push({ this.pendingFileUpdates.push({
path, path,
@ -330,7 +335,11 @@ class FolderWatcher extends EventEmitter {
if (this.pendingFileUpdates.length) { if (this.pendingFileUpdates.length) {
LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask) LibraryScanner.scanFilesChanged(this.pendingFileUpdates, this.pendingTask)
} else { } else {
this.pendingTask.setFinished('Scan abandoned. No files to scan.') const taskFinishedString = {
text: 'No files to scan',
key: 'MessageTaskNoFilesToScan'
}
this.pendingTask.setFinished(taskFinishedString)
TaskManager.taskFinished(this.pendingTask) TaskManager.taskFinished(this.pendingTask)
} }
this.pendingTask = null this.pendingTask = null

View file

@ -9,7 +9,6 @@ const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilter
const libraryItemFilters = require('../utils/queries/libraryItemFilters') const libraryItemFilters = require('../utils/queries/libraryItemFilters')
const seriesFilters = require('../utils/queries/seriesFilters') const seriesFilters = require('../utils/queries/seriesFilters')
const fileUtils = require('../utils/fileUtils') const fileUtils = require('../utils/fileUtils')
const { asciiOnlyToLowerCase } = require('../utils/index')
const { createNewSortInstance } = require('../libs/fastSort') const { createNewSortInstance } = require('../libs/fastSort')
const naturalSort = createNewSortInstance({ const naturalSort = createNewSortInstance({
comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare comparer: new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }).compare
@ -493,8 +492,8 @@ class LibraryController {
const payload = { const payload = {
results: [], results: [],
total: undefined, total: undefined,
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, limit: req.query.limit,
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0, page: req.query.page,
sortBy: req.query.sort, sortBy: req.query.sort,
sortDesc: req.query.desc === '1', sortDesc: req.query.desc === '1',
filterBy: req.query.filter, filterBy: req.query.filter,
@ -503,6 +502,7 @@ class LibraryController {
collapseseries: req.query.collapseseries === '1', collapseseries: req.query.collapseseries === '1',
include: include.join(',') include: include.join(',')
} }
payload.offset = payload.page * payload.limit payload.offset = payload.page * payload.limit
// TODO: Temporary way of handling collapse sub-series. Either remove feature or handle through sql queries // TODO: Temporary way of handling collapse sub-series. Either remove feature or handle through sql queries
@ -594,8 +594,8 @@ class LibraryController {
const payload = { const payload = {
results: [], results: [],
total: 0, total: 0,
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, limit: req.query.limit,
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0, page: req.query.page,
sortBy: req.query.sort, sortBy: req.query.sort,
sortDesc: req.query.desc === '1', sortDesc: req.query.desc === '1',
filterBy: req.query.filter, filterBy: req.query.filter,
@ -666,8 +666,8 @@ class LibraryController {
const payload = { const payload = {
results: [], results: [],
total: 0, total: 0,
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, limit: req.query.limit,
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0, page: req.query.page,
sortBy: req.query.sort, sortBy: req.query.sort,
sortDesc: req.query.desc === '1', sortDesc: req.query.desc === '1',
filterBy: req.query.filter, filterBy: req.query.filter,
@ -702,8 +702,8 @@ class LibraryController {
const payload = { const payload = {
results: [], results: [],
total: playlistsForUser.length, total: playlistsForUser.length,
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, limit: req.query.limit,
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0 page: req.query.page
} }
if (payload.limit) { if (payload.limit) {
@ -734,7 +734,7 @@ class LibraryController {
* @param {Response} res * @param {Response} res
*/ */
async getUserPersonalizedShelves(req, res) { async getUserPersonalizedShelves(req, res) {
const limitPerShelf = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) || 10 : 10 const limitPerShelf = req.query.limit || 10
const include = (req.query.include || '') const include = (req.query.include || '')
.split(',') .split(',')
.map((v) => v.trim().toLowerCase()) .map((v) => v.trim().toLowerCase())
@ -807,8 +807,8 @@ class LibraryController {
return res.status(400).send('Invalid request. Query param "q" must be a string') return res.status(400).send('Invalid request. Query param "q" must be a string')
} }
const limit = req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 12 const limit = req.query.limit || 12
const query = asciiOnlyToLowerCase(req.query.q.trim()) const query = req.query.q.trim()
const matches = await libraryItemFilters.search(req.user, req.library, query, limit) const matches = await libraryItemFilters.search(req.user, req.library, query, limit)
res.json(matches) res.json(matches)
@ -865,8 +865,40 @@ class LibraryController {
* @param {Response} res * @param {Response} res
*/ */
async getAuthors(req, res) { async getAuthors(req, res) {
const isPaginated = req.query.limit && !isNaN(req.query.limit) && !isNaN(req.query.page)
const payload = {
results: [],
total: 0,
limit: isPaginated ? Number(req.query.limit) : 0,
page: isPaginated ? Number(req.query.page) : 0,
sortBy: req.query.sort,
sortDesc: req.query.desc === '1',
filterBy: req.query.filter,
minified: req.query.minified === '1',
include: req.query.include
}
// create order, limit and offset for pagination
let offset = isPaginated ? payload.page * payload.limit : undefined
let limit = isPaginated ? payload.limit : undefined
let order = undefined
const direction = payload.sortDesc ? 'DESC' : 'ASC'
if (payload.sortBy === 'name') {
order = [[Sequelize.literal('name COLLATE NOCASE'), direction]]
} else if (payload.sortBy === 'lastFirst') {
order = [[Sequelize.literal('lastFirst COLLATE NOCASE'), direction]]
} else if (payload.sortBy === 'addedAt') {
order = [['createdAt', direction]]
} else if (payload.sortBy === 'updatedAt') {
order = [['updatedAt', direction]]
} else if (payload.sortBy === 'numBooks') {
offset = undefined
limit = undefined
}
const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user) const { bookWhere, replacements } = libraryItemsBookFilters.getUserPermissionBookWhereQuery(req.user)
const authors = await Database.authorModel.findAll({ const { rows: authors, count } = await Database.authorModel.findAndCountAll({
where: { where: {
libraryId: req.library.id libraryId: req.library.id
}, },
@ -880,10 +912,13 @@ class LibraryController {
attributes: [] attributes: []
} }
}, },
order: [[Sequelize.literal('name COLLATE NOCASE'), 'ASC']] order: order,
limit: limit,
offset: offset,
distinct: true
}) })
const oldAuthors = [] let oldAuthors = []
for (const author of authors) { for (const author of authors) {
const oldAuthor = author.toOldJSONExpanded(author.books.length) const oldAuthor = author.toOldJSONExpanded(author.books.length)
@ -891,9 +926,25 @@ class LibraryController {
oldAuthors.push(oldAuthor) oldAuthors.push(oldAuthor)
} }
res.json({ // numBooks sort is handled post-query
authors: oldAuthors if (payload.sortBy === 'numBooks') {
}) oldAuthors.sort((a, b) => (payload.sortDesc ? b.numBooks - a.numBooks : a.numBooks - b.numBooks))
if (isPaginated) {
const startIndex = payload.page * payload.limit
const endIndex = startIndex + payload.limit
oldAuthors = oldAuthors.slice(startIndex, endIndex)
}
}
payload.results = oldAuthors
if (isPaginated) {
payload.total = count
res.json(payload)
} else {
res.json({
authors: payload.results
})
}
} }
/** /**
@ -1088,8 +1139,8 @@ class LibraryController {
const payload = { const payload = {
episodes: [], episodes: [],
limit: req.query.limit && !isNaN(req.query.limit) ? Number(req.query.limit) : 0, limit: req.query.limit,
page: req.query.page && !isNaN(req.query.page) ? Number(req.query.page) : 0 page: req.query.page
} }
const offset = payload.page * payload.limit const offset = payload.page * payload.limit
@ -1192,6 +1243,17 @@ class LibraryController {
return res.status(404).send('Library not found') return res.status(404).send('Library not found')
} }
req.library = library req.library = library
// Ensure pagination query params are positive integers
for (const queryKey of ['limit', 'page']) {
if (req.query[queryKey] !== undefined) {
req.query[queryKey] = !isNaN(req.query[queryKey]) ? Number(req.query[queryKey]) : 0
if (!Number.isInteger(req.query[queryKey]) || req.query[queryKey] < 0) {
return res.status(400).send(`Invalid request. ${queryKey} must be a positive integer`)
}
}
}
next() next()
} }
} }

View file

@ -480,7 +480,7 @@ class LibraryItemController {
const libraryId = itemsToDelete[0].libraryId const libraryId = itemsToDelete[0].libraryId
for (const libraryItem of itemsToDelete) { for (const libraryItem of itemsToDelete) {
const libraryItemPath = libraryItem.path const libraryItemPath = libraryItem.path
Logger.info(`[LibraryItemController] Deleting Library Item "${libraryItem.media.metadata.title}"`) Logger.info(`[LibraryItemController] (${hardDelete ? 'Hard' : 'Soft'}) deleting Library Item "${libraryItem.media.metadata.title}" with id "${libraryItem.id}"`)
const mediaItemIds = libraryItem.mediaType === 'podcast' ? libraryItem.media.episodes.map((ep) => ep.id) : [libraryItem.media.id] const mediaItemIds = libraryItem.mediaType === 'podcast' ? libraryItem.media.episodes.map((ep) => ep.id) : [libraryItem.media.id]
await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds) await this.handleDeleteLibraryItem(libraryItem.mediaType, libraryItem.id, mediaItemIds)
if (hardDelete) { if (hardDelete) {

View file

@ -1,6 +1,7 @@
const { Request, Response, NextFunction } = require('express') const { Request, Response, NextFunction } = require('express')
const Database = require('../Database') const Database = require('../Database')
const { version } = require('../../package.json') const { version } = require('../../package.json')
const NotificationManager = require('../managers/NotificationManager')
/** /**
* @typedef RequestUserObject * @typedef RequestUserObject
@ -23,7 +24,7 @@ class NotificationController {
*/ */
get(req, res) { get(req, res) {
res.json({ res.json({
data: this.notificationManager.getData(), data: NotificationManager.getData(),
settings: Database.notificationSettings settings: Database.notificationSettings
}) })
} }
@ -52,7 +53,7 @@ class NotificationController {
* @param {Response} res * @param {Response} res
*/ */
getData(req, res) { getData(req, res) {
res.json(this.notificationManager.getData()) res.json(NotificationManager.getData())
} }
/** /**
@ -64,7 +65,7 @@ class NotificationController {
* @param {Response} res * @param {Response} res
*/ */
async fireTestEvent(req, res) { async fireTestEvent(req, res) {
await this.notificationManager.triggerNotification('onTest', { version: `v${version}` }, req.query.fail === '1') await NotificationManager.triggerNotification('onTest', { version: `v${version}` }, req.query.fail === '1')
res.sendStatus(200) res.sendStatus(200)
} }
@ -121,7 +122,7 @@ class NotificationController {
async sendNotificationTest(req, res) { async sendNotificationTest(req, res) {
if (!Database.notificationSettings.isUseable) return res.status(400).send('Apprise is not configured') if (!Database.notificationSettings.isUseable) return res.status(400).send('Apprise is not configured')
const success = await this.notificationManager.sendTestNotification(req.notification) const success = await NotificationManager.sendTestNotification(req.notification)
if (success) res.sendStatus(200) if (success) res.sendStatus(200)
else res.sendStatus(500) else res.sendStatus(500)
} }

View file

@ -40,7 +40,11 @@ class AbMergeManager {
* @returns {Promise<void>} * @returns {Promise<void>}
*/ */
cancelEncode(task) { cancelEncode(task) {
task.setFailed('Task canceled by user') const taskFailedString = {
text: 'Task canceled by user',
key: 'MessageTaskCanceledByUser'
}
task.setFailed(taskFailedString)
return this.removeTask(task, true) return this.removeTask(task, true)
} }
@ -76,8 +80,17 @@ class AbMergeManager {
duration: libraryItem.media.duration, duration: libraryItem.media.duration,
encodeOptions: options encodeOptions: options
} }
const taskDescription = `Encoding audiobook "${libraryItem.media.metadata.title}" into a single m4b file.`
task.setData('encode-m4b', 'Encoding M4b', taskDescription, false, taskData) const taskTitleString = {
text: 'Encoding M4b',
key: 'MessageTaskEncodingM4b'
}
const taskDescriptionString = {
text: `Encoding audiobook "${libraryItem.media.metadata.title}" into a single m4b file.`,
key: 'MessageTaskEncodingM4bDescription',
subs: [libraryItem.media.metadata.title]
}
task.setData('encode-m4b', taskTitleString, taskDescriptionString, false, taskData)
TaskManager.addTask(task) TaskManager.addTask(task)
Logger.info(`Start m4b encode for ${libraryItem.id} - TaskId: ${task.id}`) Logger.info(`Start m4b encode for ${libraryItem.id} - TaskId: ${task.id}`)
@ -98,7 +111,11 @@ class AbMergeManager {
// Make sure the target directory is writable // Make sure the target directory is writable
if (!(await isWritable(task.data.libraryItemDir))) { if (!(await isWritable(task.data.libraryItemDir))) {
Logger.error(`[AbMergeManager] Target directory is not writable: ${task.data.libraryItemDir}`) Logger.error(`[AbMergeManager] Target directory is not writable: ${task.data.libraryItemDir}`)
task.setFailed('Target directory is not writable') const taskFailedString = {
text: 'Target directory is not writable',
key: 'MessageTaskTargetDirectoryNotWritable'
}
task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)
return return
} }
@ -106,7 +123,11 @@ class AbMergeManager {
// Create ffmetadata file // Create ffmetadata file
if (!(await ffmpegHelpers.writeFFMetadataFile(task.data.ffmetadataObject, task.data.chapters, task.data.ffmetadataPath))) { if (!(await ffmpegHelpers.writeFFMetadataFile(task.data.ffmetadataObject, task.data.chapters, task.data.ffmetadataPath))) {
Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`) Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`)
task.setFailed('Failed to write metadata file.') const taskFailedString = {
text: 'Failed to write metadata file',
key: 'MessageTaskFailedToWriteMetadataFile'
}
task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)
return return
} }
@ -137,7 +158,11 @@ class AbMergeManager {
Logger.info(`[AbMergeManager] Task cancelled ${task.id}`) Logger.info(`[AbMergeManager] Task cancelled ${task.id}`)
} else { } else {
Logger.error(`[AbMergeManager] mergeAudioFiles failed`, error) Logger.error(`[AbMergeManager] mergeAudioFiles failed`, error)
task.setFailed('Failed to merge audio files') const taskFailedString = {
text: 'Failed to merge audio files',
key: 'MessageTaskFailedToMergeAudioFiles'
}
task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)
} }
return return
@ -163,8 +188,13 @@ class AbMergeManager {
if (error.message === 'FFMPEG_CANCELED') { if (error.message === 'FFMPEG_CANCELED') {
Logger.info(`[AbMergeManager] Task cancelled ${task.id}`) Logger.info(`[AbMergeManager] Task cancelled ${task.id}`)
} else { } else {
Logger.error(`[AbMergeManager] Failed to write metadata to file "${task.data.tempFilepath}"`) Logger.error(`[AbMergeManager] Failed to embed metadata in file "${task.data.tempFilepath}"`)
task.setFailed('Failed to write metadata to m4b file') const taskFailedString = {
text: `Failed to embed metadata in file ${Path.basename(task.data.tempFilepath)}`,
key: 'MessageTaskFailedToEmbedMetadataInFile',
subs: [Path.basename(task.data.tempFilepath)]
}
task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)
} }
return return
@ -196,7 +226,11 @@ class AbMergeManager {
await fs.remove(task.data.tempFilepath) await fs.remove(task.data.tempFilepath)
} catch (err) { } catch (err) {
Logger.error(`[AbMergeManager] Failed to move m4b from ${task.data.tempFilepath} to ${task.data.targetFilepath}`, err) Logger.error(`[AbMergeManager] Failed to move m4b from ${task.data.tempFilepath} to ${task.data.targetFilepath}`, err)
task.setFailed('Failed to move m4b file') const taskFailedString = {
text: 'Failed to move m4b file',
key: 'MessageTaskFailedToMoveM4bFile'
}
task.setFailed(taskFailedString)
this.removeTask(task, true) this.removeTask(task, true)
return return
} }

View file

@ -97,8 +97,17 @@ class AudioMetadataMangaer {
}, },
duration: libraryItem.media.duration duration: libraryItem.media.duration
} }
const taskDescription = `Embedding metadata in audiobook "${libraryItem.media.metadata.title}".`
task.setData('embed-metadata', 'Embedding Metadata', taskDescription, false, taskData) const taskTitleString = {
text: 'Embedding Metadata',
key: 'MessageTaskEmbeddingMetadata'
}
const taskDescriptionString = {
text: `Embedding metadata in audiobook "${libraryItem.media.metadata.title}".`,
key: 'MessageTaskEmbeddingMetadataDescription',
subs: [libraryItem.media.metadata.title]
}
task.setData('embed-metadata', taskTitleString, taskDescriptionString, false, taskData)
if (this.tasksRunning.length >= this.MAX_CONCURRENT_TASKS) { if (this.tasksRunning.length >= this.MAX_CONCURRENT_TASKS) {
Logger.info(`[AudioMetadataManager] Queueing embed metadata for audiobook "${libraryItem.media.metadata.title}"`) Logger.info(`[AudioMetadataManager] Queueing embed metadata for audiobook "${libraryItem.media.metadata.title}"`)
@ -112,6 +121,10 @@ class AudioMetadataMangaer {
} }
} }
/**
*
* @param {import('../objects/Task')} task
*/
async runMetadataEmbed(task) { async runMetadataEmbed(task) {
this.tasksRunning.push(task) this.tasksRunning.push(task)
TaskManager.addTask(task) TaskManager.addTask(task)
@ -123,7 +136,11 @@ class AudioMetadataMangaer {
Logger.debug(`[AudioMetadataManager] Target directory ${task.data.libraryItemDir} writable: ${targetDirWritable}`) Logger.debug(`[AudioMetadataManager] Target directory ${task.data.libraryItemDir} writable: ${targetDirWritable}`)
if (!targetDirWritable) { if (!targetDirWritable) {
Logger.error(`[AudioMetadataManager] Target directory is not writable: ${task.data.libraryItemDir}`) Logger.error(`[AudioMetadataManager] Target directory is not writable: ${task.data.libraryItemDir}`)
task.setFailed('Target directory is not writable') const taskFailedString = {
text: 'Target directory is not writable',
key: 'MessageTaskTargetDirectoryNotWritable'
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }
@ -134,7 +151,12 @@ class AudioMetadataMangaer {
await fs.access(af.path, fs.constants.W_OK) await fs.access(af.path, fs.constants.W_OK)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Audio file is not writable: ${af.path}`) Logger.error(`[AudioMetadataManager] Audio file is not writable: ${af.path}`)
task.setFailed(`Audio file "${Path.basename(af.path)}" is not writable`) const taskFailedString = {
text: `Audio file "${Path.basename(af.path)}" is not writable`,
key: 'MessageTaskAudioFileNotWritable',
subs: [Path.basename(af.path)]
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }
@ -148,7 +170,11 @@ class AudioMetadataMangaer {
cacheDirCreated = true cacheDirCreated = true
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to create cache directory ${task.data.itemCachePath}`, err) Logger.error(`[AudioMetadataManager] Failed to create cache directory ${task.data.itemCachePath}`, err)
task.setFailed('Failed to create cache directory') const taskFailedString = {
text: 'Failed to create cache directory',
key: 'MessageTaskFailedToCreateCacheDirectory'
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }
@ -159,7 +185,11 @@ class AudioMetadataMangaer {
const success = await ffmpegHelpers.writeFFMetadataFile(task.data.metadataObject, task.data.chapters, ffmetadataPath) const success = await ffmpegHelpers.writeFFMetadataFile(task.data.metadataObject, task.data.chapters, ffmetadataPath)
if (!success) { if (!success) {
Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`) Logger.error(`[AudioMetadataManager] Failed to write ffmetadata file for audiobook "${task.data.libraryItemId}"`)
task.setFailed('Failed to write metadata file.') const taskFailedString = {
text: 'Failed to write metadata file',
key: 'MessageTaskFailedToWriteMetadataFile'
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }
@ -181,7 +211,12 @@ class AudioMetadataMangaer {
Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`) Logger.debug(`[AudioMetadataManager] Backed up audio file at "${backupFilePath}"`)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to backup audio file "${af.path}"`, err) Logger.error(`[AudioMetadataManager] Failed to backup audio file "${af.path}"`, err)
task.setFailed(`Failed to backup audio file "${Path.basename(af.path)}"`) const taskFailedString = {
text: `Failed to backup audio file "${Path.basename(af.path)}"`,
key: 'MessageTaskFailedToBackupAudioFile',
subs: [Path.basename(af.path)]
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }
@ -195,7 +230,12 @@ class AudioMetadataMangaer {
Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${af.path}"`) Logger.info(`[AudioMetadataManager] Successfully tagged audio file "${af.path}"`)
} catch (err) { } catch (err) {
Logger.error(`[AudioMetadataManager] Failed to tag audio file "${af.path}"`, err) Logger.error(`[AudioMetadataManager] Failed to tag audio file "${af.path}"`, err)
task.setFailed(`Failed to tag audio file "${Path.basename(af.path)}"`) const taskFailedString = {
text: `Failed to embed metadata in file "${Path.basename(af.path)}"`,
key: 'MessageTaskFailedToEmbedMetadataInFile',
subs: [Path.basename(af.path)]
}
task.setFailed(taskFailedString)
this.handleTaskFinished(task) this.handleTaskFinished(task)
return return
} }

View file

@ -15,13 +15,12 @@ const { getFileSize } = require('../utils/fileUtils')
const Backup = require('../objects/Backup') const Backup = require('../objects/Backup')
const CacheManager = require('./CacheManager') const CacheManager = require('./CacheManager')
const NotificationManager = require('./NotificationManager')
class BackupManager { class BackupManager {
constructor(notificationManager) { constructor() {
this.ItemsMetadataPath = Path.join(global.MetadataPath, 'items') this.ItemsMetadataPath = Path.join(global.MetadataPath, 'items')
this.AuthorsMetadataPath = Path.join(global.MetadataPath, 'authors') this.AuthorsMetadataPath = Path.join(global.MetadataPath, 'authors')
/** @type {import('./NotificationManager')} */
this.notificationManager = notificationManager
this.scheduleTask = null this.scheduleTask = null
@ -301,7 +300,7 @@ class BackupManager {
const sqliteBackupPath = await this.backupSqliteDb(newBackup).catch((error) => { const sqliteBackupPath = await this.backupSqliteDb(newBackup).catch((error) => {
Logger.error(`[BackupManager] Failed to backup sqlite db`, error) Logger.error(`[BackupManager] Failed to backup sqlite db`, error)
const errorMsg = error?.message || error || 'Unknown Error' const errorMsg = error?.message || error || 'Unknown Error'
this.notificationManager.onBackupFailed(errorMsg) NotificationManager.onBackupFailed(errorMsg)
return false return false
}) })
@ -313,7 +312,7 @@ class BackupManager {
const zipResult = await this.zipBackup(sqliteBackupPath, newBackup).catch((error) => { const zipResult = await this.zipBackup(sqliteBackupPath, newBackup).catch((error) => {
Logger.error(`[BackupManager] Backup Failed ${error}`) Logger.error(`[BackupManager] Backup Failed ${error}`)
const errorMsg = error?.message || error || 'Unknown Error' const errorMsg = error?.message || error || 'Unknown Error'
this.notificationManager.onBackupFailed(errorMsg) NotificationManager.onBackupFailed(errorMsg)
return false return false
}) })
@ -344,7 +343,7 @@ class BackupManager {
} }
// Notification for backup successfully completed // Notification for backup successfully completed
this.notificationManager.onBackupCompleted(newBackup, this.backups.length, removeOldest) NotificationManager.onBackupCompleted(newBackup, this.backups.length, removeOldest)
return true return true
} }

View file

@ -76,18 +76,27 @@ class ZippedAssetDownloader {
async extractFiles(zipPath, filesToExtract, destDir) { async extractFiles(zipPath, filesToExtract, destDir) {
const zip = new StreamZip.async({ file: zipPath }) const zip = new StreamZip.async({ file: zipPath })
for (const file of filesToExtract) { try {
const outputPath = path.join(destDir, file.outputFileName) for (const file of filesToExtract) {
await zip.extract(file.pathInsideZip, outputPath) const outputPath = path.join(destDir, file.outputFileName)
Logger.debug(`[ZippedAssetDownloader] Extracted file ${file.pathInsideZip} to ${outputPath}`) if (!(await zip.entry(file.pathInsideZip))) {
Logger.error(`[ZippedAssetDownloader] File ${file.pathInsideZip} not found in zip file ${zipPath}`)
continue
}
await zip.extract(file.pathInsideZip, outputPath)
Logger.debug(`[ZippedAssetDownloader] Extracted file ${file.pathInsideZip} to ${outputPath}`)
// Set executable permission for Linux // Set executable permission for Linux
if (process.platform !== 'win32') { if (process.platform !== 'win32') {
await fs.chmod(outputPath, 0o755) await fs.chmod(outputPath, 0o755)
}
} }
} catch (error) {
Logger.error('[ZippedAssetDownloader] Error extracting files:', error)
throw error
} finally {
await zip.close()
} }
await zip.close()
} }
async downloadAndExtractFiles(releaseTag, assetName, filesToExtract, destDir) { async downloadAndExtractFiles(releaseTag, assetName, filesToExtract, destDir) {
@ -99,7 +108,6 @@ class ZippedAssetDownloader {
await this.extractFiles(zipPath, filesToExtract, destDir) await this.extractFiles(zipPath, filesToExtract, destDir)
} catch (error) { } catch (error) {
Logger.error(`[ZippedAssetDownloader] Error downloading or extracting files: ${error.message}`) Logger.error(`[ZippedAssetDownloader] Error downloading or extracting files: ${error.message}`)
throw error
} finally { } finally {
if (zipPath) await fs.remove(zipPath) if (zipPath) await fs.remove(zipPath)
} }
@ -164,14 +172,67 @@ class FFBinariesDownloader extends ZippedAssetDownloader {
} }
} }
class NunicodeDownloader extends ZippedAssetDownloader {
constructor() {
super()
this.platformSuffix = this.getPlatformSuffix()
}
getPlatformSuffix() {
const platform = process.platform
const arch = process.arch
if (platform === 'win32' && arch === 'x64') {
return 'win-x64'
} else if (platform === 'darwin' && (arch === 'x64' || arch === 'arm64')) {
return 'osx-arm64'
} else if (platform === 'linux' && arch === 'x64') {
return 'linux-x64'
} else if (platform === 'linux' && arch === 'arm64') {
return 'linux-arm64'
}
return null
}
async getAssetUrl(releaseTag, assetName) {
return `https://github.com/mikiher/nunicode-sqlite/releases/download/v${releaseTag}/${assetName}`
}
getAssetName(binaryName, releaseTag) {
if (!this.platformSuffix) {
throw new Error(`[NunicodeDownloader] Platform ${process.platform}-${process.arch} not supported`)
}
return `${binaryName}-${this.platformSuffix}.zip`
}
getAssetFileName(binaryName) {
if (process.platform === 'win32') {
return `${binaryName}.dll`
} else if (process.platform === 'darwin') {
return `${binaryName}.dylib`
} else if (process.platform === 'linux') {
return `${binaryName}.so`
}
throw new Error(`[NunicodeDownloader] Platform ${process.platform} not supported`)
}
}
class Binary { class Binary {
constructor(name, type, envVariable, validVersions, source) { constructor(name, type, envVariable, validVersions, source, required = true) {
if (!name) throw new Error('Binary name is required')
this.name = name this.name = name
if (!type) throw new Error('Binary type is required')
this.type = type this.type = type
if (!envVariable) throw new Error('Binary environment variable name is required')
this.envVariable = envVariable this.envVariable = envVariable
if (!validVersions || !validVersions.length) throw new Error(`No valid versions specified for ${type} ${name}. At least one version is required.`)
this.validVersions = validVersions this.validVersions = validVersions
if (!source || !(source instanceof ZippedAssetDownloader)) throw new Error('Binary source is required, and must be an instance of ZippedAssetDownloader')
this.source = source this.source = source
this.fileName = this.getFileName() this.fileName = this.getFileName()
this.required = required
this.exec = exec this.exec = exec
} }
@ -205,37 +266,65 @@ class Binary {
} }
} }
async isGood(binaryPath) { async isLibraryVersionValid(libraryPath) {
if (!binaryPath || !(await fs.pathExists(binaryPath))) return false
if (!this.validVersions.length) return true
if (this.type === 'library') return true
try { try {
const { stdout } = await this.exec('"' + binaryPath + '"' + ' -version') const versionFilePath = libraryPath + '.ver'
if (!(await fs.pathExists(versionFilePath))) return false
const version = (await fs.readFile(versionFilePath, 'utf8')).trim()
return this.validVersions.some((validVersion) => version.startsWith(validVersion))
} catch (err) {
Logger.error(`[Binary] Failed to check version of ${libraryPath}`, err)
return false
}
}
async isExecutableVersionValid(executablePath) {
try {
const { stdout } = await this.exec('"' + executablePath + '"' + ' -version')
const version = stdout.match(/version\s([\d\.]+)/)?.[1] const version = stdout.match(/version\s([\d\.]+)/)?.[1]
if (!version) return false if (!version) return false
return this.validVersions.some((validVersion) => version.startsWith(validVersion)) return this.validVersions.some((validVersion) => version.startsWith(validVersion))
} catch (err) { } catch (err) {
Logger.error(`[Binary] Failed to check version of ${binaryPath}`) Logger.error(`[Binary] Failed to check version of ${executablePath}`, err)
return false
}
}
async isGood(binaryPath) {
try {
if (!binaryPath || !(await fs.pathExists(binaryPath))) return false
if (this.type === 'library') return await this.isLibraryVersionValid(binaryPath)
else if (this.type === 'executable') return await this.isExecutableVersionValid(binaryPath)
else return true
} catch (err) {
Logger.error(`[Binary] Failed to check ${this.type} ${this.name} at ${binaryPath}`, err)
return false return false
} }
} }
async download(destination) { async download(destination) {
await this.source.downloadBinary(this.name, this.validVersions[0], destination) const version = this.validVersions[0]
try {
await this.source.downloadBinary(this.name, version, destination)
// if it's a library, write the version string to a file
if (this.type === 'library') {
const libraryPath = path.join(destination, this.fileName)
await fs.writeFile(libraryPath + '.ver', version)
}
} catch (err) {
Logger.error(`[Binary] Failed to download ${this.type} ${this.name} version ${version} to ${destination}`, err)
}
} }
} }
const ffbinaries = new FFBinariesDownloader() const ffbinaries = new FFBinariesDownloader()
module.exports.ffbinaries = ffbinaries // for testing const nunicode = new NunicodeDownloader()
//const sqlean = new SQLeanDownloader()
//module.exports.sqlean = sqlean // for testing
class BinaryManager { class BinaryManager {
defaultRequiredBinaries = [ defaultRequiredBinaries = [
new Binary('ffmpeg', 'executable', 'FFMPEG_PATH', ['5.1'], ffbinaries), // ffmpeg executable new Binary('ffmpeg', 'executable', 'FFMPEG_PATH', ['5.1'], ffbinaries), // ffmpeg executable
new Binary('ffprobe', 'executable', 'FFPROBE_PATH', ['5.1'], ffbinaries) // ffprobe executable new Binary('ffprobe', 'executable', 'FFPROBE_PATH', ['5.1'], ffbinaries), // ffprobe executable
// TODO: Temporarily disabled due to db corruption issues new Binary('libnusqlite3', 'library', 'NUSQLITE3_PATH', ['1.2'], nunicode, false) // nunicode sqlite3 extension
// new Binary('unicode', 'library', 'SQLEAN_UNICODE_PATH', ['0.24.2'], sqlean) // sqlean unicode extension
] ]
constructor(requiredBinaries = this.defaultRequiredBinaries) { constructor(requiredBinaries = this.defaultRequiredBinaries) {
@ -249,7 +338,7 @@ class BinaryManager {
// Optional skip binaries check // Optional skip binaries check
if (process.env.SKIP_BINARIES_CHECK === '1') { if (process.env.SKIP_BINARIES_CHECK === '1') {
for (const binary of this.requiredBinaries) { for (const binary of this.requiredBinaries) {
if (!process.env[binary.envVariable]) { if (!process.env[binary.envVariable] && binary.required) {
await Logger.fatal(`[BinaryManager] Environment variable ${binary.envVariable} must be set`) await Logger.fatal(`[BinaryManager] Environment variable ${binary.envVariable} must be set`)
process.exit(1) process.exit(1)
} }
@ -265,21 +354,37 @@ class BinaryManager {
await this.removeOldBinaries(missingBinaries) await this.removeOldBinaries(missingBinaries)
await this.install(missingBinaries) await this.install(missingBinaries)
const missingBinariesAfterInstall = await this.findRequiredBinaries() const missingBinariesAfterInstall = await this.findRequiredBinaries()
if (missingBinariesAfterInstall.length) { const missingRequiredBinryNames = missingBinariesAfterInstall.filter((binary) => binary.required).map((binary) => binary.name)
Logger.error(`[BinaryManager] Failed to find or install required binaries: ${missingBinariesAfterInstall.join(', ')}`) if (missingRequiredBinryNames.length) {
Logger.error(`[BinaryManager] Failed to find or install required binaries: ${missingRequiredBinryNames.join(', ')}`)
process.exit(1) process.exit(1)
} }
this.initialized = true this.initialized = true
} }
/**
* Remove binary
*
* @param {string} destination
* @param {Binary} binary
*/
async removeBinary(destination, binary) { async removeBinary(destination, binary) {
const binaryPath = path.join(destination, binary.fileName) try {
if (await fs.pathExists(binaryPath)) { const binaryPath = path.join(destination, binary.fileName)
Logger.debug(`[BinaryManager] Removing binary: ${binaryPath}`) if (await fs.pathExists(binaryPath)) {
await fs.remove(binaryPath) Logger.debug(`[BinaryManager] Removing binary: ${binaryPath}`)
await fs.remove(binaryPath)
}
} catch (err) {
Logger.error(`[BinaryManager] Error removing binary: ${binaryPath}`)
} }
} }
/**
* Remove old binaries
*
* @param {Binary[]} binaries
*/
async removeOldBinaries(binaries) { async removeOldBinaries(binaries) {
for (const binary of binaries) { for (const binary of binaries) {
await this.removeBinary(this.mainInstallDir, binary) await this.removeBinary(this.mainInstallDir, binary)
@ -290,26 +395,31 @@ class BinaryManager {
/** /**
* Find required binaries and return array of binary names that are missing * Find required binaries and return array of binary names that are missing
* *
* @returns {Promise<string[]>} * @returns {Promise<Binary[]>} Array of missing binaries
*/ */
async findRequiredBinaries() { async findRequiredBinaries() {
const missingBinaries = [] const missingBinaries = []
for (const binary of this.requiredBinaries) { for (const binary of this.requiredBinaries) {
const binaryPath = await binary.find(this.mainInstallDir, this.altInstallDir) const binaryPath = await binary.find(this.mainInstallDir, this.altInstallDir)
if (binaryPath) { if (binaryPath) {
Logger.info(`[BinaryManager] Found valid binary ${binary.name} at ${binaryPath}`) Logger.info(`[BinaryManager] Found valid ${binary.type} ${binary.name} at ${binaryPath}`)
if (process.env[binary.envVariable] !== binaryPath) { if (process.env[binary.envVariable] !== binaryPath) {
Logger.info(`[BinaryManager] Updating process.env.${binary.envVariable}`) Logger.info(`[BinaryManager] Updating process.env.${binary.envVariable}`)
process.env[binary.envVariable] = binaryPath process.env[binary.envVariable] = binaryPath
} }
} else { } else {
Logger.info(`[BinaryManager] ${binary.name} not found or version too old`) Logger.info(`[BinaryManager] ${binary.name} not found or not a valid version`)
missingBinaries.push(binary) missingBinaries.push(binary)
} }
} }
return missingBinaries return missingBinaries
} }
/**
* Install missing binaries
*
* @param {Binary[]} binaries
*/
async install(binaries) { async install(binaries) {
if (!binaries.length) return if (!binaries.length) return
Logger.info(`[BinaryManager] Installing binaries: ${binaries.map((binary) => binary.name).join(', ')}`) Logger.info(`[BinaryManager] Installing binaries: ${binaries.map((binary) => binary.name).join(', ')}`)
@ -323,3 +433,5 @@ class BinaryManager {
module.exports = BinaryManager module.exports = BinaryManager
module.exports.Binary = Binary // for testing module.exports.Binary = Binary // for testing
module.exports.ffbinaries = ffbinaries // for testing
module.exports.nunicode = nunicode // for testing

View file

@ -180,4 +180,4 @@ class NotificationManager {
}) })
} }
} }
module.exports = NotificationManager module.exports = new NotificationManager()

View file

@ -14,6 +14,7 @@ const ffmpegHelpers = require('../utils/ffmpegHelpers')
const TaskManager = require('./TaskManager') const TaskManager = require('./TaskManager')
const CoverManager = require('../managers/CoverManager') const CoverManager = require('../managers/CoverManager')
const NotificationManager = require('../managers/NotificationManager')
const LibraryFile = require('../objects/files/LibraryFile') const LibraryFile = require('../objects/files/LibraryFile')
const PodcastEpisodeDownload = require('../objects/PodcastEpisodeDownload') const PodcastEpisodeDownload = require('../objects/PodcastEpisodeDownload')
@ -22,9 +23,8 @@ const AudioFile = require('../objects/files/AudioFile')
const LibraryItem = require('../objects/LibraryItem') const LibraryItem = require('../objects/LibraryItem')
class PodcastManager { class PodcastManager {
constructor(watcher, notificationManager) { constructor(watcher) {
this.watcher = watcher this.watcher = watcher
this.notificationManager = notificationManager
this.downloadQueue = [] this.downloadQueue = []
this.currentDownload = null this.currentDownload = null
@ -71,12 +71,20 @@ class PodcastManager {
return return
} }
const taskDescription = `Downloading episode "${podcastEpisodeDownload.podcastEpisode.title}".`
const taskData = { const taskData = {
libraryId: podcastEpisodeDownload.libraryId, libraryId: podcastEpisodeDownload.libraryId,
libraryItemId: podcastEpisodeDownload.libraryItemId libraryItemId: podcastEpisodeDownload.libraryItemId
} }
const task = TaskManager.createAndAddTask('download-podcast-episode', 'Downloading Episode', taskDescription, false, taskData) const taskTitleString = {
text: 'Downloading episode',
key: 'MessageDownloadingEpisode'
}
const taskDescriptionString = {
text: `Downloading episode "${podcastEpisodeDownload.podcastEpisode.title}".`,
key: 'MessageTaskDownloadingEpisodeDescription',
subs: [podcastEpisodeDownload.podcastEpisode.title]
}
const task = TaskManager.createAndAddTask('download-podcast-episode', taskTitleString, taskDescriptionString, false, taskData)
SocketAuthority.emitter('episode_download_started', podcastEpisodeDownload.toJSONForClient()) SocketAuthority.emitter('episode_download_started', podcastEpisodeDownload.toJSONForClient())
this.currentDownload = podcastEpisodeDownload this.currentDownload = podcastEpisodeDownload
@ -119,14 +127,22 @@ class PodcastManager {
if (!success) { if (!success) {
await fs.remove(this.currentDownload.targetPath) await fs.remove(this.currentDownload.targetPath)
this.currentDownload.setFinished(false) this.currentDownload.setFinished(false)
task.setFailed('Failed to download episode') const taskFailedString = {
text: 'Failed',
key: 'MessageTaskFailed'
}
task.setFailed(taskFailedString)
} else { } else {
Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`) Logger.info(`[PodcastManager] Successfully downloaded podcast episode "${this.currentDownload.podcastEpisode.title}"`)
this.currentDownload.setFinished(true) this.currentDownload.setFinished(true)
task.setFinished() task.setFinished()
} }
} else { } else {
task.setFailed('Failed to download episode') const taskFailedString = {
text: 'Failed',
key: 'MessageTaskFailed'
}
task.setFailed(taskFailedString)
this.currentDownload.setFinished(false) this.currentDownload.setFinished(false)
} }
@ -187,7 +203,7 @@ class PodcastManager {
if (this.currentDownload.isAutoDownload) { if (this.currentDownload.isAutoDownload) {
// Notifications only for auto downloaded episodes // Notifications only for auto downloaded episodes
this.notificationManager.onPodcastEpisodeDownloaded(libraryItem, podcastEpisode) NotificationManager.onPodcastEpisodeDownloaded(libraryItem, podcastEpisode)
} }
return true return true
@ -407,13 +423,35 @@ class PodcastManager {
* @param {import('../managers/CronManager')} cronManager * @param {import('../managers/CronManager')} cronManager
*/ */
async createPodcastsFromFeedUrls(rssFeedUrls, folder, autoDownloadEpisodes, cronManager) { async createPodcastsFromFeedUrls(rssFeedUrls, folder, autoDownloadEpisodes, cronManager) {
const task = TaskManager.createAndAddTask('opml-import', 'OPML import', `Creating podcasts from ${rssFeedUrls.length} RSS feeds`, true, null) const taskTitleString = {
text: 'OPML import',
key: 'MessageTaskOpmlImport'
}
const taskDescriptionString = {
text: `Creating podcasts from ${rssFeedUrls.length} RSS feeds`,
key: 'MessageTaskOpmlImportDescription',
subs: [rssFeedUrls.length]
}
const task = TaskManager.createAndAddTask('opml-import', taskTitleString, taskDescriptionString, true, null)
let numPodcastsAdded = 0 let numPodcastsAdded = 0
Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Importing ${rssFeedUrls.length} RSS feeds to folder "${folder.path}"`) Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Importing ${rssFeedUrls.length} RSS feeds to folder "${folder.path}"`)
for (const feedUrl of rssFeedUrls) { for (const feedUrl of rssFeedUrls) {
const feed = await getPodcastFeed(feedUrl).catch(() => null) const feed = await getPodcastFeed(feedUrl).catch(() => null)
if (!feed?.episodes) { if (!feed?.episodes) {
TaskManager.createAndEmitFailedTask('opml-import-feed', 'OPML import feed', `Importing RSS feed "${feedUrl}"`, 'Failed to get podcast feed') const taskTitleStringFeed = {
text: 'OPML import feed',
key: 'MessageTaskOpmlImportFeed'
}
const taskDescriptionStringFeed = {
text: `Importing RSS feed "${feedUrl}"`,
key: 'MessageTaskOpmlImportFeedDescription',
subs: [feedUrl]
}
const taskErrorString = {
text: 'Failed to get podcast feed',
key: 'MessageTaskOpmlImportFeedFailed'
}
TaskManager.createAndEmitFailedTask('opml-import-feed', taskTitleStringFeed, taskDescriptionStringFeed, taskErrorString)
Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Failed to get podcast feed for "${feedUrl}"`) Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Failed to get podcast feed for "${feedUrl}"`)
continue continue
} }
@ -429,7 +467,20 @@ class PodcastManager {
})) > 0 })) > 0
if (existingLibraryItem) { if (existingLibraryItem) {
Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Podcast already exists at path "${podcastPath}"`) Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Podcast already exists at path "${podcastPath}"`)
TaskManager.createAndEmitFailedTask('opml-import-feed', 'OPML import feed', `Creating podcast "${feed.metadata.title}"`, 'Podcast already exists at path') const taskTitleStringFeed = {
text: 'OPML import feed',
key: 'MessageTaskOpmlImportFeed'
}
const taskDescriptionStringPodcast = {
text: `Creating podcast "${feed.metadata.title}"`,
key: 'MessageTaskOpmlImportFeedPodcastDescription',
subs: [feed.metadata.title]
}
const taskErrorString = {
text: 'Podcast already exists at path',
key: 'MessageTaskOpmlImportFeedPodcastExists'
}
TaskManager.createAndEmitFailedTask('opml-import-feed', taskTitleStringFeed, taskDescriptionStringPodcast, taskErrorString)
continue continue
} }
@ -442,7 +493,20 @@ class PodcastManager {
}) })
if (!successCreatingPath) { if (!successCreatingPath) {
Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Failed to create podcast folder at "${podcastPath}"`) Logger.error(`[PodcastManager] createPodcastsFromFeedUrls: Failed to create podcast folder at "${podcastPath}"`)
TaskManager.createAndEmitFailedTask('opml-import-feed', 'OPML import feed', `Creating podcast "${feed.metadata.title}"`, 'Failed to create podcast folder') const taskTitleStringFeed = {
text: 'OPML import feed',
key: 'MessageTaskOpmlImportFeed'
}
const taskDescriptionStringPodcast = {
text: `Creating podcast "${feed.metadata.title}"`,
key: 'MessageTaskOpmlImportFeedPodcastDescription',
subs: [feed.metadata.title]
}
const taskErrorString = {
text: 'Failed to create podcast folder',
key: 'MessageTaskOpmlImportFeedPodcastFailed'
}
TaskManager.createAndEmitFailedTask('opml-import-feed', taskTitleStringFeed, taskDescriptionStringPodcast, taskErrorString)
continue continue
} }
@ -504,7 +568,12 @@ class PodcastManager {
numPodcastsAdded++ numPodcastsAdded++
} }
task.setFinished(`Added ${numPodcastsAdded} podcasts`) const taskFinishedString = {
text: `Added ${numPodcastsAdded} podcasts`,
key: 'MessageTaskOpmlImportFinished',
subs: [numPodcastsAdded]
}
task.setFinished(taskFinishedString)
TaskManager.taskFinished(task) TaskManager.taskFinished(task)
Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Finished OPML import. Created ${numPodcastsAdded} podcasts out of ${rssFeedUrls.length} RSS feed URLs`) Logger.info(`[PodcastManager] createPodcastsFromFeedUrls: Finished OPML import. Created ${numPodcastsAdded} podcasts out of ${rssFeedUrls.length} RSS feed URLs`)
} }

View file

@ -1,6 +1,13 @@
const SocketAuthority = require('../SocketAuthority') const SocketAuthority = require('../SocketAuthority')
const Task = require('../objects/Task') const Task = require('../objects/Task')
/**
* @typedef TaskString
* @property {string} text
* @property {string} key
* @property {string[]} [subs]
*/
class TaskManager { class TaskManager {
constructor() { constructor() {
/** @type {Task[]} */ /** @type {Task[]} */
@ -33,14 +40,14 @@ class TaskManager {
* Create new task and add * Create new task and add
* *
* @param {string} action * @param {string} action
* @param {string} title * @param {TaskString} titleString
* @param {string} description * @param {TaskString|null} descriptionString
* @param {boolean} showSuccess * @param {boolean} showSuccess
* @param {Object} [data] * @param {Object} [data]
*/ */
createAndAddTask(action, title, description, showSuccess, data = {}) { createAndAddTask(action, titleString, descriptionString, showSuccess, data = {}) {
const task = new Task() const task = new Task()
task.setData(action, title, description, showSuccess, data) task.setData(action, titleString, descriptionString, showSuccess, data)
this.addTask(task) this.addTask(task)
return task return task
} }
@ -49,14 +56,14 @@ class TaskManager {
* Create new failed task and add * Create new failed task and add
* *
* @param {string} action * @param {string} action
* @param {string} title * @param {TaskString} titleString
* @param {string} description * @param {TaskString|null} descriptionString
* @param {string} errorMessage * @param {TaskString} errorMessageString
*/ */
createAndEmitFailedTask(action, title, description, errorMessage) { createAndEmitFailedTask(action, titleString, descriptionString, errorMessageString) {
const task = new Task() const task = new Task()
task.setData(action, title, description, false) task.setData(action, titleString, descriptionString, false)
task.setFailed(errorMessage) task.setFailed(errorMessageString)
SocketAuthority.emitter('task_started', task.toJSON()) SocketAuthority.emitter('task_started', task.toJSON())
return task return task
} }

View file

@ -1,6 +1,5 @@
const { DataTypes, Model, where, fn, col } = require('sequelize') const { DataTypes, Model, where, fn, col } = require('sequelize')
const parseNameString = require('../utils/parsers/parseNameString') const parseNameString = require('../utils/parsers/parseNameString')
const { asciiOnlyToLowerCase } = require('../utils/index')
class Author extends Model { class Author extends Model {
constructor(values, options) { constructor(values, options) {
@ -56,7 +55,7 @@ class Author extends Model {
static async getByNameAndLibrary(authorName, libraryId) { static async getByNameAndLibrary(authorName, libraryId) {
return this.findOne({ return this.findOne({
where: [ where: [
where(fn('lower', col('name')), asciiOnlyToLowerCase(authorName)), where(fn('lower', col('name')), authorName.toLowerCase()),
{ {
libraryId libraryId
} }

View file

@ -1,7 +1,6 @@
const { DataTypes, Model, where, fn, col } = require('sequelize') const { DataTypes, Model, where, fn, col } = require('sequelize')
const { getTitlePrefixAtEnd } = require('../utils/index') const { getTitlePrefixAtEnd } = require('../utils/index')
const { asciiOnlyToLowerCase } = require('../utils/index')
class Series extends Model { class Series extends Model {
constructor(values, options) { constructor(values, options) {
@ -42,7 +41,7 @@ class Series extends Model {
static async getByNameAndLibrary(seriesName, libraryId) { static async getByNameAndLibrary(seriesName, libraryId) {
return this.findOne({ return this.findOne({
where: [ where: [
where(fn('lower', col('name')), asciiOnlyToLowerCase(seriesName)), where(fn('lower', col('name')), seriesName.toLowerCase()),
{ {
libraryId libraryId
} }

View file

@ -1,4 +1,11 @@
const uuidv4 = require("uuid").v4 const uuidv4 = require('uuid').v4
/**
* @typedef TaskString
* @property {string} text
* @property {string} key
* @property {string[]} [subs]
*/
class Task { class Task {
constructor() { constructor() {
@ -11,10 +18,25 @@ class Task {
/** @type {string} */ /** @type {string} */
this.title = null this.title = null
/** @type {string} - Used for translation */
this.titleKey = null
/** @type {string[]} - Used for translation */
this.titleSubs = null
/** @type {string} */ /** @type {string} */
this.description = null this.description = null
/** @type {string} - Used for translation */
this.descriptionKey = null
/** @type {string[]} - Used for translation */
this.descriptionSubs = null
/** @type {string} */ /** @type {string} */
this.error = null this.error = null
/** @type {string} - Used for translation */
this.errorKey = null
/** @type {string[]} - Used for translation */
this.errorSubs = null
/** @type {boolean} client should keep the task visible after success */ /** @type {boolean} client should keep the task visible after success */
this.showSuccess = false this.showSuccess = false
@ -35,8 +57,14 @@ class Task {
action: this.action, action: this.action,
data: this.data ? { ...this.data } : {}, data: this.data ? { ...this.data } : {},
title: this.title, title: this.title,
titleKey: this.titleKey,
titleSubs: this.titleSubs,
description: this.description, description: this.description,
descriptionKey: this.descriptionKey,
descriptionSubs: this.descriptionSubs,
error: this.error, error: this.error,
errorKey: this.errorKey,
errorSubs: this.errorSubs,
showSuccess: this.showSuccess, showSuccess: this.showSuccess,
isFailed: this.isFailed, isFailed: this.isFailed,
isFinished: this.isFinished, isFinished: this.isFinished,
@ -47,30 +75,36 @@ class Task {
/** /**
* Set initial task data * Set initial task data
* *
* @param {string} action * @param {string} action
* @param {string} title * @param {TaskString} titleString
* @param {string} description * @param {TaskString|null} descriptionString
* @param {boolean} showSuccess * @param {boolean} showSuccess
* @param {Object} [data] * @param {Object} [data]
*/ */
setData(action, title, description, showSuccess, data = {}) { setData(action, titleString, descriptionString, showSuccess, data = {}) {
this.id = uuidv4() this.id = uuidv4()
this.action = action this.action = action
this.data = { ...data } this.data = { ...data }
this.title = title this.title = titleString.text
this.description = description this.titleKey = titleString.key || null
this.titleSubs = titleString.subs || null
this.description = descriptionString?.text || null
this.descriptionKey = descriptionString?.key || null
this.descriptionSubs = descriptionString?.subs || null
this.showSuccess = showSuccess this.showSuccess = showSuccess
this.startedAt = Date.now() this.startedAt = Date.now()
} }
/** /**
* Set task as failed * Set task as failed
* *
* @param {string} message error message * @param {TaskString} messageString
*/ */
setFailed(message) { setFailed(messageString) {
this.error = message this.error = messageString.text
this.errorKey = messageString.key || null
this.errorSubs = messageString.subs || null
this.isFailed = true this.isFailed = true
this.failedAt = Date.now() this.failedAt = Date.now()
this.setFinished() this.setFinished()
@ -78,15 +112,22 @@ class Task {
/** /**
* Set task as finished * Set task as finished
* *
* @param {string} [newDescription] update description * @param {TaskString} [newDescriptionString] update description
* @param {boolean} [clearDescription] clear description
*/ */
setFinished(newDescription = null) { setFinished(newDescriptionString = null, clearDescription = false) {
if (newDescription) { if (newDescriptionString) {
this.description = newDescription this.description = newDescriptionString.text
this.descriptionKey = newDescriptionString.key || null
this.descriptionSubs = newDescriptionString.subs || null
} else if (clearDescription) {
this.description = null
this.descriptionKey = null
this.descriptionSubs = null
} }
this.isFinished = true this.isFinished = true
this.finishedAt = Date.now() this.finishedAt = Date.now()
} }
} }
module.exports = Task module.exports = Task

View file

@ -129,7 +129,7 @@ class Audnexus {
return null return null
} }
const author = await this.authorRequest(closestMatch.asin) const author = await this.authorRequest(closestMatch.asin, region)
if (!author) { if (!author) {
return null return null
} }

View file

@ -55,8 +55,6 @@ class ApiRouter {
this.rssFeedManager = Server.rssFeedManager this.rssFeedManager = Server.rssFeedManager
/** @type {import('../managers/CronManager')} */ /** @type {import('../managers/CronManager')} */
this.cronManager = Server.cronManager this.cronManager = Server.cronManager
/** @type {import('../managers/NotificationManager')} */
this.notificationManager = Server.notificationManager
/** @type {import('../managers/EmailManager')} */ /** @type {import('../managers/EmailManager')} */
this.emailManager = Server.emailManager this.emailManager = Server.emailManager
this.apiCacheManager = Server.apiCacheManager this.apiCacheManager = Server.apiCacheManager

View file

@ -475,16 +475,26 @@ class AudioFileScanner {
audioFiles.forEach((file) => { audioFiles.forEach((file) => {
if (file.duration) { if (file.duration) {
const afChapters = // Multi-file audiobook may include the previous and next chapters embedded with close to 0 duration
file.chapters?.map((c) => ({ // Filter these out and log a warning
...c, // See https://github.com/advplyr/audiobookshelf/issues/3361
id: c.id + currChapterId, const afChaptersCleaned =
start: c.start + currStartTime, file.chapters?.filter((c) => {
end: c.end + currStartTime if (c.end - c.start < 0.1) {
})) ?? [] libraryScan.addLog(LogLevel.WARN, `Chapter "${c.title}" has invalid duration of ${c.end - c.start} seconds. Skipping this chapter.`)
return false
}
return true
}) || []
const afChapters = afChaptersCleaned.map((c) => ({
...c,
id: c.id + currChapterId,
start: c.start + currStartTime,
end: c.end + currStartTime
}))
chapters = chapters.concat(afChapters) chapters = chapters.concat(afChapters)
currChapterId += file.chapters?.length ?? 0 currChapterId += afChaptersCleaned.length ?? 0
currStartTime += file.duration currStartTime += file.duration
} }
}) })

View file

@ -590,6 +590,10 @@ class BookScanner {
Database.addPublisherToFilterData(libraryItemData.libraryId, libraryItem.book.publisher) Database.addPublisherToFilterData(libraryItemData.libraryId, libraryItem.book.publisher)
Database.addLanguageToFilterData(libraryItemData.libraryId, libraryItem.book.language) Database.addLanguageToFilterData(libraryItemData.libraryId, libraryItem.book.language)
const publishedYear = libraryItem.book.publishedYear
const decade = publishedYear ? `${Math.floor(publishedYear / 10) * 10}` : null
Database.addPublishedDecadeToFilterData(libraryItemData.libraryId, decade)
// Load for emitting to client // Load for emitting to client
libraryItem.media = await libraryItem.getMedia({ libraryItem.media = await libraryItem.getMedia({
include: [ include: [

View file

@ -15,12 +15,12 @@ const LibraryFile = require('../objects/files/LibraryFile')
const SocketAuthority = require('../SocketAuthority') const SocketAuthority = require('../SocketAuthority')
class LibraryItemScanner { class LibraryItemScanner {
constructor() { } constructor() {}
/** /**
* Scan single library item * Scan single library item
* *
* @param {string} libraryItemId * @param {string} libraryItemId
* @param {{relPath:string, path:string}} [updateLibraryItemDetails] used by watcher when item folder was renamed * @param {{relPath:string, path:string}} [updateLibraryItemDetails] used by watcher when item folder was renamed
* @returns {number} ScanResult * @returns {number} ScanResult
*/ */
@ -76,8 +76,8 @@ class LibraryItemScanner {
/** /**
* Remove empty authors and series * Remove empty authors and series
* @param {string} libraryId * @param {string} libraryId
* @param {ScanLogger} scanLogger * @param {ScanLogger} scanLogger
* @returns {Promise} * @returns {Promise}
*/ */
async checkAuthorsAndSeriesRemovedFromBooks(libraryId, scanLogger) { async checkAuthorsAndSeriesRemovedFromBooks(libraryId, scanLogger) {
@ -90,11 +90,11 @@ class LibraryItemScanner {
} }
/** /**
* *
* @param {string} libraryItemPath * @param {string} libraryItemPath
* @param {import('../models/Library')} library * @param {import('../models/Library')} library
* @param {import('../models/LibraryFolder')} folder * @param {import('../models/LibraryFolder')} folder
* @param {boolean} isSingleMediaItem * @param {boolean} isSingleMediaItem
* @returns {Promise<LibraryItemScanData>} * @returns {Promise<LibraryItemScanData>}
*/ */
async getLibraryItemScanData(libraryItemPath, library, folder, isSingleMediaItem) { async getLibraryItemScanData(libraryItemPath, library, folder, isSingleMediaItem) {
@ -105,7 +105,8 @@ class LibraryItemScanner {
let fileItems = [] let fileItems = []
if (isSingleMediaItem) { // Single media item in root of folder if (isSingleMediaItem) {
// Single media item in root of folder
fileItems = [ fileItems = [
{ {
fullpath: libraryItemPath, fullpath: libraryItemPath,
@ -151,9 +152,9 @@ class LibraryItemScanner {
} }
/** /**
* *
* @param {import('../models/LibraryItem')} existingLibraryItem * @param {import('../models/LibraryItem')} existingLibraryItem
* @param {LibraryItemScanData} libraryItemData * @param {LibraryItemScanData} libraryItemData
* @param {import('../models/Library').LibrarySettingsObject} librarySettings * @param {import('../models/Library').LibrarySettingsObject} librarySettings
* @param {LibraryScan} libraryScan * @param {LibraryScan} libraryScan
* @returns {Promise<{libraryItem:LibraryItem, wasUpdated:boolean}>} * @returns {Promise<{libraryItem:LibraryItem, wasUpdated:boolean}>}
@ -167,8 +168,8 @@ class LibraryItemScanner {
} }
/** /**
* *
* @param {LibraryItemScanData} libraryItemData * @param {LibraryItemScanData} libraryItemData
* @param {import('../models/Library').LibrarySettingsObject} librarySettings * @param {import('../models/Library').LibrarySettingsObject} librarySettings
* @param {LibraryScan} libraryScan * @param {LibraryScan} libraryScan
* @returns {Promise<LibraryItem>} * @returns {Promise<LibraryItem>}
@ -181,17 +182,17 @@ class LibraryItemScanner {
newLibraryItem = await PodcastScanner.scanNewPodcastLibraryItem(libraryItemData, librarySettings, libraryScan) newLibraryItem = await PodcastScanner.scanNewPodcastLibraryItem(libraryItemData, librarySettings, libraryScan)
} }
if (newLibraryItem) { if (newLibraryItem) {
libraryScan.addLog(LogLevel.INFO, `Created new library item "${newLibraryItem.relPath}"`) libraryScan.addLog(LogLevel.INFO, `Created new library item "${newLibraryItem.relPath}" with id "${newLibraryItem.id}"`)
} }
return newLibraryItem return newLibraryItem
} }
/** /**
* Scan library item folder coming from Watcher * Scan library item folder coming from Watcher
* @param {string} libraryItemPath * @param {string} libraryItemPath
* @param {import('../models/Library')} library * @param {import('../models/Library')} library
* @param {import('../models/LibraryFolder')} folder * @param {import('../models/LibraryFolder')} folder
* @param {boolean} isSingleMediaItem * @param {boolean} isSingleMediaItem
* @returns {Promise<LibraryItem>} ScanResult * @returns {Promise<LibraryItem>} ScanResult
*/ */
async scanPotentialNewLibraryItem(libraryItemPath, library, folder, isSingleMediaItem) { async scanPotentialNewLibraryItem(libraryItemPath, library, folder, isSingleMediaItem) {
@ -204,4 +205,4 @@ class LibraryItemScanner {
return this.scanNewLibraryItem(libraryItemScanData, library.settings, scanLogger) return this.scanNewLibraryItem(libraryItemScanData, library.settings, scanLogger)
} }
} }
module.exports = new LibraryItemScanner() module.exports = new LibraryItemScanner()

View file

@ -18,7 +18,6 @@ class LibraryScan {
this.startedAt = null this.startedAt = null
this.finishedAt = null this.finishedAt = null
this.elapsed = null this.elapsed = null
this.error = null
this.resultsMissing = 0 this.resultsMissing = 0
this.resultsAdded = 0 this.resultsAdded = 0
@ -55,22 +54,6 @@ class LibraryScan {
get elapsedTimestamp() { get elapsedTimestamp() {
return secondsToTimestamp(this.elapsed / 1000) return secondsToTimestamp(this.elapsed / 1000)
} }
get getScanEmitData() {
return {
id: this.libraryId,
type: this.type,
name: this.libraryName,
error: this.error,
results: {
added: this.resultsAdded,
updated: this.resultsUpdated,
missing: this.resultsMissing
}
}
}
get totalResults() {
return this.resultsAdded + this.resultsUpdated + this.resultsMissing
}
get logFilename() { get logFilename() {
return date.format(new Date(), 'YYYY-MM-DD') + '_' + this.id + '.txt' return date.format(new Date(), 'YYYY-MM-DD') + '_' + this.id + '.txt'
} }
@ -79,10 +62,19 @@ class LibraryScan {
if (this.resultsAdded) strs.push(`${this.resultsAdded} added`) if (this.resultsAdded) strs.push(`${this.resultsAdded} added`)
if (this.resultsUpdated) strs.push(`${this.resultsUpdated} updated`) if (this.resultsUpdated) strs.push(`${this.resultsUpdated} updated`)
if (this.resultsMissing) strs.push(`${this.resultsMissing} missing`) if (this.resultsMissing) strs.push(`${this.resultsMissing} missing`)
const changesDetected = strs.length > 0 ? strs.join(', ') : 'No changes detected' const changesDetected = strs.length > 0 ? strs.join(', ') : 'No changes needed'
const timeElapsed = `(${elapsedPretty(this.elapsed / 1000)})` const timeElapsed = `(${elapsedPretty(this.elapsed / 1000)})`
const error = this.error ? `${this.error}. ` : '' return `${changesDetected} ${timeElapsed}`
return `${error}${changesDetected} ${timeElapsed}` }
get scanResults() {
return {
added: this.resultsAdded,
updated: this.resultsUpdated,
missing: this.resultsMissing,
elapsed: this.elapsed,
text: this.scanResultsString
}
} }
toJSON() { toJSON() {
@ -93,7 +85,6 @@ class LibraryScan {
startedAt: this.startedAt, startedAt: this.startedAt,
finishedAt: this.finishedAt, finishedAt: this.finishedAt,
elapsed: this.elapsed, elapsed: this.elapsed,
error: this.error,
resultsAdded: this.resultsAdded, resultsAdded: this.resultsAdded,
resultsUpdated: this.resultsUpdated, resultsUpdated: this.resultsUpdated,
resultsMissing: this.resultsMissing resultsMissing: this.resultsMissing
@ -113,14 +104,9 @@ class LibraryScan {
this.startedAt = Date.now() this.startedAt = Date.now()
} }
/** setComplete() {
*
* @param {string} error
*/
setComplete(error = null) {
this.finishedAt = Date.now() this.finishedAt = Date.now()
this.elapsed = this.finishedAt - this.startedAt this.elapsed = this.finishedAt - this.startedAt
this.error = error
} }
getLogLevelString(level) { getLogLevelString(level) {

Some files were not shown because too many files have changed in this diff Show more