mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-06-06 10:42:44 +02:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b41db23994 | |||
| 125f265f55 | |||
| aa4a191567 | |||
| e431ea0472 | |||
| e3388d4446 | |||
| 88879f1409 | |||
| 3e0099e8d9 | |||
| f558182d94 | |||
| a30fe15b10 | |||
| 0bbf8bde5c | |||
| 0e2cdde731 | |||
| bc6bfbe804 | |||
| 2755204168 | |||
| 2d4df273f0 | |||
| d73b64a19c | |||
| b7e8a0474a | |||
| 39adefb632 | |||
| 24cab79c66 | |||
| b27f21fd95 | |||
| 09fa0b38f5 | |||
| 455e605162 | |||
| 88667d00a1 | |||
| 94c426bd97 | |||
| 522b9735e2 | |||
| 64cbf59609 | |||
| fda1a6ea9b | |||
| c4c8b8d0f2 | |||
| ab3bd6f4a1 | |||
| 093124aac6 | |||
| 5de92d08f9 | |||
| 8b89b27654 | |||
| 3faa6f3e7d | |||
| 9821c31f8e | |||
| efe2a22674 | |||
| 9634c46bc5 | |||
| 5f8db24b96 | |||
| e781ff5eae | |||
| 32a17c0044 | |||
| f84831d6f1 | |||
| dc54d42dcf | |||
| 15af7407ff | |||
| 5d9682410a | |||
| 4bdd76d94c | |||
| 7c0d9efe91 | |||
| 874e9e1856 | |||
| d9355ac3aa |
@@ -196,6 +196,7 @@ export default {
|
|||||||
requestBatchQuickEmbed() {
|
requestBatchQuickEmbed() {
|
||||||
const payload = {
|
const payload = {
|
||||||
message: this.$strings.MessageConfirmQuickEmbed,
|
message: this.$strings.MessageConfirmQuickEmbed,
|
||||||
|
allowHtml: true,
|
||||||
callback: (confirmed) => {
|
callback: (confirmed) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$axios
|
this.$axios
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ export default {
|
|||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.error('Failed to create collection', error)
|
console.error('Failed to create collection', error)
|
||||||
var errMsg = error.response ? error.response.data || '' : ''
|
var errMsg = error.response ? error.response.data || '' : ''
|
||||||
this.$toast.error(this.$strings.ToastCollectionCreateFailed + ': ' + errMsg)
|
this.$toast.error(errMsg)
|
||||||
this.processing = false
|
this.processing = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ export default {
|
|||||||
quickEmbed() {
|
quickEmbed() {
|
||||||
const payload = {
|
const payload = {
|
||||||
message: this.$strings.MessageConfirmQuickEmbed,
|
message: this.$strings.MessageConfirmQuickEmbed,
|
||||||
|
allowHtml: true,
|
||||||
callback: (confirmed) => {
|
callback: (confirmed) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$axios
|
this.$axios
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-linear-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
<div class="absolute top-0 left-0 right-0 w-full h-36 bg-linear-to-t from-transparent via-black-500 to-black-700 opacity-90 pointer-events-none" />
|
||||||
<div ref="content" class="relative text-white" :style="{ height: modalHeight, width: modalWidth }" v-click-outside="clickedOutside">
|
<div ref="content" class="relative text-white" :style="{ height: modalHeight, width: modalWidth }" v-click-outside="clickedOutside">
|
||||||
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
<div class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
|
||||||
<p id="confirm-prompt-message" class="text-lg mb-6 mt-2 px-1" v-html="message" />
|
<p v-if="allowHtmlMessage" id="confirm-prompt-message" class="text-lg mb-6 mt-2 px-1" v-html="sanitizedMessage" />
|
||||||
|
<p v-else id="confirm-prompt-message" class="text-lg mb-6 mt-2 px-1">{{ message }}</p>
|
||||||
|
|
||||||
<ui-checkbox v-if="checkboxLabel" v-model="checkboxValue" checkbox-bg="bg" :label="checkboxLabel" label-class="pl-2 text-base" class="mb-6 px-1" />
|
<ui-checkbox v-if="checkboxLabel" v-model="checkboxValue" checkbox-bg="bg" :label="checkboxLabel" label-class="pl-2 text-base" class="mb-6 px-1" />
|
||||||
|
|
||||||
@@ -52,6 +53,17 @@ export default {
|
|||||||
message() {
|
message() {
|
||||||
return this.confirmPromptOptions.message || ''
|
return this.confirmPromptOptions.message || ''
|
||||||
},
|
},
|
||||||
|
allowHtmlMessage() {
|
||||||
|
return !!this.confirmPromptOptions.allowHtml
|
||||||
|
},
|
||||||
|
sanitizedMessage() {
|
||||||
|
if (!this.allowHtmlMessage) return this.message
|
||||||
|
|
||||||
|
return this.escapeHtml(this.message)
|
||||||
|
.replace(/<br\s*\/?>/gi, '<br>')
|
||||||
|
.replace(/<code>/gi, '<code>')
|
||||||
|
.replace(/<\/code>/gi, '</code>')
|
||||||
|
},
|
||||||
callback() {
|
callback() {
|
||||||
return this.confirmPromptOptions.callback
|
return this.confirmPromptOptions.callback
|
||||||
},
|
},
|
||||||
@@ -103,6 +115,14 @@ export default {
|
|||||||
if (this.callback) this.callback(true, this.checkboxValue)
|
if (this.callback) this.callback(true, this.checkboxValue)
|
||||||
this.show = false
|
this.show = false
|
||||||
},
|
},
|
||||||
|
escapeHtml(value) {
|
||||||
|
return String(value)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
},
|
||||||
setShow() {
|
setShow() {
|
||||||
this.checkboxValue = this.checkboxDefaultValue
|
this.checkboxValue = this.checkboxDefaultValue
|
||||||
this.$eventBus.$emit('showing-prompt', true)
|
this.$eventBus.$emit('showing-prompt', true)
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nuxtjs/axios": "^5.13.6",
|
"@nuxtjs/axios": "^5.13.6",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf-client",
|
"name": "audiobookshelf-client",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast client",
|
"description": "Self-hosted audiobook and podcast client",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -390,8 +390,8 @@ export default {
|
|||||||
},
|
},
|
||||||
purgeItemsCache() {
|
purgeItemsCache() {
|
||||||
const payload = {
|
const payload = {
|
||||||
// message: `This will delete the entire folder at <code>/metadata/cache/items</code>.<br />Are you sure you want to purge items cache?`,
|
|
||||||
message: this.$strings.MessageConfirmPurgeItemsCache,
|
message: this.$strings.MessageConfirmPurgeItemsCache,
|
||||||
|
allowHtml: true,
|
||||||
callback: (confirmed) => {
|
callback: (confirmed) => {
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.sendPurgeItemsCache()
|
this.sendPurgeItemsCache()
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ export default {
|
|||||||
|
|
||||||
let message = this.$getString('MessageConfirmRenameGenre', [this.editingGenre, this.newGenreName])
|
let message = this.$getString('MessageConfirmRenameGenre', [this.editingGenre, this.newGenreName])
|
||||||
if (genreNameExists) {
|
if (genreNameExists) {
|
||||||
message += `<br><span class="text-sm">${this.$strings.MessageConfirmRenameGenreMergeNote}</span>`
|
message += ` ${this.$strings.MessageConfirmRenameGenreMergeNote}`
|
||||||
} else if (genreNameExistsOfDifferentCase) {
|
} else if (genreNameExistsOfDifferentCase) {
|
||||||
message += `<br><span class="text-warning text-sm">${this.$getString('MessageConfirmRenameGenreWarning', [genreNameExistsOfDifferentCase])}</span>`
|
message += ` ${this.$getString('MessageConfirmRenameGenreWarning', [genreNameExistsOfDifferentCase])}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|||||||
@@ -86,9 +86,9 @@ export default {
|
|||||||
|
|
||||||
let message = this.$getString('MessageConfirmRenameTag', [this.editingTag, this.newTagName])
|
let message = this.$getString('MessageConfirmRenameTag', [this.editingTag, this.newTagName])
|
||||||
if (tagNameExists) {
|
if (tagNameExists) {
|
||||||
message += `<br><span class="text-sm">${this.$strings.MessageConfirmRenameTagMergeNote}</span>`
|
message += ` ${this.$strings.MessageConfirmRenameTagMergeNote}`
|
||||||
} else if (tagNameExistsOfDifferentCase) {
|
} else if (tagNameExistsOfDifferentCase) {
|
||||||
message += `<br><span class="text-warning text-sm">${this.$getString('MessageConfirmRenameTagWarning', [tagNameExistsOfDifferentCase])}</span>`
|
message += ` ${this.$getString('MessageConfirmRenameTagWarning', [tagNameExistsOfDifferentCase])}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
|
|||||||
@@ -46,7 +46,20 @@ export default class LocalAudioPlayer extends EventEmitter {
|
|||||||
this.player.addEventListener('loadedmetadata', this.evtLoadedMetadata.bind(this))
|
this.player.addEventListener('loadedmetadata', this.evtLoadedMetadata.bind(this))
|
||||||
this.player.addEventListener('timeupdate', this.evtTimeupdate.bind(this))
|
this.player.addEventListener('timeupdate', this.evtTimeupdate.bind(this))
|
||||||
|
|
||||||
var mimeTypes = ['audio/flac', 'audio/mpeg', 'audio/mp4', 'audio/ogg', 'audio/aac', 'audio/x-ms-wma', 'audio/x-aiff', 'audio/webm']
|
var mimeTypes = [
|
||||||
|
'audio/flac',
|
||||||
|
'audio/mpeg',
|
||||||
|
'audio/mp4',
|
||||||
|
'audio/ogg',
|
||||||
|
'audio/aac',
|
||||||
|
'audio/x-ms-wma',
|
||||||
|
'audio/x-aiff',
|
||||||
|
'audio/webm',
|
||||||
|
// `audio/matroska` is the correct mimetype, but the server still uses `audio/x-matroska`
|
||||||
|
// ref: https://www.iana.org/assignments/media-types/media-types.xhtml
|
||||||
|
'audio/matroska',
|
||||||
|
'audio/x-matroska'
|
||||||
|
]
|
||||||
var mimeTypeCanPlayMap = {}
|
var mimeTypeCanPlayMap = {}
|
||||||
mimeTypes.forEach((mt) => {
|
mimeTypes.forEach((mt) => {
|
||||||
var canPlay = this.player.canPlayType(mt)
|
var canPlay = this.player.canPlayType(mt)
|
||||||
|
|||||||
+35
-35
@@ -16,7 +16,7 @@
|
|||||||
"ButtonBrowseForFolder": "Агляд папак",
|
"ButtonBrowseForFolder": "Агляд папак",
|
||||||
"ButtonCancel": "Скасаваць",
|
"ButtonCancel": "Скасаваць",
|
||||||
"ButtonCancelEncode": "Скасаваць кадзіраванне",
|
"ButtonCancelEncode": "Скасаваць кадзіраванне",
|
||||||
"ButtonChangeRootPassword": "Зменіце Root пароль",
|
"ButtonChangeRootPassword": "Змяніць пароль root",
|
||||||
"ButtonCheckAndDownloadNewEpisodes": "Праверыць і спампаваць новыя выпускі",
|
"ButtonCheckAndDownloadNewEpisodes": "Праверыць і спампаваць новыя выпускі",
|
||||||
"ButtonChooseAFolder": "Выбраць папку",
|
"ButtonChooseAFolder": "Выбраць папку",
|
||||||
"ButtonChooseFiles": "Выбраць файлы",
|
"ButtonChooseFiles": "Выбраць файлы",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"ButtonManageTracks": "Кіраванне трэкамі",
|
"ButtonManageTracks": "Кіраванне трэкамі",
|
||||||
"ButtonMapChapterTitles": "Супаставіць загалоўкі раздзелаў",
|
"ButtonMapChapterTitles": "Супаставіць загалоўкі раздзелаў",
|
||||||
"ButtonMatchAllAuthors": "Супадзенне ўсіх аўтараў",
|
"ButtonMatchAllAuthors": "Супадзенне ўсіх аўтараў",
|
||||||
"ButtonMatchBooks": "Падбор кніг",
|
"ButtonMatchBooks": "Параўнаць кнігі",
|
||||||
"ButtonNevermind": "Няважна",
|
"ButtonNevermind": "Няважна",
|
||||||
"ButtonNext": "Далей",
|
"ButtonNext": "Далей",
|
||||||
"ButtonNextChapter": "Наступны раздзел",
|
"ButtonNextChapter": "Наступны раздзел",
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"ButtonRemove": "Выдаліць",
|
"ButtonRemove": "Выдаліць",
|
||||||
"ButtonRemoveAll": "Выдаліць усе",
|
"ButtonRemoveAll": "Выдаліць усе",
|
||||||
"ButtonRemoveAllLibraryItems": "Выдаліць усе элементы бібліятэкі",
|
"ButtonRemoveAllLibraryItems": "Выдаліць усе элементы бібліятэкі",
|
||||||
"ButtonRemoveFromContinueListening": "Выдаліць з Працягваць слухаць",
|
"ButtonRemoveFromContinueListening": "Выдаліць з Працяг праслухоўвання",
|
||||||
"ButtonRemoveFromContinueReading": "Выдаліць з Працягваць чытанне",
|
"ButtonRemoveFromContinueReading": "Выдаліць з Працягваць чытанне",
|
||||||
"ButtonRemoveSeriesFromContinueSeries": "Выдаліць серыю з Працягваць серыю",
|
"ButtonRemoveSeriesFromContinueSeries": "Выдаліць серыю з Працягваць серыю",
|
||||||
"ButtonReset": "Скінуць",
|
"ButtonReset": "Скінуць",
|
||||||
@@ -107,10 +107,10 @@
|
|||||||
"ButtonSubmit": "Адправіць",
|
"ButtonSubmit": "Адправіць",
|
||||||
"ButtonTest": "Тэст",
|
"ButtonTest": "Тэст",
|
||||||
"ButtonUnlinkOpenId": "Адвязаць OpenID",
|
"ButtonUnlinkOpenId": "Адвязаць OpenID",
|
||||||
"ButtonUpload": "Загрузіць",
|
"ButtonUpload": "Запампаваць",
|
||||||
"ButtonUploadBackup": "Загрузіць рэзервовую копію",
|
"ButtonUploadBackup": "Запампаваць рэзервовую копію",
|
||||||
"ButtonUploadCover": "Загрузіць вокладку",
|
"ButtonUploadCover": "Запампаваць вокладку",
|
||||||
"ButtonUploadOPMLFile": "Загрузіць файл OPML",
|
"ButtonUploadOPMLFile": "Запампаваць файл OPML",
|
||||||
"ButtonUserDelete": "Выдаліць карыстальніка {0}",
|
"ButtonUserDelete": "Выдаліць карыстальніка {0}",
|
||||||
"ButtonUserEdit": "Рэдагаваць карыстальніка {0}",
|
"ButtonUserEdit": "Рэдагаваць карыстальніка {0}",
|
||||||
"ButtonViewAll": "Прагледзець усе",
|
"ButtonViewAll": "Прагледзець усе",
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
"HeaderFindChapters": "Знайсці раздзелы",
|
"HeaderFindChapters": "Знайсці раздзелы",
|
||||||
"HeaderIgnoredFiles": "Ігнараваныя файлы",
|
"HeaderIgnoredFiles": "Ігнараваныя файлы",
|
||||||
"HeaderItemFiles": "Файлы элементаў",
|
"HeaderItemFiles": "Файлы элементаў",
|
||||||
"HeaderItemMetadataUtils": "Утыліты для метаданых элементаў",
|
"HeaderItemMetadataUtils": "Утыліты для метаданых",
|
||||||
"HeaderLastListeningSession": "Апошні сеанс праслухоўвання",
|
"HeaderLastListeningSession": "Апошні сеанс праслухоўвання",
|
||||||
"HeaderLatestEpisodes": "Апошнія выпускі",
|
"HeaderLatestEpisodes": "Апошнія выпускі",
|
||||||
"HeaderLibraries": "Бібліятэкі",
|
"HeaderLibraries": "Бібліятэкі",
|
||||||
@@ -196,7 +196,7 @@
|
|||||||
"HeaderSession": "Сеанс",
|
"HeaderSession": "Сеанс",
|
||||||
"HeaderSetBackupSchedule": "Наладзіць расклад рэзервовага капіравання",
|
"HeaderSetBackupSchedule": "Наладзіць расклад рэзервовага капіравання",
|
||||||
"HeaderSettings": "Налады",
|
"HeaderSettings": "Налады",
|
||||||
"HeaderSettingsDisplay": "Дысплей",
|
"HeaderSettingsDisplay": "Выгляд",
|
||||||
"HeaderSettingsExperimental": "Эксперыментальныя функцыі",
|
"HeaderSettingsExperimental": "Эксперыментальныя функцыі",
|
||||||
"HeaderSettingsGeneral": "Агульныя",
|
"HeaderSettingsGeneral": "Агульныя",
|
||||||
"HeaderSettingsScanner": "Сканер",
|
"HeaderSettingsScanner": "Сканер",
|
||||||
@@ -207,8 +207,8 @@
|
|||||||
"HeaderStatsLongestItems": "Найдаўжэйшыя элементы (гадзіны)",
|
"HeaderStatsLongestItems": "Найдаўжэйшыя элементы (гадзіны)",
|
||||||
"HeaderStatsMinutesListeningChart": "Хвілін праслухоўвання (апошнія 7 дзён)",
|
"HeaderStatsMinutesListeningChart": "Хвілін праслухоўвання (апошнія 7 дзён)",
|
||||||
"HeaderStatsRecentSessions": "Апошнія сеансы",
|
"HeaderStatsRecentSessions": "Апошнія сеансы",
|
||||||
"HeaderStatsTop10Authors": "10 лепшых аўтараў",
|
"HeaderStatsTop10Authors": "Топ 10 аўтараў",
|
||||||
"HeaderStatsTop5Genres": "5 лепшых жанраў",
|
"HeaderStatsTop5Genres": "Топ 5 жанраў",
|
||||||
"HeaderTableOfContents": "Змест",
|
"HeaderTableOfContents": "Змест",
|
||||||
"HeaderTools": "Інструменты",
|
"HeaderTools": "Інструменты",
|
||||||
"HeaderUpdateAccount": "Абнавіць уліковы запіс",
|
"HeaderUpdateAccount": "Абнавіць уліковы запіс",
|
||||||
@@ -239,8 +239,8 @@
|
|||||||
"LabelAll": "Усе",
|
"LabelAll": "Усе",
|
||||||
"LabelAllEpisodesDownloaded": "Усе выпускі спампаваныя",
|
"LabelAllEpisodesDownloaded": "Усе выпускі спампаваныя",
|
||||||
"LabelAllUsers": "Усе карыстальнікі",
|
"LabelAllUsers": "Усе карыстальнікі",
|
||||||
"LabelAllUsersExcludingGuests": "Усе карыстальнікі, акрамя гасцей",
|
"LabelAllUsersExcludingGuests": "Усіх карыстальнікаў, акрамя гасцей",
|
||||||
"LabelAllUsersIncludingGuests": "Усе карыстальнікі, уключаючы гасцей",
|
"LabelAllUsersIncludingGuests": "Усіх карыстальнікаў, уключаючы гасцей",
|
||||||
"LabelAlreadyInYourLibrary": "Ужо ў вашай бібліятэцы",
|
"LabelAlreadyInYourLibrary": "Ужо ў вашай бібліятэцы",
|
||||||
"LabelApiKeyCreated": "API-ключ \"{0}\" паспяхова створаны.",
|
"LabelApiKeyCreated": "API-ключ \"{0}\" паспяхова створаны.",
|
||||||
"LabelApiKeyCreatedDescription": "Пераканайцеся, што вы скапіявалі API-ключ зараз, бо паўторна яго ўбачыць не атрымаецца.",
|
"LabelApiKeyCreatedDescription": "Пераканайцеся, што вы скапіявалі API-ключ зараз, бо паўторна яго ўбачыць не атрымаецца.",
|
||||||
@@ -252,8 +252,8 @@
|
|||||||
"LabelAudioChannels": "Аўдыяканалы (1 або 2)",
|
"LabelAudioChannels": "Аўдыяканалы (1 або 2)",
|
||||||
"LabelAudioCodec": "Аўдыякодэк",
|
"LabelAudioCodec": "Аўдыякодэк",
|
||||||
"LabelAuthor": "Аўтар",
|
"LabelAuthor": "Аўтар",
|
||||||
"LabelAuthorFirstLast": "Аўтар (Імя Прозвішча)",
|
"LabelAuthorFirstLast": "Аўтар (імя, прозвішча)",
|
||||||
"LabelAuthorLastFirst": "Аўтар (Прозвішча, Імя)",
|
"LabelAuthorLastFirst": "Аўтар (прозвішча, імя)",
|
||||||
"LabelAuthors": "Аўтары",
|
"LabelAuthors": "Аўтары",
|
||||||
"LabelAutoDownloadEpisodes": "Аўтаматычна спампоўваць выпускі",
|
"LabelAutoDownloadEpisodes": "Аўтаматычна спампоўваць выпускі",
|
||||||
"LabelAutoFetchMetadata": "Аўтаматычнае атрыманне метаданых",
|
"LabelAutoFetchMetadata": "Аўтаматычнае атрыманне метаданых",
|
||||||
@@ -264,7 +264,7 @@
|
|||||||
"LabelAutoRegisterDescription": "Аўтаматычна ствараць новых карыстальнікаў пасля ўваходу ў сістэму",
|
"LabelAutoRegisterDescription": "Аўтаматычна ствараць новых карыстальнікаў пасля ўваходу ў сістэму",
|
||||||
"LabelBackToUser": "Вярнуцца да карыстальніка",
|
"LabelBackToUser": "Вярнуцца да карыстальніка",
|
||||||
"LabelBackupAudioFiles": "Рэзервовае капіраванне аўдыяфайлаў",
|
"LabelBackupAudioFiles": "Рэзервовае капіраванне аўдыяфайлаў",
|
||||||
"LabelBackupLocation": "Месцазнаходжанне рэзервовых копій",
|
"LabelBackupLocation": "Размяшчэнне рэзервовых копій",
|
||||||
"LabelBackupsEnableAutomaticBackups": "Аўтаматычнае рэзервовае капіраванне",
|
"LabelBackupsEnableAutomaticBackups": "Аўтаматычнае рэзервовае капіраванне",
|
||||||
"LabelBackupsEnableAutomaticBackupsHelp": "Рэзервовыя копіі захаваныя ў /metadata/backups",
|
"LabelBackupsEnableAutomaticBackupsHelp": "Рэзервовыя копіі захаваныя ў /metadata/backups",
|
||||||
"LabelBackupsMaxBackupSize": "Максімальны памер рэзервовай копіі (у ГБ) (0 — неабмежавана)",
|
"LabelBackupsMaxBackupSize": "Максімальны памер рэзервовай копіі (у ГБ) (0 — неабмежавана)",
|
||||||
@@ -292,7 +292,7 @@
|
|||||||
"LabelCollections": "Калекцыі",
|
"LabelCollections": "Калекцыі",
|
||||||
"LabelComplete": "Завяршыць",
|
"LabelComplete": "Завяршыць",
|
||||||
"LabelConfirmPassword": "Пацвердзіце пароль",
|
"LabelConfirmPassword": "Пацвердзіце пароль",
|
||||||
"LabelContinueListening": "Працягваць слухаць",
|
"LabelContinueListening": "Працяг праслухоўвання",
|
||||||
"LabelContinueReading": "Працягнуць чытанне",
|
"LabelContinueReading": "Працягнуць чытанне",
|
||||||
"LabelContinueSeries": "Працягнуць серыі",
|
"LabelContinueSeries": "Працягнуць серыі",
|
||||||
"LabelCorsAllowed": "Дазволеныя крыніцы CORS",
|
"LabelCorsAllowed": "Дазволеныя крыніцы CORS",
|
||||||
@@ -316,7 +316,7 @@
|
|||||||
"LabelDirectory": "Каталог",
|
"LabelDirectory": "Каталог",
|
||||||
"LabelDiscFromFilename": "Дыск з файла",
|
"LabelDiscFromFilename": "Дыск з файла",
|
||||||
"LabelDiscFromMetadata": "Дыск з метаданых",
|
"LabelDiscFromMetadata": "Дыск з метаданых",
|
||||||
"LabelDiscover": "Знайсці",
|
"LabelDiscover": "Знаходкі",
|
||||||
"LabelDownload": "Спампаваць",
|
"LabelDownload": "Спампаваць",
|
||||||
"LabelDownloadNEpisodes": "Спампавана {0} выпускаў",
|
"LabelDownloadNEpisodes": "Спампавана {0} выпускаў",
|
||||||
"LabelDownloadable": "Спампоўваецца",
|
"LabelDownloadable": "Спампоўваецца",
|
||||||
@@ -332,7 +332,7 @@
|
|||||||
"LabelEmailSettingsFromAddress": "Адрас адпраўніка",
|
"LabelEmailSettingsFromAddress": "Адрас адпраўніка",
|
||||||
"LabelEmailSettingsRejectUnauthorized": "Адхіляць неаўтарызаваныя сертыфікаты",
|
"LabelEmailSettingsRejectUnauthorized": "Адхіляць неаўтарызаваныя сертыфікаты",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Адключэнне праверкі SSL-сертыфіката можа зрабіць ваша злучэнне ўразлівым перад пагрозамі бяспекі, такімі як атакі \"чалавек пасярэдзіне\". Адключайце гэтую опцыю толькі калі цалкам разумееце наступствы і ўпэўнены ў надзейнасці паштовага сервера.",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Адключэнне праверкі SSL-сертыфіката можа зрабіць ваша злучэнне ўразлівым перад пагрозамі бяспекі, такімі як атакі \"чалавек пасярэдзіне\". Адключайце гэтую опцыю толькі калі цалкам разумееце наступствы і ўпэўнены ў надзейнасці паштовага сервера.",
|
||||||
"LabelEmailSettingsSecure": "Бяспечныя",
|
"LabelEmailSettingsSecure": "Бяспечна",
|
||||||
"LabelEmailSettingsSecureHelp": "Калі ўключана, злучэнне будзе выкарыстоўваць TLS пры падключэнні да сервера. Калі выключана, TLS будзе выкарыстоўвацца толькі ў выпадку падтрымкі пашырэння STARTTLS на серверы. У большасці выпадкаў усталюйце значэнне true пры падключэнні да порта 465. Для партоў 587 або 25 не ўключайце яго. (інфармацыя з nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Калі ўключана, злучэнне будзе выкарыстоўваць TLS пры падключэнні да сервера. Калі выключана, TLS будзе выкарыстоўвацца толькі ў выпадку падтрымкі пашырэння STARTTLS на серверы. У большасці выпадкаў усталюйце значэнне true пры падключэнні да порта 465. Для партоў 587 або 25 не ўключайце яго. (інфармацыя з nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "Тэставы адрас",
|
"LabelEmailSettingsTestAddress": "Тэставы адрас",
|
||||||
"LabelEmbeddedCover": "Убудаваная вокладка",
|
"LabelEmbeddedCover": "Убудаваная вокладка",
|
||||||
@@ -424,7 +424,7 @@
|
|||||||
"LabelLastBookAdded": "Апошняя дададзеная кніга",
|
"LabelLastBookAdded": "Апошняя дададзеная кніга",
|
||||||
"LabelLastBookUpdated": "Апошняя абноўленая кніга",
|
"LabelLastBookUpdated": "Апошняя абноўленая кніга",
|
||||||
"LabelLastProgressDate": "Апошні прагрэс: {0}",
|
"LabelLastProgressDate": "Апошні прагрэс: {0}",
|
||||||
"LabelLastSeen": "Апошні прагляд",
|
"LabelLastSeen": "Апошняя актыўнасць",
|
||||||
"LabelLastTime": "Апошні раз",
|
"LabelLastTime": "Апошні раз",
|
||||||
"LabelLastUpdate": "Апошняе абнаўленне",
|
"LabelLastUpdate": "Апошняе абнаўленне",
|
||||||
"LabelLayout": "Знешні выгляд",
|
"LabelLayout": "Знешні выгляд",
|
||||||
@@ -545,7 +545,7 @@
|
|||||||
"LabelRSSFeedSlug": "Ідэнтыфікатар RSS-стужкі",
|
"LabelRSSFeedSlug": "Ідэнтыфікатар RSS-стужкі",
|
||||||
"LabelRSSFeedURL": "URL RSS-стужкі",
|
"LabelRSSFeedURL": "URL RSS-стужкі",
|
||||||
"LabelRandomly": "Выпадкова",
|
"LabelRandomly": "Выпадкова",
|
||||||
"LabelReAddSeriesToContinueListening": "Дадаць серыю зноў у Працягваць слухаць",
|
"LabelReAddSeriesToContinueListening": "Дадаць серыю зноў у Працяг праслухоўвання",
|
||||||
"LabelRead": "Чытаць",
|
"LabelRead": "Чытаць",
|
||||||
"LabelReadAgain": "Чытаць зноў",
|
"LabelReadAgain": "Чытаць зноў",
|
||||||
"LabelReadEbookWithoutProgress": "Чытаць электронную кнігу без захавання прагрэсу",
|
"LabelReadEbookWithoutProgress": "Чытаць электронную кнігу без захавання прагрэсу",
|
||||||
@@ -588,23 +588,23 @@
|
|||||||
"LabelSettingsBookshelfViewHelp": "Рэалістычны дызайн з драўлянымі паліцамі",
|
"LabelSettingsBookshelfViewHelp": "Рэалістычны дызайн з драўлянымі паліцамі",
|
||||||
"LabelSettingsChromecastSupport": "Падтрымка Chromecast",
|
"LabelSettingsChromecastSupport": "Падтрымка Chromecast",
|
||||||
"LabelSettingsDateFormat": "Фарматы даты",
|
"LabelSettingsDateFormat": "Фарматы даты",
|
||||||
"LabelSettingsEnableWatcher": "Аўтаматычна сачыць за зменамі ў бібліятэцках",
|
"LabelSettingsEnableWatcher": "Аўтаматычна сачыць за зменамі ў бібліятэках",
|
||||||
"LabelSettingsEnableWatcherForLibrary": "Аўтаматычна сачыць за зменамі ў бібліятэцы",
|
"LabelSettingsEnableWatcherForLibrary": "Аўтаматычна сачыць за зменамі ў бібліятэцы",
|
||||||
"LabelSettingsEnableWatcherHelp": "Адключае аўтаматычнае дадаванне/абнаўленне элементаў пры выяўленні змен у файлах. *Патрабуецца перазапуск сервера",
|
"LabelSettingsEnableWatcherHelp": "Адключае аўтаматычнае дадаванне/абнаўленне элементаў пры выяўленні змен у файлах. *Патрабуецца перазапуск сервера",
|
||||||
"LabelSettingsEpubsAllowScriptedContent": "Дазваляць скрыпты ў файлах EPUB",
|
"LabelSettingsEpubsAllowScriptedContent": "Дазваляць скрыпты ў файлах EPUB",
|
||||||
"LabelSettingsEpubsAllowScriptedContentHelp": "Дазволіць файлам EPUB выконваць скрыпты. Рэкамендуецца пакінуць гэтую наладу выключанай, калі вы не давяраеце крыніцы файлаў EPUB.",
|
"LabelSettingsEpubsAllowScriptedContentHelp": "Дазволіць файлам EPUB выконваць скрыпты. Рэкамендуецца пакінуць гэтую наладу выключанай, калі вы не давяраеце крыніцы файлаў EPUB.",
|
||||||
"LabelSettingsExperimentalFeatures": "Эксперыментальныя функцыі",
|
"LabelSettingsExperimentalFeatures": "Эксперыментальныя функцыі",
|
||||||
"LabelSettingsExperimentalFeaturesHelp": "Функцыі ў распрацоўцы, для якіх вашы водгукі і дапамога ў тэставанні будуць карыснымі. Націсніце, каб адкрыць абмеркаванне на GitHub.",
|
"LabelSettingsExperimentalFeaturesHelp": "Функцыі ў распрацоўцы, для якіх вашы водгукі і дапамога ў тэставанні будуць карыснымі. Націсніце, каб адкрыць абмеркаванне на GitHub.",
|
||||||
"LabelSettingsFindCovers": "Знайсці вокладкі",
|
"LabelSettingsFindCovers": "Шукаць вокладкі",
|
||||||
"LabelSettingsFindCoversHelp": "Калі ў вашай аўдыякнізе няма ўбудаванай вокладкі або відарыса вокладкі ў папцы, сканер паспрабуе знайсці вокладку.<br>Заўвага: гэта павялічыць час сканіравання",
|
"LabelSettingsFindCoversHelp": "Калі ў вашай аўдыякнізе няма ўбудаванай вокладкі або відарыса вокладкі ў папцы, сканер паспрабуе знайсці вокладку.<br>Заўвага: гэта павялічыць час сканіравання",
|
||||||
"LabelSettingsHideSingleBookSeries": "Схаваць серыі з адной кнігай",
|
"LabelSettingsHideSingleBookSeries": "Схаваць серыі з адной кнігай",
|
||||||
"LabelSettingsHideSingleBookSeriesHelp": "Серыі, якія змяшчаюць толькі адну кнігу, будуць схаваны са старонкі серый і паліц на галоўнай старонцы.",
|
"LabelSettingsHideSingleBookSeriesHelp": "Серыі, якія змяшчаюць толькі адну кнігу, будуць схаваны са старонкі серый і паліц на галоўнай старонцы.",
|
||||||
"LabelSettingsHomePageBookshelfView": "Галоўная старонка выкарыстоўвае выгляд кніжнай паліцы",
|
"LabelSettingsHomePageBookshelfView": "Кніжныя паліцы на галоўнай старонцы",
|
||||||
"LabelSettingsLibraryBookshelfView": "Бібліятэка выкарыстоўвае выгляд кніжнай паліцы",
|
"LabelSettingsLibraryBookshelfView": "Кніжныя паліцы ў бібліятэцы",
|
||||||
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Працэнт завяршэння большы за",
|
"LabelSettingsLibraryMarkAsFinishedPercentComplete": "Працэнт завяршэння большы за",
|
||||||
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Час, што застаўся, менш за (секунд)",
|
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Час, што застаўся, меншы за (секунд)",
|
||||||
"LabelSettingsLibraryMarkAsFinishedWhen": "Пазначыць элемент медыя як завершаны, калі",
|
"LabelSettingsLibraryMarkAsFinishedWhen": "Пазначыць элемент медыя як завершаны, калі",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Пропусціць папярэднія кнігі ў \"Працягнуць серыю\"",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Прапусціць папярэднія кнігі ў \"Працягнуць серыю\"",
|
||||||
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Паліца \"Працягнуць серыю\" на галоўнай старонцы паказвае першую не пачатую кнігу ў серыях, дзе завершана хаця б адна кніга і няма кніг у працэсе чытання. Уключэнне гэтай налады дазволіць працягваць серыю з самай апошняй завершанай кнігі замест першай не пачатай.",
|
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Паліца \"Працягнуць серыю\" на галоўнай старонцы паказвае першую не пачатую кнігу ў серыях, дзе завершана хаця б адна кніга і няма кніг у працэсе чытання. Уключэнне гэтай налады дазволіць працягваць серыю з самай апошняй завершанай кнігі замест першай не пачатай.",
|
||||||
"LabelSettingsParseSubtitles": "Аналізаваць падзагалоўкі",
|
"LabelSettingsParseSubtitles": "Аналізаваць падзагалоўкі",
|
||||||
"LabelSettingsParseSubtitlesHelp": "Выдзяляць падзагаловак з назваў папак аўдыякніг.<br>Падзагаловак павінен быць аддзелены сімвалам \" - \".<br>Напрыклад, \"Назва кнігі - Падзагаловак тут\" мае падзагаловак \"Падзагаловак тут\"",
|
"LabelSettingsParseSubtitlesHelp": "Выдзяляць падзагаловак з назваў папак аўдыякніг.<br>Падзагаловак павінен быць аддзелены сімвалам \" - \".<br>Напрыклад, \"Назва кнігі - Падзагаловак тут\" мае падзагаловак \"Падзагаловак тут\"",
|
||||||
@@ -618,7 +618,7 @@
|
|||||||
"LabelSettingsSquareBookCoversHelp": "Аддаваць перавагу квадратным вокладкам замест стандартных вокладак з суадносінамі бакоў 1.6:1",
|
"LabelSettingsSquareBookCoversHelp": "Аддаваць перавагу квадратным вокладкам замест стандартных вокладак з суадносінамі бакоў 1.6:1",
|
||||||
"LabelSettingsStoreCoversWithItem": "Захоўваць вокладкі з элементам",
|
"LabelSettingsStoreCoversWithItem": "Захоўваць вокладкі з элементам",
|
||||||
"LabelSettingsStoreCoversWithItemHelp": "Прадвызначана вокладкі захоўваюцца ў /metadata/items, уключэнне гэтай опцыі забяспечыць захоўванне вокладак у папцы элемента бібліятэкі. Захоўвацца будзе толькі адзін файл з назвай \"cover\"",
|
"LabelSettingsStoreCoversWithItemHelp": "Прадвызначана вокладкі захоўваюцца ў /metadata/items, уключэнне гэтай опцыі забяспечыць захоўванне вокладак у папцы элемента бібліятэкі. Захоўвацца будзе толькі адзін файл з назвай \"cover\"",
|
||||||
"LabelSettingsStoreMetadataWithItem": "Захоўваць метаданыя разам з элементам",
|
"LabelSettingsStoreMetadataWithItem": "Захоўваць метаданыя з элементам",
|
||||||
"LabelSettingsStoreMetadataWithItemHelp": "Прадвызначана метаданыя захоўваюцца ў /metadata/items. Пры ўключэнні гэтай опцыі файлаў метаданых будуць захоўвацца ў папках элементаў бібліятэкі",
|
"LabelSettingsStoreMetadataWithItemHelp": "Прадвызначана метаданыя захоўваюцца ў /metadata/items. Пры ўключэнні гэтай опцыі файлаў метаданых будуць захоўвацца ў папках элементаў бібліятэкі",
|
||||||
"LabelSettingsTimeFormat": "Фармат часу",
|
"LabelSettingsTimeFormat": "Фармат часу",
|
||||||
"LabelShare": "Абагуліць",
|
"LabelShare": "Абагуліць",
|
||||||
@@ -634,14 +634,14 @@
|
|||||||
"LabelSortAscending": "Па ўзрастанні",
|
"LabelSortAscending": "Па ўзрастанні",
|
||||||
"LabelSortDescending": "Па ўбыванні",
|
"LabelSortDescending": "Па ўбыванні",
|
||||||
"LabelSortPubDate": "Сартаваць па даце публікацыі",
|
"LabelSortPubDate": "Сартаваць па даце публікацыі",
|
||||||
"LabelStart": "Пачаць",
|
"LabelStart": "Пачатак",
|
||||||
"LabelStartTime": "Час пачатку",
|
"LabelStartTime": "Час пачатку",
|
||||||
"LabelStarted": "Пачата",
|
"LabelStarted": "Пачата",
|
||||||
"LabelStartedAt": "Пачата ў",
|
"LabelStartedAt": "Пачата ў",
|
||||||
"LabelStartedDate": "Пачата {0}",
|
"LabelStartedDate": "Пачата {0}",
|
||||||
"LabelStatsAudioTracks": "Аўдыятрэкі",
|
"LabelStatsAudioTracks": "Аўдыятрэкі",
|
||||||
"LabelStatsAuthors": "Аўтары",
|
"LabelStatsAuthors": "Аўтараў",
|
||||||
"LabelStatsBestDay": "Лепшы дзень",
|
"LabelStatsBestDay": "Найлепшы дзень",
|
||||||
"LabelStatsDailyAverage": "У сярэднім за дзень",
|
"LabelStatsDailyAverage": "У сярэднім за дзень",
|
||||||
"LabelStatsDays": "Дзён",
|
"LabelStatsDays": "Дзён",
|
||||||
"LabelStatsDaysListened": "Дзён праслухана",
|
"LabelStatsDaysListened": "Дзён праслухана",
|
||||||
@@ -655,7 +655,7 @@
|
|||||||
"LabelStatsOverallHours": "Агульная колькасць гадзін",
|
"LabelStatsOverallHours": "Агульная колькасць гадзін",
|
||||||
"LabelStatsWeekListening": "Праслухана за тыдзень",
|
"LabelStatsWeekListening": "Праслухана за тыдзень",
|
||||||
"LabelSubtitle": "Падзагаловак",
|
"LabelSubtitle": "Падзагаловак",
|
||||||
"LabelSupportedFileTypes": "Падтрымліваемыя тыпы файлаў",
|
"LabelSupportedFileTypes": "Падтрымліваюцца тыпы файлаў",
|
||||||
"LabelTag": "Метка",
|
"LabelTag": "Метка",
|
||||||
"LabelTags": "Меткі",
|
"LabelTags": "Меткі",
|
||||||
"LabelTagsAccessibleToUser": "Меткі, даступныя карыстальніку",
|
"LabelTagsAccessibleToUser": "Меткі, даступныя карыстальніку",
|
||||||
@@ -742,7 +742,7 @@
|
|||||||
"MessageAuthenticationSecurityMessage": "Дзеля бяспекі была палепшана аўтэнтыфікацыя. Усім карыстальнікам трэба паўторна ўвайсці ў сістэму.",
|
"MessageAuthenticationSecurityMessage": "Дзеля бяспекі была палепшана аўтэнтыфікацыя. Усім карыстальнікам трэба паўторна ўвайсці ў сістэму.",
|
||||||
"MessageBackupsDescription": "Рэзервовыя копіі ўключаюць карыстальнікаў, іх прагрэс, падрабязнасці элементаў бібліятэкі, налады сервера і відарысы, якія захоўваюцца ў <code>/metadata/items</code> і <code>/metadata/authors</code>. Рэзервовыя копіі <strong>не</strong> ўключаюць файлы, якія захоўваюцца ў папках бібліятэкі.",
|
"MessageBackupsDescription": "Рэзервовыя копіі ўключаюць карыстальнікаў, іх прагрэс, падрабязнасці элементаў бібліятэкі, налады сервера і відарысы, якія захоўваюцца ў <code>/metadata/items</code> і <code>/metadata/authors</code>. Рэзервовыя копіі <strong>не</strong> ўключаюць файлы, якія захоўваюцца ў папках бібліятэкі.",
|
||||||
"MessageBackupsLocationEditNote": "Заўвага: Абнаўленне месцазнаходжання рэзервовых копій не перамяшчае і не змяняе існуючыя рэзервовыя копіі",
|
"MessageBackupsLocationEditNote": "Заўвага: Абнаўленне месцазнаходжання рэзервовых копій не перамяшчае і не змяняе існуючыя рэзервовыя копіі",
|
||||||
"MessageBackupsLocationNoEditNote": "Заўвага: Месцазнаходжанне рэзервовых копій задаецца праз зменную асяроддзя і не можа быць зменена тут.",
|
"MessageBackupsLocationNoEditNote": "Заўвага: Размяшчэнне рэзервовых копій задаецца праз зменную асяроддзя і не можа быць зменена тут.",
|
||||||
"MessageBackupsLocationPathEmpty": "Шлях да месцазнаходжання рэзервовых копій не можа быць пустым",
|
"MessageBackupsLocationPathEmpty": "Шлях да месцазнаходжання рэзервовых копій не можа быць пустым",
|
||||||
"MessageBatchEditPopulateMapDetailsAllHelp": "Запоўніце ўключаныя палі данымі з усіх элементаў. Палі з некалькімі значэннямі будуць аб'яднаны",
|
"MessageBatchEditPopulateMapDetailsAllHelp": "Запоўніце ўключаныя палі данымі з усіх элементаў. Палі з некалькімі значэннямі будуць аб'яднаны",
|
||||||
"MessageBatchEditPopulateMapDetailsItemHelp": "Запоўніце ўключаныя палі падрабязнасцей карты данымі з гэтага элемента",
|
"MessageBatchEditPopulateMapDetailsItemHelp": "Запоўніце ўключаныя палі падрабязнасцей карты данымі з гэтага элемента",
|
||||||
@@ -968,7 +968,7 @@
|
|||||||
"StatsBooksAdditional": "Некаторыя дапаўненні ўключаюць…",
|
"StatsBooksAdditional": "Некаторыя дапаўненні ўключаюць…",
|
||||||
"StatsBooksFinished": "завершана кніг",
|
"StatsBooksFinished": "завершана кніг",
|
||||||
"StatsBooksFinishedThisYear": "Некаторыя кнігі завершаны ў гэтым годзе…",
|
"StatsBooksFinishedThisYear": "Некаторыя кнігі завершаны ў гэтым годзе…",
|
||||||
"StatsBooksListenedTo": "кнігі, якія былі праслуханы",
|
"StatsBooksListenedTo": "кніг праслухана",
|
||||||
"StatsCollectionGrewTo": "Ваша калекцыя кніг павялічылася да…",
|
"StatsCollectionGrewTo": "Ваша калекцыя кніг павялічылася да…",
|
||||||
"StatsSessions": "сеансаў",
|
"StatsSessions": "сеансаў",
|
||||||
"StatsSpentListening": "праслухана",
|
"StatsSpentListening": "праслухана",
|
||||||
@@ -1147,7 +1147,7 @@
|
|||||||
"ToastUnlinkOpenIdFailed": "Не ўдалося адвязаць карыстальніка ад OpenID",
|
"ToastUnlinkOpenIdFailed": "Не ўдалося адвязаць карыстальніка ад OpenID",
|
||||||
"ToastUnlinkOpenIdSuccess": "Карыстальнік адвязаны ад OpenID",
|
"ToastUnlinkOpenIdSuccess": "Карыстальнік адвязаны ад OpenID",
|
||||||
"ToastUploaderFilepathExistsError": "Файл \"{0}\" ужо існуе на серверы",
|
"ToastUploaderFilepathExistsError": "Файл \"{0}\" ужо існуе на серверы",
|
||||||
"ToastUploaderItemExistsInSubdirectoryError": "Элемент \"{0}\" выкарыстоўвае падкаталог шляху загрузкі.",
|
"ToastUploaderItemExistsInSubdirectoryError": "Элемент \"{0}\" выкарыстоўвае падкаталог шляху запампоўкі.",
|
||||||
"ToastUserDeleteFailed": "Не ўдалося выдаліць карыстальніка",
|
"ToastUserDeleteFailed": "Не ўдалося выдаліць карыстальніка",
|
||||||
"ToastUserDeleteSuccess": "Карыстальнік выдалены",
|
"ToastUserDeleteSuccess": "Карыстальнік выдалены",
|
||||||
"ToastUserPasswordChangeSuccess": "Пароль паспяхова зменены",
|
"ToastUserPasswordChangeSuccess": "Пароль паспяхова зменены",
|
||||||
|
|||||||
+36
-2
@@ -436,7 +436,7 @@
|
|||||||
"LabelLibraryFilterSublistEmpty": "Не {0}",
|
"LabelLibraryFilterSublistEmpty": "Не {0}",
|
||||||
"LabelLibraryItem": "Елемент на Библиотека",
|
"LabelLibraryItem": "Елемент на Библиотека",
|
||||||
"LabelLibraryName": "Име на Библиотека",
|
"LabelLibraryName": "Име на Библиотека",
|
||||||
"LabelLibrarySortByProgress": "Прогрес: Последно Обновен",
|
"LabelLibrarySortByProgress": "Прогрес: Последно обновление",
|
||||||
"LabelLibrarySortByProgressFinished": "Прогрес: Приключено",
|
"LabelLibrarySortByProgressFinished": "Прогрес: Приключено",
|
||||||
"LabelLibrarySortByProgressStarted": "Прогрес: Започнато",
|
"LabelLibrarySortByProgressStarted": "Прогрес: Започнато",
|
||||||
"LabelLimit": "Лимит",
|
"LabelLimit": "Лимит",
|
||||||
@@ -892,7 +892,7 @@
|
|||||||
"MessageScheduleRunEveryWeekdayAtTime": "Изпълни всеки {0} в {1}",
|
"MessageScheduleRunEveryWeekdayAtTime": "Изпълни всеки {0} в {1}",
|
||||||
"MessageSearchResultsFor": "Резултати от търсенето за",
|
"MessageSearchResultsFor": "Резултати от търсенето за",
|
||||||
"MessageSelected": "{0} избрани",
|
"MessageSelected": "{0} избрани",
|
||||||
"MessageSeriesSequenceCannotContainSpaces": "Подредбата в серия не може да съдържа шпации.",
|
"MessageSeriesSequenceCannotContainSpaces": "Подредбата в серия не може да съдържа шпации",
|
||||||
"MessageServerCouldNotBeReached": "Сървърът не може да бъде достигнат",
|
"MessageServerCouldNotBeReached": "Сървърът не може да бъде достигнат",
|
||||||
"MessageSetChaptersFromTracksDescription": "Задайте глави, като използвате всеки аудио файл като глава и заглавие на главата като име на аудио файла",
|
"MessageSetChaptersFromTracksDescription": "Задайте глави, като използвате всеки аудио файл като глава и заглавие на главата като име на аудио файла",
|
||||||
"MessageShareExpirationWillBe": "Изтичането ще бъде на <strong>{0}</strong>",
|
"MessageShareExpirationWillBe": "Изтичането ще бъде на <strong>{0}</strong>",
|
||||||
@@ -956,6 +956,8 @@
|
|||||||
"NotificationOnEpisodeDownloadedDescription": "Изпълнява се при автоматично изтегляне на подкаст епизод",
|
"NotificationOnEpisodeDownloadedDescription": "Изпълнява се при автоматично изтегляне на подкаст епизод",
|
||||||
"NotificationOnRSSFeedDisabledDescription": "Изпълнява се, когато автоматичното изтегляне на епизодите е деактивирано, поради твърде много неуспешни опити",
|
"NotificationOnRSSFeedDisabledDescription": "Изпълнява се, когато автоматичното изтегляне на епизодите е деактивирано, поради твърде много неуспешни опити",
|
||||||
"NotificationOnRSSFeedFailedDescription": "Пуска се когато заявката за RSS фийд е неуспешна за автоматично сваляне на епизод",
|
"NotificationOnRSSFeedFailedDescription": "Пуска се когато заявката за RSS фийд е неуспешна за автоматично сваляне на епизод",
|
||||||
|
"NotificationOnTestDescription": "Event за тестване на системата за нотификации",
|
||||||
|
"PlaceholderBulkChapterInput": "Въведете име на глава или използвайте номериране (прим. 'Епизод 1', 'Глава 10', '1.')",
|
||||||
"PlaceholderNewCollection": "Ново име на колекцията",
|
"PlaceholderNewCollection": "Ново име на колекцията",
|
||||||
"PlaceholderNewFolderPath": "Нов път на папката",
|
"PlaceholderNewFolderPath": "Нов път на папката",
|
||||||
"PlaceholderNewPlaylist": "Ново име на плейлиста",
|
"PlaceholderNewPlaylist": "Ново име на плейлиста",
|
||||||
@@ -963,26 +965,58 @@
|
|||||||
"PlaceholderSearchEpisode": "Търсене на Епизоди...",
|
"PlaceholderSearchEpisode": "Търсене на Епизоди...",
|
||||||
"StatsAuthorsAdded": "добаврени автори",
|
"StatsAuthorsAdded": "добаврени автори",
|
||||||
"StatsBooksAdded": "добавени книги",
|
"StatsBooksAdded": "добавени книги",
|
||||||
|
"StatsBooksAdditional": "Някой от вкючените добавки…",
|
||||||
"StatsBooksFinished": "завършени книги",
|
"StatsBooksFinished": "завършени книги",
|
||||||
|
"StatsBooksFinishedThisYear": "Някой от книгите приключени тази година…",
|
||||||
|
"StatsBooksListenedTo": "слушани книги",
|
||||||
|
"StatsCollectionGrewTo": "Твоята книжна колекция израсна до…",
|
||||||
|
"StatsSessions": "сесии",
|
||||||
|
"StatsSpentListening": "прекарано в слушане",
|
||||||
|
"StatsTopAuthor": "ТОП АВТОР",
|
||||||
|
"StatsTopAuthors": "ТОП АВТОРИ",
|
||||||
|
"StatsTopGenre": "ТОП ЖАНР",
|
||||||
|
"StatsTopGenres": "ТОП ЖАНРА",
|
||||||
|
"StatsTopMonth": "ТОП МЕСЕЦ",
|
||||||
|
"StatsTopNarrator": "ТОП РАЗКАЗВАЧ",
|
||||||
|
"StatsTopNarrators": "ТОП РАЗКАЗВАЧИ",
|
||||||
|
"StatsTotalDuration": "С пълно времетраене…",
|
||||||
|
"StatsYearInReview": "ГОДИНАТА В ПРЕГЛЕД",
|
||||||
"ToastAccountUpdateSuccess": "Успешно обновяване на акаунта",
|
"ToastAccountUpdateSuccess": "Успешно обновяване на акаунта",
|
||||||
|
"ToastAppriseUrlRequired": "Трябва да въведете Apprise URL",
|
||||||
|
"ToastAsinRequired": "ASIN-а е задължителен",
|
||||||
"ToastAuthorImageRemoveSuccess": "Авторската снимка е премахната",
|
"ToastAuthorImageRemoveSuccess": "Авторската снимка е премахната",
|
||||||
|
"ToastAuthorNotFound": "Автор \"{0}\" не е намерен",
|
||||||
|
"ToastAuthorRemoveSuccess": "Арторът е премахнат",
|
||||||
|
"ToastAuthorSearchNotFound": "Авторът не е намерен",
|
||||||
"ToastAuthorUpdateMerged": "Обновяване на автора сливано",
|
"ToastAuthorUpdateMerged": "Обновяване на автора сливано",
|
||||||
"ToastAuthorUpdateSuccess": "Автора обновен",
|
"ToastAuthorUpdateSuccess": "Автора обновен",
|
||||||
"ToastAuthorUpdateSuccessNoImageFound": "Автор обновен (не е намерена снимка)",
|
"ToastAuthorUpdateSuccessNoImageFound": "Автор обновен (не е намерена снимка)",
|
||||||
|
"ToastBackupAppliedSuccess": "Архивът е приложен",
|
||||||
"ToastBackupCreateFailed": "Неуспешно създаване на архив",
|
"ToastBackupCreateFailed": "Неуспешно създаване на архив",
|
||||||
"ToastBackupCreateSuccess": "Архивът е създаден",
|
"ToastBackupCreateSuccess": "Архивът е създаден",
|
||||||
"ToastBackupDeleteFailed": "Неуспешно изтриване на архив",
|
"ToastBackupDeleteFailed": "Неуспешно изтриване на архив",
|
||||||
"ToastBackupDeleteSuccess": "Архивът е изтрит",
|
"ToastBackupDeleteSuccess": "Архивът е изтрит",
|
||||||
|
"ToastBackupInvalidMaxKeep": "Невалиден брой за архиви за запазване",
|
||||||
|
"ToastBackupInvalidMaxSize": "Невалиден максимален рамер на архив",
|
||||||
"ToastBackupRestoreFailed": "Неуспешно възстановяване на архив",
|
"ToastBackupRestoreFailed": "Неуспешно възстановяване на архив",
|
||||||
"ToastBackupUploadFailed": "Неуспешно качване на архив",
|
"ToastBackupUploadFailed": "Неуспешно качване на архив",
|
||||||
"ToastBackupUploadSuccess": "Архивът е качен",
|
"ToastBackupUploadSuccess": "Архивът е качен",
|
||||||
|
"ToastBatchApplyDetailsToItemsSuccess": "Детайли приложени на предмети",
|
||||||
|
"ToastBatchDeleteFailed": "Груповото изтриване се провали",
|
||||||
|
"ToastBatchDeleteSuccess": "Успешно групово изтриване",
|
||||||
|
"ToastBatchQuickMatchFailed": "Груповото Бързо Съвпадение се провали!",
|
||||||
|
"ToastBatchQuickMatchStarted": "Груповото Бързо Съвпадение на {0} книги започна!",
|
||||||
"ToastBatchUpdateFailed": "Неуспешно групово актуализиране",
|
"ToastBatchUpdateFailed": "Неуспешно групово актуализиране",
|
||||||
"ToastBatchUpdateSuccess": "Успешно групово актуализиране",
|
"ToastBatchUpdateSuccess": "Успешно групово актуализиране",
|
||||||
"ToastBookmarkCreateFailed": "Неуспешно създаване на отметка",
|
"ToastBookmarkCreateFailed": "Неуспешно създаване на отметка",
|
||||||
"ToastBookmarkCreateSuccess": "Отметката е създадена",
|
"ToastBookmarkCreateSuccess": "Отметката е създадена",
|
||||||
"ToastBookmarkRemoveSuccess": "Отметката е премахната",
|
"ToastBookmarkRemoveSuccess": "Отметката е премахната",
|
||||||
|
"ToastBulkChapterInvalidCount": "Въведете число между 1 и 150",
|
||||||
"ToastCachePurgeFailed": "Неуспешно изчистване на кеша",
|
"ToastCachePurgeFailed": "Неуспешно изчистване на кеша",
|
||||||
"ToastCachePurgeSuccess": "Успешно изчистване на кеша",
|
"ToastCachePurgeSuccess": "Успешно изчистване на кеша",
|
||||||
|
"ToastChapterLocked": "Главата е заключена.",
|
||||||
|
"ToastChapterStartTimeAdjusted": "Начално време на главате е настоено с {0} секунди",
|
||||||
|
"ToastChaptersAllLocked": "Всички глави са заключени. Оключете някой глави за да преместите техните времена.",
|
||||||
"ToastChaptersHaveErrors": "Главите имат грешки",
|
"ToastChaptersHaveErrors": "Главите имат грешки",
|
||||||
"ToastChaptersMustHaveTitles": "Главите трябва да имат заглавия",
|
"ToastChaptersMustHaveTitles": "Главите трябва да имат заглавия",
|
||||||
"ToastCollectionRemoveSuccess": "Колекцията е премахната",
|
"ToastCollectionRemoveSuccess": "Колекцията е премахната",
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
"ButtonViewAll": "Alles anzeigen",
|
"ButtonViewAll": "Alles anzeigen",
|
||||||
"ButtonYes": "Ja",
|
"ButtonYes": "Ja",
|
||||||
"ErrorUploadFetchMetadataAPI": "Fehler beim Abrufen der Metadaten",
|
"ErrorUploadFetchMetadataAPI": "Fehler beim Abrufen der Metadaten",
|
||||||
"ErrorUploadFetchMetadataNoResults": "Metadaten konnten nicht abgerufen werden. Versuche, den Titel und/oder den Autor zu aktualisieren.",
|
"ErrorUploadFetchMetadataNoResults": "Metadaten konnten nicht abgerufen werden - versuche den Titel und/oder den Autor zu aktualisieren",
|
||||||
"ErrorUploadLacksTitle": "Es muss ein Titel eingegeben werden",
|
"ErrorUploadLacksTitle": "Es muss ein Titel eingegeben werden",
|
||||||
"HeaderAccount": "Konto",
|
"HeaderAccount": "Konto",
|
||||||
"HeaderAddCustomMetadataProvider": "Benutzerdefinierten Metadatenanbieter hinzufügen",
|
"HeaderAddCustomMetadataProvider": "Benutzerdefinierten Metadatenanbieter hinzufügen",
|
||||||
@@ -331,7 +331,7 @@
|
|||||||
"LabelEmail": "E-Mail",
|
"LabelEmail": "E-Mail",
|
||||||
"LabelEmailSettingsFromAddress": "Sender",
|
"LabelEmailSettingsFromAddress": "Sender",
|
||||||
"LabelEmailSettingsRejectUnauthorized": "Nicht autorisierte Zertifikate ablehnen",
|
"LabelEmailSettingsRejectUnauthorized": "Nicht autorisierte Zertifikate ablehnen",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Durch das Deaktivieren der SSL-Zertifikatsüberprüfung kann deine Verbindung Sicherheitsrisiken wie Man-in-the-Middle-Angriffen ausgesetzt sein. Deaktiviere diese Option nur, wenn due die Auswirkungen verstehst und dem E-Mail-Server vertraust, mit dem eine Verbindung hergestellt wird.",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Durch das Deaktivieren der SSL-Zertifikatsüberprüfung kann deine Verbindung Sicherheitsrisiken wie Man-in-the-Middle-Angriffen ausgesetzt sein. Deaktiviere diese Option nur, wenn du die Auswirkungen verstehst und dem E-Mail-Server vertraust, mit dem eine Verbindung hergestellt wird.",
|
||||||
"LabelEmailSettingsSecure": "Sicher",
|
"LabelEmailSettingsSecure": "Sicher",
|
||||||
"LabelEmailSettingsSecureHelp": "Wenn an, verwendet die Verbindung TLS, wenn du eine Verbindung zum Server herstellst. Bei „aus“ wird TLS verwendet, wenn der Server die STARTTLS-Erweiterung unterstützt. In den meisten Fällen solltest du diesen Wert auf „an“ schalten, wenn du eine Verbindung zu Port 465 herstellst. Für Port 587 oder 25 behalte den Wert „aus“ bei. (von nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Wenn an, verwendet die Verbindung TLS, wenn du eine Verbindung zum Server herstellst. Bei „aus“ wird TLS verwendet, wenn der Server die STARTTLS-Erweiterung unterstützt. In den meisten Fällen solltest du diesen Wert auf „an“ schalten, wenn du eine Verbindung zu Port 465 herstellst. Für Port 587 oder 25 behalte den Wert „aus“ bei. (von nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "Test-Adresse",
|
"LabelEmailSettingsTestAddress": "Test-Adresse",
|
||||||
@@ -622,7 +622,7 @@
|
|||||||
"LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet",
|
"LabelSettingsStoreMetadataWithItemHelp": "Standardmäßig werden die Metadaten in /metadata/items gespeichert. Wenn diese Option aktiviert ist, werden die Metadaten als OPF-Datei (Textdatei) in dem gleichen Ordner gespeichert in welchem sich auch das Medium befindet",
|
||||||
"LabelSettingsTimeFormat": "Zeitformat",
|
"LabelSettingsTimeFormat": "Zeitformat",
|
||||||
"LabelShare": "Freigeben",
|
"LabelShare": "Freigeben",
|
||||||
"LabelShareDownloadableHelp": "Erlaubt es einem Nutzer, mit dem Link, die Dateien des Mediums als ZIP herunterzuladen.",
|
"LabelShareDownloadableHelp": "Erlaubt es einem Nutzer, mit dem Link die Dateien des Mediums als ZIP herunterzuladen.",
|
||||||
"LabelShareOpen": "Freigeben",
|
"LabelShareOpen": "Freigeben",
|
||||||
"LabelShareURL": "Freigabe URL",
|
"LabelShareURL": "Freigabe URL",
|
||||||
"LabelShowAll": "Alles anzeigen",
|
"LabelShowAll": "Alles anzeigen",
|
||||||
@@ -737,7 +737,7 @@
|
|||||||
"MessageAddToPlayerQueue": "Zur Abspielwarteliste hinzufügen",
|
"MessageAddToPlayerQueue": "Zur Abspielwarteliste hinzufügen",
|
||||||
"MessageAppriseDescription": "Um diese Funktion nutzen zu können, musst du eine Instanz von <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> laufen haben oder eine API verwenden welche dieselbe Anfragen bearbeiten kann. <br />Die Apprise API Url muss der vollständige URL-Pfad sein, an den die Benachrichtigung gesendet werden soll, z.B. wenn Ihre API-Instanz unter <code>http://192.168.1.1:8337</code> läuft, würdest du <code>http://192.168.1.1:8337/notify</code> eingeben.",
|
"MessageAppriseDescription": "Um diese Funktion nutzen zu können, musst du eine Instanz von <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">Apprise API</a> laufen haben oder eine API verwenden welche dieselbe Anfragen bearbeiten kann. <br />Die Apprise API Url muss der vollständige URL-Pfad sein, an den die Benachrichtigung gesendet werden soll, z.B. wenn Ihre API-Instanz unter <code>http://192.168.1.1:8337</code> läuft, würdest du <code>http://192.168.1.1:8337/notify</code> eingeben.",
|
||||||
"MessageAsinCheck": "Stelle sicher, dass die ASIN aus der richtigen Audible Region verwendet wird, nicht Amazon.",
|
"MessageAsinCheck": "Stelle sicher, dass die ASIN aus der richtigen Audible Region verwendet wird, nicht Amazon.",
|
||||||
"MessageAuthenticationLegacyTokenWarning": "Alte API-Token werden in Zukunft entfernt. Benutze stattdessen <a href=\"/config/api-keys\">API Keys</a>.",
|
"MessageAuthenticationLegacyTokenWarning": "Nicht mehr unterstützte API tokens werden in der Zukunft entfernt. Nutze stattdessen <a href=\"/config/api-keys\">API Schlüssel</a>.",
|
||||||
"MessageAuthenticationOIDCChangesRestart": "Nach dem Speichern muss der Server neugestartet werden um die OIDC Änderungen zu übernehmen.",
|
"MessageAuthenticationOIDCChangesRestart": "Nach dem Speichern muss der Server neugestartet werden um die OIDC Änderungen zu übernehmen.",
|
||||||
"MessageAuthenticationSecurityMessage": "Die Anmeldung wurde abgesichert. Benutzersitzungen werden getrennt, alle Benutzer müssen sich erneut anmelden.",
|
"MessageAuthenticationSecurityMessage": "Die Anmeldung wurde abgesichert. Benutzersitzungen werden getrennt, alle Benutzer müssen sich erneut anmelden.",
|
||||||
"MessageBackupsDescription": "In einer Sicherung werden Benutzer, Benutzerfortschritte, Details zu den Bibliotheksobjekten, Servereinstellungen und Bilder welche in <code>/metadata/items</code> & <code>/metadata/authors</code> gespeichert sind gespeichert. Sicherungen enthalten keine Dateien welche in den einzelnen Bibliotheksordnern (Medien-Ordnern) gespeichert sind.",
|
"MessageBackupsDescription": "In einer Sicherung werden Benutzer, Benutzerfortschritte, Details zu den Bibliotheksobjekten, Servereinstellungen und Bilder welche in <code>/metadata/items</code> & <code>/metadata/authors</code> gespeichert sind gespeichert. Sicherungen enthalten keine Dateien welche in den einzelnen Bibliotheksordnern (Medien-Ordnern) gespeichert sind.",
|
||||||
@@ -816,7 +816,7 @@
|
|||||||
"MessageFeedURLWillBe": "Feed-URL wird {0} sein",
|
"MessageFeedURLWillBe": "Feed-URL wird {0} sein",
|
||||||
"MessageFetching": "Wird abgerufen …",
|
"MessageFetching": "Wird abgerufen …",
|
||||||
"MessageForceReScanDescription": "Durchsucht alle Dateien erneut, wie bei einem frischen Scan. ID3-Tags von Audiodateien, OPF-Dateien und Textdateien werden neu durchsucht.",
|
"MessageForceReScanDescription": "Durchsucht alle Dateien erneut, wie bei einem frischen Scan. ID3-Tags von Audiodateien, OPF-Dateien und Textdateien werden neu durchsucht.",
|
||||||
"MessageHeatmapListeningTimeTooltip": "<strong>{0} </strong> auf {1} gehört",
|
"MessageHeatmapListeningTimeTooltip": "<strong>{0} gehört</strong> auf {1}",
|
||||||
"MessageHeatmapNoListeningSessions": "Keine Hörsitzungen am {0}",
|
"MessageHeatmapNoListeningSessions": "Keine Hörsitzungen am {0}",
|
||||||
"MessageImportantNotice": "Wichtiger Hinweis!",
|
"MessageImportantNotice": "Wichtiger Hinweis!",
|
||||||
"MessageInsertChapterBelow": "Kapitel unten einfügen",
|
"MessageInsertChapterBelow": "Kapitel unten einfügen",
|
||||||
@@ -1103,7 +1103,7 @@
|
|||||||
"ToastPodcastCreateFailed": "Podcast konnte nicht erstellt werden",
|
"ToastPodcastCreateFailed": "Podcast konnte nicht erstellt werden",
|
||||||
"ToastPodcastCreateSuccess": "Podcast erstellt",
|
"ToastPodcastCreateSuccess": "Podcast erstellt",
|
||||||
"ToastPodcastEpisodeUpdated": "Podcast-Folge aktualisiert",
|
"ToastPodcastEpisodeUpdated": "Podcast-Folge aktualisiert",
|
||||||
"ToastPodcastGetFeedFailed": "Fehler beim abrufen des Podcast-Feeds",
|
"ToastPodcastGetFeedFailed": "Fehler beim Abrufen des Podcast Feeds",
|
||||||
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
|
"ToastPodcastNoEpisodesInFeed": "Keine Episoden in RSS Feed gefunden",
|
||||||
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
|
"ToastPodcastNoRssFeed": "Podcast enthält keinen RSS Feed",
|
||||||
"ToastProgressIsNotBeingSynced": "Fortschritt wird nicht synchronisiert, Wiedergabe wird neu gestartet",
|
"ToastProgressIsNotBeingSynced": "Fortschritt wird nicht synchronisiert, Wiedergabe wird neu gestartet",
|
||||||
|
|||||||
+122
-98
@@ -20,10 +20,10 @@
|
|||||||
"ButtonCheckAndDownloadNewEpisodes": "Comprobar y descargar episodios nuevos",
|
"ButtonCheckAndDownloadNewEpisodes": "Comprobar y descargar episodios nuevos",
|
||||||
"ButtonChooseAFolder": "Elegir una carpeta",
|
"ButtonChooseAFolder": "Elegir una carpeta",
|
||||||
"ButtonChooseFiles": "Elegir archivos",
|
"ButtonChooseFiles": "Elegir archivos",
|
||||||
"ButtonClearFilter": "Quitar filtros",
|
"ButtonClearFilter": "Vaciar filtro",
|
||||||
"ButtonClose": "Cerrar",
|
"ButtonClose": "Cerrar",
|
||||||
"ButtonCloseFeed": "Cerrar suministro",
|
"ButtonCloseFeed": "Cerrar suministro",
|
||||||
"ButtonCloseSession": "Cerrar la sesión abierta",
|
"ButtonCloseSession": "Cerrar sesión abierta",
|
||||||
"ButtonCollections": "Colecciones",
|
"ButtonCollections": "Colecciones",
|
||||||
"ButtonConfigureScanner": "Configurar Escáner",
|
"ButtonConfigureScanner": "Configurar Escáner",
|
||||||
"ButtonCreate": "Crear",
|
"ButtonCreate": "Crear",
|
||||||
@@ -33,27 +33,27 @@
|
|||||||
"ButtonEdit": "Editar",
|
"ButtonEdit": "Editar",
|
||||||
"ButtonEditChapters": "Editar capítulos",
|
"ButtonEditChapters": "Editar capítulos",
|
||||||
"ButtonEditPodcast": "Editar pódcast",
|
"ButtonEditPodcast": "Editar pódcast",
|
||||||
"ButtonEnable": "Permitir",
|
"ButtonEnable": "Habilitar",
|
||||||
"ButtonFireAndFail": "Ejecutado y fallido",
|
"ButtonFireAndFail": "Ejecutado y fallido",
|
||||||
"ButtonFireOnTest": "Activar evento de prueba",
|
"ButtonFireOnTest": "Activar evento de prueba",
|
||||||
"ButtonForceReScan": "Forzar Re-Escaneo",
|
"ButtonForceReScan": "Forzar Re-Escaneo",
|
||||||
"ButtonFullPath": "Ruta completa",
|
"ButtonFullPath": "Ruta completa",
|
||||||
"ButtonHide": "Ocultar",
|
"ButtonHide": "Ocultar",
|
||||||
"ButtonHome": "Inicio",
|
"ButtonHome": "Inicio",
|
||||||
"ButtonIssues": "Problemas",
|
"ButtonIssues": "Incidencias",
|
||||||
"ButtonJumpBackward": "Retroceder",
|
"ButtonJumpBackward": "Retroceder",
|
||||||
"ButtonJumpForward": "Adelantar",
|
"ButtonJumpForward": "Adelantar",
|
||||||
"ButtonLatest": "Más recientes",
|
"ButtonLatest": "Más recientes",
|
||||||
"ButtonLibrary": "Biblioteca",
|
"ButtonLibrary": "Biblioteca",
|
||||||
"ButtonLogout": "Salir",
|
"ButtonLogout": "Cerrar Sesión",
|
||||||
"ButtonLookup": "Buscar",
|
"ButtonLookup": "Averiguar",
|
||||||
"ButtonManageTracks": "Gestionar pistas",
|
"ButtonManageTracks": "Gestionar pistas",
|
||||||
"ButtonMapChapterTitles": "Asignar Títulos a Capítulos",
|
"ButtonMapChapterTitles": "Asignar Títulos a Capítulos",
|
||||||
"ButtonMatchAllAuthors": "Encontrar Todos los Autores",
|
"ButtonMatchAllAuthors": "Encontrar Todos los Autores",
|
||||||
"ButtonMatchBooks": "Encontrar Libros",
|
"ButtonMatchBooks": "Cotejar Libros",
|
||||||
"ButtonNevermind": "Olvidar",
|
"ButtonNevermind": "Olvidar",
|
||||||
"ButtonNext": "Siguiente",
|
"ButtonNext": "Siguiente",
|
||||||
"ButtonNextChapter": "Siguiente Capítulo",
|
"ButtonNextChapter": "Siguiente capítulo",
|
||||||
"ButtonNextItemInQueue": "El siguiente elemento en cola",
|
"ButtonNextItemInQueue": "El siguiente elemento en cola",
|
||||||
"ButtonOk": "Aceptar",
|
"ButtonOk": "Aceptar",
|
||||||
"ButtonOpenFeed": "Abrir suministro",
|
"ButtonOpenFeed": "Abrir suministro",
|
||||||
@@ -64,26 +64,26 @@
|
|||||||
"ButtonPlaying": "Reproduciendo",
|
"ButtonPlaying": "Reproduciendo",
|
||||||
"ButtonPlaylists": "Listas de reproducción",
|
"ButtonPlaylists": "Listas de reproducción",
|
||||||
"ButtonPrevious": "Anterior",
|
"ButtonPrevious": "Anterior",
|
||||||
"ButtonPreviousChapter": "Capítulo Anterior",
|
"ButtonPreviousChapter": "Capítulo anterior",
|
||||||
"ButtonProbeAudioFile": "Examinar archivo de audio",
|
"ButtonProbeAudioFile": "Sonda del archivo de audio",
|
||||||
"ButtonPurgeAllCache": "Purgar toda la antememoria",
|
"ButtonPurgeAllCache": "Purgar toda la caché",
|
||||||
"ButtonPurgeItemsCache": "Purgar antememoria de elementos",
|
"ButtonPurgeItemsCache": "Purgar caché de elementos",
|
||||||
"ButtonQueueAddItem": "Añadir a la cola",
|
"ButtonQueueAddItem": "Añadir a cola",
|
||||||
"ButtonQueueRemoveItem": "Quitar de la cola",
|
"ButtonQueueRemoveItem": "Quitar de cola",
|
||||||
"ButtonQuickEmbed": "Inserción rápida",
|
"ButtonQuickEmbed": "Inserción rápida",
|
||||||
"ButtonQuickEmbedMetadata": "Agregue metadatos rápidamente",
|
"ButtonQuickEmbedMetadata": "Empotrar metadatos rápidamente",
|
||||||
"ButtonQuickMatch": "Encontrar Rápido",
|
"ButtonQuickMatch": "Cotejo Rápido",
|
||||||
"ButtonReScan": "Re-Escanear",
|
"ButtonReScan": "Re-Escanear",
|
||||||
"ButtonRead": "Leer",
|
"ButtonRead": "Leer",
|
||||||
"ButtonReadLess": "Leer menos",
|
"ButtonReadLess": "Leer menos",
|
||||||
"ButtonReadMore": "Leer más",
|
"ButtonReadMore": "Leer más",
|
||||||
"ButtonRefresh": "Actualizar",
|
"ButtonRefresh": "Recargar",
|
||||||
"ButtonRemove": "Quitar",
|
"ButtonRemove": "Quitar",
|
||||||
"ButtonRemoveAll": "Quitar todo",
|
"ButtonRemoveAll": "Quitar todo",
|
||||||
"ButtonRemoveAllLibraryItems": "Quitar todos los elementos de la biblioteca",
|
"ButtonRemoveAllLibraryItems": "Quitar todos los elementos de la biblioteca",
|
||||||
"ButtonRemoveFromContinueListening": "Quitar de Continuar escuchando",
|
"ButtonRemoveFromContinueListening": "Quitar desde Escucha Continua",
|
||||||
"ButtonRemoveFromContinueReading": "Quitar de Continuar leyendo",
|
"ButtonRemoveFromContinueReading": "Quitar desde Continuar Leyendo",
|
||||||
"ButtonRemoveSeriesFromContinueSeries": "Quitar serie de Continuar serie",
|
"ButtonRemoveSeriesFromContinueSeries": "Quitar Series desde Series Continuas",
|
||||||
"ButtonReset": "Restablecer",
|
"ButtonReset": "Restablecer",
|
||||||
"ButtonResetToDefault": "Restaurar valores predeterminados",
|
"ButtonResetToDefault": "Restaurar valores predeterminados",
|
||||||
"ButtonRestore": "Restaurar",
|
"ButtonRestore": "Restaurar",
|
||||||
@@ -92,47 +92,47 @@
|
|||||||
"ButtonSaveTracklist": "Guardar lista de pistas",
|
"ButtonSaveTracklist": "Guardar lista de pistas",
|
||||||
"ButtonScan": "Escanear",
|
"ButtonScan": "Escanear",
|
||||||
"ButtonScanLibrary": "Escanear biblioteca",
|
"ButtonScanLibrary": "Escanear biblioteca",
|
||||||
"ButtonScrollLeft": "Desplazarse hacia la izquierda",
|
"ButtonScrollLeft": "Desplazarse a la izquierda",
|
||||||
"ButtonScrollRight": "Desplazarse hacia la derecha",
|
"ButtonScrollRight": "Desplazarse a la derecha",
|
||||||
"ButtonSearch": "Buscar",
|
"ButtonSearch": "Buscar",
|
||||||
"ButtonSelectFolderPath": "Seleccionar ruta de carpeta",
|
"ButtonSelectFolderPath": "Seleccionar ruta de carpeta",
|
||||||
"ButtonSeries": "Series",
|
"ButtonSeries": "Series",
|
||||||
"ButtonSetChaptersFromTracks": "Seleccionar Capítulos Según las Pistas",
|
"ButtonSetChaptersFromTracks": "Establecer capítulos según las pistas",
|
||||||
"ButtonShare": "Compartir",
|
"ButtonShare": "Compartir",
|
||||||
"ButtonShiftTimes": "Desplazar Tiempos",
|
"ButtonShiftTimes": "Veces de Desplazo",
|
||||||
"ButtonShow": "Mostrar",
|
"ButtonShow": "Mostrar",
|
||||||
"ButtonStartM4BEncode": "Iniciar Codificación M4B",
|
"ButtonStartM4BEncode": "Iniciar Codificación M4B",
|
||||||
"ButtonStartMetadataEmbed": "Iniciar la Inserción de Metadata",
|
"ButtonStartMetadataEmbed": "Iniciar Inserción de Metadatos",
|
||||||
"ButtonStats": "Estadísticas",
|
"ButtonStats": "Estadísticas",
|
||||||
"ButtonSubmit": "Enviar",
|
"ButtonSubmit": "Entregar",
|
||||||
"ButtonTest": "Prueba",
|
"ButtonTest": "Prueba",
|
||||||
"ButtonUnlinkOpenId": "Desvincular OpenID",
|
"ButtonUnlinkOpenId": "Desenlazar OpenID",
|
||||||
"ButtonUpload": "Cargar",
|
"ButtonUpload": "Subir",
|
||||||
"ButtonUploadBackup": "Cargar respaldo",
|
"ButtonUploadBackup": "Subir Respaldo",
|
||||||
"ButtonUploadCover": "Cargar cubierta",
|
"ButtonUploadCover": "Subir Cubierta",
|
||||||
"ButtonUploadOPMLFile": "Cargar archivo OPML",
|
"ButtonUploadOPMLFile": "Subir archivo OPML",
|
||||||
"ButtonUserDelete": "Eliminar usuario {0}",
|
"ButtonUserDelete": "Eliminar usuario {0}",
|
||||||
"ButtonUserEdit": "Editar usuario {0}",
|
"ButtonUserEdit": "Editar usuario {0}",
|
||||||
"ButtonViewAll": "Ver todo",
|
"ButtonViewAll": "Ver todo",
|
||||||
"ButtonYes": "Sí",
|
"ButtonYes": "Sí",
|
||||||
"ErrorUploadFetchMetadataAPI": "Error al recuperar los metadatos",
|
"ErrorUploadFetchMetadataAPI": "Error al recuperar los metadatos",
|
||||||
"ErrorUploadFetchMetadataNoResults": "No se pudieron recuperar los metadatos; pruebe a actualizar el título o autor",
|
"ErrorUploadFetchMetadataNoResults": "No se pudieron recuperar los metadatos; pruebe a actualizar el título y/o autor",
|
||||||
"ErrorUploadLacksTitle": "Debe tener título",
|
"ErrorUploadLacksTitle": "Debe tener un título",
|
||||||
"HeaderAccount": "Cuenta",
|
"HeaderAccount": "Cuenta",
|
||||||
"HeaderAddCustomMetadataProvider": "Añadir proveedor de metadatos personalizado",
|
"HeaderAddCustomMetadataProvider": "Añadir proveedor de metadatos personalizado",
|
||||||
"HeaderAdvanced": "Avanzado",
|
"HeaderAdvanced": "Avanzado",
|
||||||
"HeaderApiKeys": "Claves API",
|
"HeaderApiKeys": "Claves API",
|
||||||
"HeaderAppriseNotificationSettings": "Configuración de notificaciones de Apprise",
|
"HeaderAppriseNotificationSettings": "Ajustes de notificaciones de Apprise",
|
||||||
"HeaderAudioTracks": "Pistas de audio",
|
"HeaderAudioTracks": "Pistas de Audio",
|
||||||
"HeaderAudiobookTools": "Herramientas de Gestión de Archivos de Audiolibro",
|
"HeaderAudiobookTools": "Herramientas de Gestión de Archivos de Audiolibro",
|
||||||
"HeaderAuthentication": "Autenticación",
|
"HeaderAuthentication": "Autenticación",
|
||||||
"HeaderBackups": "Respaldos",
|
"HeaderBackups": "Respaldos",
|
||||||
"HeaderBulkChapterModal": "Añadir Múltiples Capítulos",
|
"HeaderBulkChapterModal": "Añadir Múltiples Capítulos",
|
||||||
"HeaderChangePassword": "Cambiar contraseña",
|
"HeaderChangePassword": "Cambiar Contraseña",
|
||||||
"HeaderChapters": "Capítulos",
|
"HeaderChapters": "Capítulos",
|
||||||
"HeaderChooseAFolder": "Escoger una Carpeta",
|
"HeaderChooseAFolder": "Escoger una Carpeta",
|
||||||
"HeaderCollection": "Colección",
|
"HeaderCollection": "Colección",
|
||||||
"HeaderCollectionItems": "Elementos en la colección",
|
"HeaderCollectionItems": "Elementos de colección",
|
||||||
"HeaderCover": "Cubierta",
|
"HeaderCover": "Cubierta",
|
||||||
"HeaderCurrentDownloads": "Descargas actuales",
|
"HeaderCurrentDownloads": "Descargas actuales",
|
||||||
"HeaderCustomMessageOnLogin": "Mensaje personalizado al acceder",
|
"HeaderCustomMessageOnLogin": "Mensaje personalizado al acceder",
|
||||||
@@ -140,49 +140,49 @@
|
|||||||
"HeaderDetails": "Detalles",
|
"HeaderDetails": "Detalles",
|
||||||
"HeaderDownloadQueue": "Cola de descargas",
|
"HeaderDownloadQueue": "Cola de descargas",
|
||||||
"HeaderEbookFiles": "Archivos de libros digitales",
|
"HeaderEbookFiles": "Archivos de libros digitales",
|
||||||
"HeaderEmail": "Correo electrónico",
|
"HeaderEmail": "Correo-e",
|
||||||
"HeaderEmailSettings": "Configuración de correo electrónico",
|
"HeaderEmailSettings": "Ajustes de correo-e",
|
||||||
"HeaderEpisodes": "Episodios",
|
"HeaderEpisodes": "Episodios",
|
||||||
"HeaderEreaderDevices": "Dispositivos Ereader",
|
"HeaderEreaderDevices": "Dispositivos Lector-e",
|
||||||
"HeaderEreaderSettings": "Configuración del lector",
|
"HeaderEreaderSettings": "Ajustes del Lector-e",
|
||||||
"HeaderFiles": "Archivos",
|
"HeaderFiles": "Archivos",
|
||||||
"HeaderFindChapters": "Buscar capítulos",
|
"HeaderFindChapters": "Buscar capítulos",
|
||||||
"HeaderIgnoredFiles": "Archivos ignorados",
|
"HeaderIgnoredFiles": "Archivos ignorados",
|
||||||
"HeaderItemFiles": "Archivos de elementos",
|
"HeaderItemFiles": "Archivos del elemento",
|
||||||
"HeaderItemMetadataUtils": "Utilidades de metadatos de elementos",
|
"HeaderItemMetadataUtils": "Utilidades de metadatos del elemento",
|
||||||
"HeaderLastListeningSession": "Última sesión de escucha",
|
"HeaderLastListeningSession": "Última sesión de escucha",
|
||||||
"HeaderLatestEpisodes": "Episodios más recientes",
|
"HeaderLatestEpisodes": "Episodios más recientes",
|
||||||
"HeaderLibraries": "Bibliotecas",
|
"HeaderLibraries": "Bibliotecas",
|
||||||
"HeaderLibraryFiles": "Archivos de biblioteca",
|
"HeaderLibraryFiles": "Archivos de biblioteca",
|
||||||
"HeaderLibraryStats": "Estadísticas de biblioteca",
|
"HeaderLibraryStats": "Estadísticas de biblioteca",
|
||||||
"HeaderListeningSessions": "Sesión",
|
"HeaderListeningSessions": "Sesiones Listadas",
|
||||||
"HeaderListeningStats": "Estadísticas de Tiempo Escuchado",
|
"HeaderListeningStats": "Estadísticas de Tiempo Escuchado",
|
||||||
"HeaderLogin": "Acceder",
|
"HeaderLogin": "Inicio de Sesión",
|
||||||
"HeaderLogs": "Registros",
|
"HeaderLogs": "Bitácoras",
|
||||||
"HeaderManageGenres": "Gestionar géneros",
|
"HeaderManageGenres": "Gestionar géneros",
|
||||||
"HeaderManageTags": "Gestionar etiquetas",
|
"HeaderManageTags": "Gestionar etiquetas",
|
||||||
"HeaderMapDetails": "Asignar Detalles",
|
"HeaderMapDetails": "Asignar Detalles",
|
||||||
"HeaderMatch": "Encontrar",
|
"HeaderMatch": "Coincidir",
|
||||||
"HeaderMetadataOrderOfPrecedence": "Orden de precedencia de metadatos",
|
"HeaderMetadataOrderOfPrecedence": "Orden de precedencia de metadatos",
|
||||||
"HeaderMetadataToEmbed": "Metadatos para Insertar",
|
"HeaderMetadataToEmbed": "Metadatos para empotrar",
|
||||||
"HeaderNewAccount": "Cuenta nueva",
|
"HeaderNewAccount": "Crear Cuenta",
|
||||||
"HeaderNewApiKey": "Nueva clave API",
|
"HeaderNewApiKey": "Nueva clave API",
|
||||||
"HeaderNewLibrary": "Biblioteca nueva",
|
"HeaderNewLibrary": "Biblioteca nueva",
|
||||||
"HeaderNotificationCreate": "Crear notificación",
|
"HeaderNotificationCreate": "Crear Notificación",
|
||||||
"HeaderNotificationUpdate": "Notificación de actualización",
|
"HeaderNotificationUpdate": "Notificación de Actualización",
|
||||||
"HeaderNotifications": "Notificaciones",
|
"HeaderNotifications": "Notificaciones",
|
||||||
"HeaderOpenIDConnectAuthentication": "Autenticación OpenID Connect",
|
"HeaderOpenIDConnectAuthentication": "Autenticación OpenID Connect",
|
||||||
"HeaderOpenListeningSessions": "Sesiones públicas de escucha",
|
"HeaderOpenListeningSessions": "Abrir escucha de sesiones",
|
||||||
"HeaderOpenRSSFeed": "Abrir suministro RSS",
|
"HeaderOpenRSSFeed": "Abrir suministro RSS",
|
||||||
"HeaderOtherFiles": "Otros archivos",
|
"HeaderOtherFiles": "Otros archivos",
|
||||||
"HeaderPasswordAuthentication": "Autenticación por contraseña",
|
"HeaderPasswordAuthentication": "Autenticación por contraseña",
|
||||||
"HeaderPermissions": "Permisos",
|
"HeaderPermissions": "Permisos",
|
||||||
"HeaderPlayerQueue": "Cola del reproductor",
|
"HeaderPlayerQueue": "Cola del reproductor",
|
||||||
"HeaderPlayerSettings": "Configuración del reproductor",
|
"HeaderPlayerSettings": "Ajustes del reproductor",
|
||||||
"HeaderPlaylist": "Lista de reproducción",
|
"HeaderPlaylist": "Lista de reproducción",
|
||||||
"HeaderPlaylistItems": "Elementos de lista de reproducción",
|
"HeaderPlaylistItems": "Elementos de lista de reproducción",
|
||||||
"HeaderPodcastsToAdd": "Pódcast para añadir",
|
"HeaderPodcastsToAdd": "Pódcast para añadir",
|
||||||
"HeaderPresets": "Preconfiguraciones",
|
"HeaderPresets": "Preajustes",
|
||||||
"HeaderPreviewCover": "Previsualizar cubierta",
|
"HeaderPreviewCover": "Previsualizar cubierta",
|
||||||
"HeaderRSSFeedGeneral": "Detalles de RSS",
|
"HeaderRSSFeedGeneral": "Detalles de RSS",
|
||||||
"HeaderRSSFeedIsOpen": "El suministro RSS está abierto",
|
"HeaderRSSFeedIsOpen": "El suministro RSS está abierto",
|
||||||
@@ -191,18 +191,18 @@
|
|||||||
"HeaderRemoveEpisodes": "Quitar {0} episodios",
|
"HeaderRemoveEpisodes": "Quitar {0} episodios",
|
||||||
"HeaderSavedMediaProgress": "Guardar Progreso de Multimedia",
|
"HeaderSavedMediaProgress": "Guardar Progreso de Multimedia",
|
||||||
"HeaderSchedule": "Horario",
|
"HeaderSchedule": "Horario",
|
||||||
"HeaderScheduleEpisodeDownloads": "Programar descargas automáticas de episodios",
|
"HeaderScheduleEpisodeDownloads": "Planificador de auto‐descargas de episodios",
|
||||||
"HeaderScheduleLibraryScans": "Programar Escaneo Automático de Biblioteca",
|
"HeaderScheduleLibraryScans": "Planificar Auto‐Escaneo de Biblioteca",
|
||||||
"HeaderSession": "Sesión",
|
"HeaderSession": "Sesión",
|
||||||
"HeaderSetBackupSchedule": "Programar Respaldo",
|
"HeaderSetBackupSchedule": "Establecer Planificación de Respaldo",
|
||||||
"HeaderSettings": "Configuración",
|
"HeaderSettings": "Ajustes",
|
||||||
"HeaderSettingsDisplay": "Interfaz",
|
"HeaderSettingsDisplay": "Interfaz",
|
||||||
"HeaderSettingsExperimental": "Funcionalidades experimentales",
|
"HeaderSettingsExperimental": "Características experimentales",
|
||||||
"HeaderSettingsGeneral": "Generales",
|
"HeaderSettingsGeneral": "Generales",
|
||||||
"HeaderSettingsScanner": "Escáner",
|
"HeaderSettingsScanner": "Escáner",
|
||||||
"HeaderSettingsSecurity": "Seguridad",
|
"HeaderSettingsSecurity": "Seguridad",
|
||||||
"HeaderSettingsWebClient": "Cliente web",
|
"HeaderSettingsWebClient": "Cliente web",
|
||||||
"HeaderSleepTimer": "Temporizador de apagado",
|
"HeaderSleepTimer": "Cronómetro de dormida",
|
||||||
"HeaderStatsLargestItems": "Elementos más grandes",
|
"HeaderStatsLargestItems": "Elementos más grandes",
|
||||||
"HeaderStatsLongestItems": "Elementos más extensos (h)",
|
"HeaderStatsLongestItems": "Elementos más extensos (h)",
|
||||||
"HeaderStatsMinutesListeningChart": "Minutos escuchando (últimos 7 días)",
|
"HeaderStatsMinutesListeningChart": "Minutos escuchando (últimos 7 días)",
|
||||||
@@ -233,29 +233,29 @@
|
|||||||
"LabelAddToCollectionBatch": "Añadir {0} libros a colección",
|
"LabelAddToCollectionBatch": "Añadir {0} libros a colección",
|
||||||
"LabelAddToPlaylist": "Añadir a lista de reproducción",
|
"LabelAddToPlaylist": "Añadir a lista de reproducción",
|
||||||
"LabelAddToPlaylistBatch": "Añadir {0} elementos a lista de reproducción",
|
"LabelAddToPlaylistBatch": "Añadir {0} elementos a lista de reproducción",
|
||||||
"LabelAddedAt": "Añadido",
|
"LabelAddedAt": "Añadido en",
|
||||||
"LabelAddedDate": "{0} Añadido",
|
"LabelAddedDate": "Añadido {0}",
|
||||||
"LabelAdminUsersOnly": "Solamente usuarios administradores",
|
"LabelAdminUsersOnly": "Solamente usuarios administradores",
|
||||||
"LabelAll": "Todos",
|
"LabelAll": "Todos",
|
||||||
"LabelAllEpisodesDownloaded": "Todos los episodios descargados",
|
"LabelAllEpisodesDownloaded": "Todos los episodios descargados",
|
||||||
"LabelAllUsers": "Todos los usuarios",
|
"LabelAllUsers": "Todos los usuarios",
|
||||||
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
|
"LabelAllUsersExcludingGuests": "Todos los usuarios excepto invitados",
|
||||||
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
|
"LabelAllUsersIncludingGuests": "Todos los usuarios e invitados",
|
||||||
"LabelAlreadyInYourLibrary": "Ya existe en la Biblioteca",
|
"LabelAlreadyInYourLibrary": "Ya dentro de tu biblioteca",
|
||||||
"LabelApiKeyCreated": "La clave de API “{0}” se ha creado con éxito.",
|
"LabelApiKeyCreated": "La clave de API “{0}” se ha creado correctamente.",
|
||||||
"LabelApiKeyCreatedDescription": "Asegúrate de copiar la clave de API ahora, no la volverás a ver otra vez.",
|
"LabelApiKeyCreatedDescription": "Asegúrate de copiar la clave de API ahora, no la volverás a ver otra vez.",
|
||||||
"LabelApiKeyUser": "Actuar en nombre del usuario",
|
"LabelApiKeyUser": "Actuar en nombre del usuario",
|
||||||
"LabelApiKeyUserDescription": "Esta clave de API tendrá los mismos permisos que el usuario al que representa. En los registros se verá como si la solicitud la hubiera hecho el usuario directamente.",
|
"LabelApiKeyUserDescription": "Esta clave de API tendrá los mismos permisos que el usuario al que representa. En los registros se verá como si la solicitud la hubiera hecho el usuario directamente.",
|
||||||
"LabelApiToken": "Token de la API",
|
"LabelApiToken": "Vale del API",
|
||||||
"LabelAppend": "Adjuntar",
|
"LabelAppend": "Adjuntar",
|
||||||
"LabelAudioBitrate": "Tasa de bits del audio (por ejemplo, 128k)",
|
"LabelAudioBitrate": "Tasa de bit del audio (p.ej., 128k)",
|
||||||
"LabelAudioChannels": "Canales de audio (1 o 2)",
|
"LabelAudioChannels": "Canales de audio (1 o 2)",
|
||||||
"LabelAudioCodec": "Códec de audio",
|
"LabelAudioCodec": "Códec de audio",
|
||||||
"LabelAuthor": "Autor",
|
"LabelAuthor": "Autor",
|
||||||
"LabelAuthorFirstLast": "Autor (Nombre Apellido)",
|
"LabelAuthorFirstLast": "Autor (Nombre Apellido)",
|
||||||
"LabelAuthorLastFirst": "Autor (Apellido, Nombre)",
|
"LabelAuthorLastFirst": "Autor (Apellido, Nombre)",
|
||||||
"LabelAuthors": "Autores",
|
"LabelAuthors": "Autores",
|
||||||
"LabelAutoDownloadEpisodes": "Descargar episodios automáticamente",
|
"LabelAutoDownloadEpisodes": "Auto‐Descargar episodios",
|
||||||
"LabelAutoFetchMetadata": "Recuperar metadatos automáticamente",
|
"LabelAutoFetchMetadata": "Recuperar metadatos automáticamente",
|
||||||
"LabelAutoFetchMetadataHelp": "Obtiene metadatos de título, autor y serie para agilizar la carga. Es posible que haya que cotejar metadatos adicionales después de la carga.",
|
"LabelAutoFetchMetadataHelp": "Obtiene metadatos de título, autor y serie para agilizar la carga. Es posible que haya que cotejar metadatos adicionales después de la carga.",
|
||||||
"LabelAutoLaunch": "Lanzamiento automático",
|
"LabelAutoLaunch": "Lanzamiento automático",
|
||||||
@@ -275,7 +275,7 @@
|
|||||||
"LabelBonus": "Bonus",
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Libros",
|
"LabelBooks": "Libros",
|
||||||
"LabelButtonText": "Texto del botón",
|
"LabelButtonText": "Texto del botón",
|
||||||
"LabelByAuthor": "por",
|
"LabelByAuthor": "por {0}",
|
||||||
"LabelChangePassword": "Cambiar contraseña",
|
"LabelChangePassword": "Cambiar contraseña",
|
||||||
"LabelChannels": "Canales",
|
"LabelChannels": "Canales",
|
||||||
"LabelChapterCount": "{0} capítulos",
|
"LabelChapterCount": "{0} capítulos",
|
||||||
@@ -286,13 +286,13 @@
|
|||||||
"LabelClickToUseCurrentValue": "Pulse para utilizar el valor actual",
|
"LabelClickToUseCurrentValue": "Pulse para utilizar el valor actual",
|
||||||
"LabelClosePlayer": "Cerrar reproductor",
|
"LabelClosePlayer": "Cerrar reproductor",
|
||||||
"LabelCodec": "Codec",
|
"LabelCodec": "Codec",
|
||||||
"LabelCollapseSeries": "Colapsar serie",
|
"LabelCollapseSeries": "Colapsar Series",
|
||||||
"LabelCollapseSubSeries": "Contraer la subserie",
|
"LabelCollapseSubSeries": "Contraer la subserie",
|
||||||
"LabelCollection": "Colección",
|
"LabelCollection": "Colección",
|
||||||
"LabelCollections": "Colecciones",
|
"LabelCollections": "Colecciones",
|
||||||
"LabelComplete": "Completo",
|
"LabelComplete": "Completo",
|
||||||
"LabelConfirmPassword": "Confirmar contraseña",
|
"LabelConfirmPassword": "Confirmar contraseña",
|
||||||
"LabelContinueListening": "Seguir escuchando",
|
"LabelContinueListening": "Seguir Escuchando",
|
||||||
"LabelContinueReading": "Continuar leyendo",
|
"LabelContinueReading": "Continuar leyendo",
|
||||||
"LabelContinueSeries": "Continuar series",
|
"LabelContinueSeries": "Continuar series",
|
||||||
"LabelCorsAllowed": "Orígenes CORS Permitidos",
|
"LabelCorsAllowed": "Orígenes CORS Permitidos",
|
||||||
@@ -325,14 +325,14 @@
|
|||||||
"LabelDurationComparisonLonger": "({0} más largo)",
|
"LabelDurationComparisonLonger": "({0} más largo)",
|
||||||
"LabelDurationComparisonShorter": "({0} más corto)",
|
"LabelDurationComparisonShorter": "({0} más corto)",
|
||||||
"LabelDurationFound": "Duración Comprobada:",
|
"LabelDurationFound": "Duración Comprobada:",
|
||||||
"LabelEbook": "Libro electrónico",
|
"LabelEbook": "Libro-e",
|
||||||
"LabelEbooks": "Libros electrónicos",
|
"LabelEbooks": "Libros-e",
|
||||||
"LabelEdit": "Editar",
|
"LabelEdit": "Editar",
|
||||||
"LabelEmail": "Correo electrónico",
|
"LabelEmail": "Correo electrónico",
|
||||||
"LabelEmailSettingsFromAddress": "Remitente",
|
"LabelEmailSettingsFromAddress": "Remitente",
|
||||||
"LabelEmailSettingsRejectUnauthorized": "Rechazar certificados no autorizados",
|
"LabelEmailSettingsRejectUnauthorized": "Rechazar certificados no autorizados",
|
||||||
"LabelEmailSettingsRejectUnauthorizedHelp": "Desactivar la validación de certificados SSL puede exponer su conexión a riesgos de seguridad, como los ataques por intermediario. Desactive esta opción solo si conoce las implicaciones y confía en el servidor de correo al que se conecta.",
|
"LabelEmailSettingsRejectUnauthorizedHelp": "Desactivar la validación de certificados SSL puede exponer su conexión a riesgos de seguridad, como los ataques por intermediario. Desactive esta opción solo si conoce las implicaciones y confía en el servidor de correo al que se conecta.",
|
||||||
"LabelEmailSettingsSecure": "Seguridad",
|
"LabelEmailSettingsSecure": "Seguro",
|
||||||
"LabelEmailSettingsSecureHelp": "Si está activado, se usará TLS para conectarse al servidor. Si está apagado, se usará TLS si su servidor tiene soporte para la extensión STARTTLS. En la mayoría de los casos, puede dejar esta opción activada si se está conectando al puerto 465. Apáguela en el caso de usar los puertos 587 o 25. (de nodemailer.com/smtp/#authentication)",
|
"LabelEmailSettingsSecureHelp": "Si está activado, se usará TLS para conectarse al servidor. Si está apagado, se usará TLS si su servidor tiene soporte para la extensión STARTTLS. En la mayoría de los casos, puede dejar esta opción activada si se está conectando al puerto 465. Apáguela en el caso de usar los puertos 587 o 25. (de nodemailer.com/smtp/#authentication)",
|
||||||
"LabelEmailSettingsTestAddress": "Probar dirección",
|
"LabelEmailSettingsTestAddress": "Probar dirección",
|
||||||
"LabelEmbeddedCover": "Cubierta incrustada",
|
"LabelEmbeddedCover": "Cubierta incrustada",
|
||||||
@@ -377,11 +377,12 @@
|
|||||||
"LabelFilename": "Nombre del archivo",
|
"LabelFilename": "Nombre del archivo",
|
||||||
"LabelFilterByUser": "Filtrar por Usuario",
|
"LabelFilterByUser": "Filtrar por Usuario",
|
||||||
"LabelFindEpisodes": "Buscar Episodio",
|
"LabelFindEpisodes": "Buscar Episodio",
|
||||||
"LabelFinished": "Terminado",
|
"LabelFinished": "Finalizado",
|
||||||
|
"LabelFinishedDate": "Finalizado {0}",
|
||||||
"LabelFolder": "Carpeta",
|
"LabelFolder": "Carpeta",
|
||||||
"LabelFolders": "Carpetas",
|
"LabelFolders": "Carpetas",
|
||||||
"LabelFontBold": "Negrilla",
|
"LabelFontBold": "Negrilla",
|
||||||
"LabelFontBoldness": "Peso tipográfico",
|
"LabelFontBoldness": "Tipográfico sin Negrita",
|
||||||
"LabelFontFamily": "Familia tipográfica",
|
"LabelFontFamily": "Familia tipográfica",
|
||||||
"LabelFontItalic": "Itálica",
|
"LabelFontItalic": "Itálica",
|
||||||
"LabelFontScale": "Escala de letra",
|
"LabelFontScale": "Escala de letra",
|
||||||
@@ -391,8 +392,8 @@
|
|||||||
"LabelGenre": "Género",
|
"LabelGenre": "Género",
|
||||||
"LabelGenres": "Géneros",
|
"LabelGenres": "Géneros",
|
||||||
"LabelHardDeleteFile": "Eliminar Definitivamente",
|
"LabelHardDeleteFile": "Eliminar Definitivamente",
|
||||||
"LabelHasEbook": "Tiene un libro",
|
"LabelHasEbook": "Tiene libro-e",
|
||||||
"LabelHasSupplementaryEbook": "Tiene un libro complementario",
|
"LabelHasSupplementaryEbook": "Tiene un libro-e suplementario",
|
||||||
"LabelHideSubtitles": "Ocultar subtítulos",
|
"LabelHideSubtitles": "Ocultar subtítulos",
|
||||||
"LabelHighestPriority": "Mayor prioridad",
|
"LabelHighestPriority": "Mayor prioridad",
|
||||||
"LabelHost": "Anfitrión",
|
"LabelHost": "Anfitrión",
|
||||||
@@ -422,6 +423,7 @@
|
|||||||
"LabelLanguages": "Idiomas",
|
"LabelLanguages": "Idiomas",
|
||||||
"LabelLastBookAdded": "Último libro añadido",
|
"LabelLastBookAdded": "Último libro añadido",
|
||||||
"LabelLastBookUpdated": "Último libro actualizado",
|
"LabelLastBookUpdated": "Último libro actualizado",
|
||||||
|
"LabelLastProgressDate": "Último progreso: {0}",
|
||||||
"LabelLastSeen": "Última Vez Visto",
|
"LabelLastSeen": "Última Vez Visto",
|
||||||
"LabelLastTime": "Última Vez",
|
"LabelLastTime": "Última Vez",
|
||||||
"LabelLastUpdate": "Última Actualización",
|
"LabelLastUpdate": "Última Actualización",
|
||||||
@@ -434,6 +436,9 @@
|
|||||||
"LabelLibraryFilterSublistEmpty": "Sin {0}",
|
"LabelLibraryFilterSublistEmpty": "Sin {0}",
|
||||||
"LabelLibraryItem": "Elemento de Biblioteca",
|
"LabelLibraryItem": "Elemento de Biblioteca",
|
||||||
"LabelLibraryName": "Nombre de Biblioteca",
|
"LabelLibraryName": "Nombre de Biblioteca",
|
||||||
|
"LabelLibrarySortByProgress": "Progreso: Último actualizado",
|
||||||
|
"LabelLibrarySortByProgressFinished": "Progreso: Finalizado",
|
||||||
|
"LabelLibrarySortByProgressStarted": "Progreso: Iniciado",
|
||||||
"LabelLimit": "Limites",
|
"LabelLimit": "Limites",
|
||||||
"LabelLineSpacing": "Interlineado",
|
"LabelLineSpacing": "Interlineado",
|
||||||
"LabelListenAgain": "Volver a escuchar",
|
"LabelListenAgain": "Volver a escuchar",
|
||||||
@@ -442,6 +447,7 @@
|
|||||||
"LabelLogLevelWarn": "Advertencia",
|
"LabelLogLevelWarn": "Advertencia",
|
||||||
"LabelLookForNewEpisodesAfterDate": "Buscar Nuevos Episodios a partir de esta Fecha",
|
"LabelLookForNewEpisodesAfterDate": "Buscar Nuevos Episodios a partir de esta Fecha",
|
||||||
"LabelLowestPriority": "Menor prioridad",
|
"LabelLowestPriority": "Menor prioridad",
|
||||||
|
"LabelMatchConfidence": "Confidencia",
|
||||||
"LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por",
|
"LabelMatchExistingUsersBy": "Emparejar a los usuarios existentes por",
|
||||||
"LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO",
|
"LabelMatchExistingUsersByDescription": "Se utiliza para conectar usuarios existentes. Una vez conectados, los usuarios serán emparejados por un identificador único de su proveedor de SSO",
|
||||||
"LabelMaxEpisodesToDownload": "Número máximo # de episodios para descargar. Usa 0 para descargar una cantidad ilimitada.",
|
"LabelMaxEpisodesToDownload": "Número máximo # de episodios para descargar. Usa 0 para descargar una cantidad ilimitada.",
|
||||||
@@ -460,7 +466,7 @@
|
|||||||
"LabelMissingEbook": "No tiene libro electrónico",
|
"LabelMissingEbook": "No tiene libro electrónico",
|
||||||
"LabelMissingSupplementaryEbook": "No tiene libro electrónico suplementario",
|
"LabelMissingSupplementaryEbook": "No tiene libro electrónico suplementario",
|
||||||
"LabelMobileRedirectURIs": "URIs de redirección a móviles permitidos",
|
"LabelMobileRedirectURIs": "URIs de redirección a móviles permitidos",
|
||||||
"LabelMobileRedirectURIsDescription": "Esta es una lista blanca de URI de redireccionamiento válidos para aplicaciones móviles. El predeterminado es <code> audiobookshelf</code> , que puede eliminar o complementar con URI adicionales para la integración de aplicaciones de terceros. Usando un asterisco (<code> *</code> ) como única entrada que permite cualquier URI.",
|
"LabelMobileRedirectURIsDescription": "Esta es una lista en blanco de las URI de re‐direccionamiento válidos para aplicaciones móviles. El predeterminado es <code>audiobookshelf</code> , que puede retirar o sustituir con las URI adicionales para la integración de aplicaciones de terceros. Usando un asterisco (<code>*</code> ) como única entrada que permite cualquier URI.",
|
||||||
"LabelMore": "Más",
|
"LabelMore": "Más",
|
||||||
"LabelMoreInfo": "Más información",
|
"LabelMoreInfo": "Más información",
|
||||||
"LabelName": "Nombre",
|
"LabelName": "Nombre",
|
||||||
@@ -473,9 +479,10 @@
|
|||||||
"LabelNextBackupDate": "Fecha del siguiente respaldo",
|
"LabelNextBackupDate": "Fecha del siguiente respaldo",
|
||||||
"LabelNextChapters": "Los próximos capítulos serán:",
|
"LabelNextChapters": "Los próximos capítulos serán:",
|
||||||
"LabelNextScheduledRun": "Próxima ejecución programada",
|
"LabelNextScheduledRun": "Próxima ejecución programada",
|
||||||
|
"LabelNoApiKeys": "Sin claves API",
|
||||||
"LabelNoCustomMetadataProviders": "Sin proveedores de metadatos personalizados",
|
"LabelNoCustomMetadataProviders": "Sin proveedores de metadatos personalizados",
|
||||||
"LabelNoEpisodesSelected": "Ningún Episodio Seleccionado",
|
"LabelNoEpisodesSelected": "Ningún Episodio Seleccionado",
|
||||||
"LabelNotFinished": "No terminado",
|
"LabelNotFinished": "No finalizado",
|
||||||
"LabelNotStarted": "Sin iniciar",
|
"LabelNotStarted": "Sin iniciar",
|
||||||
"LabelNotes": "Notas",
|
"LabelNotes": "Notas",
|
||||||
"LabelNotificationAppriseURL": "URL(s) de Apprise",
|
"LabelNotificationAppriseURL": "URL(s) de Apprise",
|
||||||
@@ -489,7 +496,7 @@
|
|||||||
"LabelNotificationsMaxQueueSizeHelp": "Las notificaciones están limitadas a 1 por segundo. Las notificaciones serán ignoradas si llegan al numero máximo de cola para prevenir spam de eventos.",
|
"LabelNotificationsMaxQueueSizeHelp": "Las notificaciones están limitadas a 1 por segundo. Las notificaciones serán ignoradas si llegan al numero máximo de cola para prevenir spam de eventos.",
|
||||||
"LabelNumberOfBooks": "Número de libros",
|
"LabelNumberOfBooks": "Número de libros",
|
||||||
"LabelNumberOfChapters": "Número de capítulos:",
|
"LabelNumberOfChapters": "Número de capítulos:",
|
||||||
"LabelNumberOfEpisodes": "N.º de episodios",
|
"LabelNumberOfEpisodes": "Nº de episodios",
|
||||||
"LabelOpenIDAdvancedPermsClaimDescription": "Nombre de la notificación de OpenID que contiene permisos avanzados para acciones de usuario dentro de la aplicación que se aplicarán a roles que no sean de administrador (<b>si están configurados</b>). Si el reclamo no aparece en la respuesta, se denegará el acceso a ABS. Si falta una sola opción, se tratará como <code>falsa</code>. Asegúrese de que la notificación del proveedor de identidades coincida con la estructura esperada:",
|
"LabelOpenIDAdvancedPermsClaimDescription": "Nombre de la notificación de OpenID que contiene permisos avanzados para acciones de usuario dentro de la aplicación que se aplicarán a roles que no sean de administrador (<b>si están configurados</b>). Si el reclamo no aparece en la respuesta, se denegará el acceso a ABS. Si falta una sola opción, se tratará como <code>falsa</code>. Asegúrese de que la notificación del proveedor de identidades coincida con la estructura esperada:",
|
||||||
"LabelOpenIDClaims": "Deje las siguientes opciones vacías para desactivar la asignación avanzada de grupos y permisos, lo que asignaría de manera automática al grupo «Usuario».",
|
"LabelOpenIDClaims": "Deje las siguientes opciones vacías para desactivar la asignación avanzada de grupos y permisos, lo que asignaría de manera automática al grupo «Usuario».",
|
||||||
"LabelOpenIDGroupClaimDescription": "Nombre de la declaración OpenID que contiene una lista de grupos del usuario. Comúnmente conocidos como <code>grupos</code>. <b>Si se configura</b>, la aplicación asignará automáticamente roles en función de la pertenencia a grupos del usuario, siempre que estos grupos se denominen \"admin\", \"user\" o \"guest\" en la notificación. La solicitud debe contener una lista, y si un usuario pertenece a varios grupos, la aplicación asignará el rol correspondiente al mayor nivel de acceso. Si ningún grupo coincide, se denegará el acceso.",
|
"LabelOpenIDGroupClaimDescription": "Nombre de la declaración OpenID que contiene una lista de grupos del usuario. Comúnmente conocidos como <code>grupos</code>. <b>Si se configura</b>, la aplicación asignará automáticamente roles en función de la pertenencia a grupos del usuario, siempre que estos grupos se denominen \"admin\", \"user\" o \"guest\" en la notificación. La solicitud debe contener una lista, y si un usuario pertenece a varios grupos, la aplicación asignará el rol correspondiente al mayor nivel de acceso. Si ningún grupo coincide, se denegará el acceso.",
|
||||||
@@ -519,7 +526,7 @@
|
|||||||
"LabelPodcasts": "Pódcast",
|
"LabelPodcasts": "Pódcast",
|
||||||
"LabelPort": "Puerto",
|
"LabelPort": "Puerto",
|
||||||
"LabelPrefixesToIgnore": "Prefijos para ignorar (no distingue entre mayúsculas y minúsculas)",
|
"LabelPrefixesToIgnore": "Prefijos para ignorar (no distingue entre mayúsculas y minúsculas)",
|
||||||
"LabelPreventIndexing": "Evite que los directorios de pódcast de iTunes y Google indicen su suministro",
|
"LabelPreventIndexing": "Evite que los directorios de pódcast de iTunes y Google indexen su suministro",
|
||||||
"LabelPrimaryEbook": "Libro electrónico principal",
|
"LabelPrimaryEbook": "Libro electrónico principal",
|
||||||
"LabelProgress": "Progreso",
|
"LabelProgress": "Progreso",
|
||||||
"LabelProvider": "Proveedor",
|
"LabelProvider": "Proveedor",
|
||||||
@@ -531,11 +538,11 @@
|
|||||||
"LabelPublishedDecades": "Décadas publicadas",
|
"LabelPublishedDecades": "Décadas publicadas",
|
||||||
"LabelPublisher": "Editor",
|
"LabelPublisher": "Editor",
|
||||||
"LabelPublishers": "Editores",
|
"LabelPublishers": "Editores",
|
||||||
"LabelRSSFeedCustomOwnerEmail": "Correo electrónico de dueño personalizado",
|
"LabelRSSFeedCustomOwnerEmail": "Correo-e de propietario personalizado",
|
||||||
"LabelRSSFeedCustomOwnerName": "Nombre de dueño personalizado",
|
"LabelRSSFeedCustomOwnerName": "Nombre de propietario personalizado",
|
||||||
"LabelRSSFeedOpen": "Fuente RSS Abierta",
|
"LabelRSSFeedOpen": "Fuente RSS Abierta",
|
||||||
"LabelRSSFeedPreventIndexing": "Evitar indización",
|
"LabelRSSFeedPreventIndexing": "Evitar indización",
|
||||||
"LabelRSSFeedSlug": "«Slug» de suministro RSS",
|
"LabelRSSFeedSlug": "Ficha de suministro RSS",
|
||||||
"LabelRSSFeedURL": "URL de suministro RSS",
|
"LabelRSSFeedURL": "URL de suministro RSS",
|
||||||
"LabelRandomly": "Aleatorio",
|
"LabelRandomly": "Aleatorio",
|
||||||
"LabelReAddSeriesToContinueListening": "Volver a agregar la serie para continuar escuchándola",
|
"LabelReAddSeriesToContinueListening": "Volver a agregar la serie para continuar escuchándola",
|
||||||
@@ -563,11 +570,12 @@
|
|||||||
"LabelSelectAll": "Seleccionar todo",
|
"LabelSelectAll": "Seleccionar todo",
|
||||||
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
|
"LabelSelectAllEpisodes": "Seleccionar todos los episodios",
|
||||||
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
|
"LabelSelectEpisodesShowing": "Seleccionar los {0} episodios visibles",
|
||||||
|
"LabelSelectUser": "Seleccionar usuario",
|
||||||
"LabelSelectUsers": "Seleccionar usuarios",
|
"LabelSelectUsers": "Seleccionar usuarios",
|
||||||
"LabelSendEbookToDevice": "Enviar libro electrónico a...",
|
"LabelSendEbookToDevice": "Enviar libro electrónico a...",
|
||||||
"LabelSequence": "Secuencia",
|
"LabelSequence": "Secuencia",
|
||||||
"LabelSerial": "En serie",
|
"LabelSerial": "En serie",
|
||||||
"LabelSeries": "Serie",
|
"LabelSeries": "Series",
|
||||||
"LabelSeriesName": "Nombre de la serie",
|
"LabelSeriesName": "Nombre de la serie",
|
||||||
"LabelSeriesProgress": "Progreso de la serie",
|
"LabelSeriesProgress": "Progreso de la serie",
|
||||||
"LabelServerLogLevel": "Nivel de registro del servidor",
|
"LabelServerLogLevel": "Nivel de registro del servidor",
|
||||||
@@ -580,8 +588,8 @@
|
|||||||
"LabelSettingsBookshelfViewHelp": "Diseño Esqueuomorfo con Estantes de Madera",
|
"LabelSettingsBookshelfViewHelp": "Diseño Esqueuomorfo con Estantes de Madera",
|
||||||
"LabelSettingsChromecastSupport": "Compatibilidad con Chromecast",
|
"LabelSettingsChromecastSupport": "Compatibilidad con Chromecast",
|
||||||
"LabelSettingsDateFormat": "Formato de Fecha",
|
"LabelSettingsDateFormat": "Formato de Fecha",
|
||||||
"LabelSettingsEnableWatcher": "Buscar cambios automáticamente en las bibliotecas",
|
"LabelSettingsEnableWatcher": "Vigilar automáticamente los cambios en bibliotecas",
|
||||||
"LabelSettingsEnableWatcherForLibrary": "Buscar cambios automáticamente en la biblioteca",
|
"LabelSettingsEnableWatcherForLibrary": "Vigilar automáticamente los cambios de biblioteca",
|
||||||
"LabelSettingsEnableWatcherHelp": "Permite agregar/actualizar elementos automáticamente cuando se detectan cambios en los archivos. *Requiere reiniciar el servidor",
|
"LabelSettingsEnableWatcherHelp": "Permite agregar/actualizar elementos automáticamente cuando se detectan cambios en los archivos. *Requiere reiniciar el servidor",
|
||||||
"LabelSettingsEpubsAllowScriptedContent": "Permitir scripts en epubs",
|
"LabelSettingsEpubsAllowScriptedContent": "Permitir scripts en epubs",
|
||||||
"LabelSettingsEpubsAllowScriptedContentHelp": "Permitir que los archivos epub ejecuten scripts. Se recomienda mantener esta opción desactivada a menos que confíe en el origen de los archivos epub.",
|
"LabelSettingsEpubsAllowScriptedContentHelp": "Permitir que los archivos epub ejecuten scripts. Se recomienda mantener esta opción desactivada a menos que confíe en el origen de los archivos epub.",
|
||||||
@@ -614,14 +622,14 @@
|
|||||||
"LabelSettingsStoreMetadataWithItemHelp": "Por defecto, los archivos de metadatos se almacenan en /metadata/items. Si habilita esta opción, los archivos de metadatos se guardarán en la carpeta de elementos de su biblioteca",
|
"LabelSettingsStoreMetadataWithItemHelp": "Por defecto, los archivos de metadatos se almacenan en /metadata/items. Si habilita esta opción, los archivos de metadatos se guardarán en la carpeta de elementos de su biblioteca",
|
||||||
"LabelSettingsTimeFormat": "Formato de Tiempo",
|
"LabelSettingsTimeFormat": "Formato de Tiempo",
|
||||||
"LabelShare": "Compartir",
|
"LabelShare": "Compartir",
|
||||||
"LabelShareDownloadableHelp": "Permite a quienes posean el enlace de compartición descargar un archivo ZIP del elemento de la biblioteca.",
|
"LabelShareDownloadableHelp": "Permite a quienes posean el enlace de compartición descargar un archivo zip del elemento de la biblioteca.",
|
||||||
"LabelShareOpen": "abrir un recurso compartido",
|
"LabelShareOpen": "abrir un recurso compartido",
|
||||||
"LabelShareURL": "Compartir la URL",
|
"LabelShareURL": "Compartir la URL",
|
||||||
"LabelShowAll": "Mostrar todo",
|
"LabelShowAll": "Mostrar todo",
|
||||||
"LabelShowSeconds": "Mostrar segundos",
|
"LabelShowSeconds": "Mostrar segundos",
|
||||||
"LabelShowSubtitles": "Mostrar subtítulos",
|
"LabelShowSubtitles": "Mostrar subtítulos",
|
||||||
"LabelSize": "Tamaño",
|
"LabelSize": "Tamaño",
|
||||||
"LabelSleepTimer": "Temporizador de apagado",
|
"LabelSleepTimer": "Temporizador de dormida",
|
||||||
"LabelSlug": "Slug",
|
"LabelSlug": "Slug",
|
||||||
"LabelSortAscending": "Ascendente",
|
"LabelSortAscending": "Ascendente",
|
||||||
"LabelSortDescending": "Descendente",
|
"LabelSortDescending": "Descendente",
|
||||||
@@ -630,6 +638,7 @@
|
|||||||
"LabelStartTime": "Tiempo de Inicio",
|
"LabelStartTime": "Tiempo de Inicio",
|
||||||
"LabelStarted": "Iniciado",
|
"LabelStarted": "Iniciado",
|
||||||
"LabelStartedAt": "Iniciado En",
|
"LabelStartedAt": "Iniciado En",
|
||||||
|
"LabelStartedDate": "Iniciado {0}",
|
||||||
"LabelStatsAudioTracks": "Pistas de Audio",
|
"LabelStatsAudioTracks": "Pistas de Audio",
|
||||||
"LabelStatsAuthors": "Autores",
|
"LabelStatsAuthors": "Autores",
|
||||||
"LabelStatsBestDay": "Mejor día",
|
"LabelStatsBestDay": "Mejor día",
|
||||||
@@ -659,6 +668,7 @@
|
|||||||
"LabelTheme": "Tema",
|
"LabelTheme": "Tema",
|
||||||
"LabelThemeDark": "Oscuro",
|
"LabelThemeDark": "Oscuro",
|
||||||
"LabelThemeLight": "Claro",
|
"LabelThemeLight": "Claro",
|
||||||
|
"LabelThemeSepia": "Sepia",
|
||||||
"LabelTimeBase": "Tiempo Base",
|
"LabelTimeBase": "Tiempo Base",
|
||||||
"LabelTimeDurationXHours": "{0} horas",
|
"LabelTimeDurationXHours": "{0} horas",
|
||||||
"LabelTimeDurationXMinutes": "{0} minutos",
|
"LabelTimeDurationXMinutes": "{0} minutos",
|
||||||
@@ -727,8 +737,10 @@
|
|||||||
"MessageAddToPlayerQueue": "Agregar a fila del Reproductor",
|
"MessageAddToPlayerQueue": "Agregar a fila del Reproductor",
|
||||||
"MessageAppriseDescription": "Para usar esta función deberás tener <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">la API de Apprise</a> corriendo o una API que maneje los mismos resultados. <br/>La URL de la API de Apprise debe tener la misma ruta de archivos que donde se envían las notificaciones. Por ejemplo: si su API esta en <code>http://192.168.1.1:8337</code> entonces pondría <code>http://192.168.1.1:8337/notify</code>.",
|
"MessageAppriseDescription": "Para usar esta función deberás tener <a href=\"https://github.com/caronc/apprise-api\" target=\"_blank\">la API de Apprise</a> corriendo o una API que maneje los mismos resultados. <br/>La URL de la API de Apprise debe tener la misma ruta de archivos que donde se envían las notificaciones. Por ejemplo: si su API esta en <code>http://192.168.1.1:8337</code> entonces pondría <code>http://192.168.1.1:8337/notify</code>.",
|
||||||
"MessageAsinCheck": "Cerciórese de usar el ASIN de la región correcta de Audible, no de Amazon.",
|
"MessageAsinCheck": "Cerciórese de usar el ASIN de la región correcta de Audible, no de Amazon.",
|
||||||
|
"MessageAuthenticationLegacyTokenWarning": "Los vales de API heredados serán retirados en el futuro. Utilice las <a href=\"/config/api-keys\">claves de API</a> en su lugar.",
|
||||||
"MessageAuthenticationOIDCChangesRestart": "Reinicie el servidor tras el guardado para aplicar los cambios de OIDC.",
|
"MessageAuthenticationOIDCChangesRestart": "Reinicie el servidor tras el guardado para aplicar los cambios de OIDC.",
|
||||||
"MessageBackupsDescription": "Los respaldos incluyen: usuarios, el progreso del los usuarios, los detalles de los elementos de la biblioteca, la configuración del servidor y las imágenes en <code>/metadata/items</code> y <code>/metadata/authors</code>. Los Respaldos <strong>NO</strong> incluyen ningún archivo guardado en la carpeta de tu biblioteca.",
|
"MessageAuthenticationSecurityMessage": "La autenticación ha sido mejorada para seguridad. Todos los usuarios requieren reiniciar sesión.",
|
||||||
|
"MessageBackupsDescription": "Los respaldos incluyen: usuarios, el progreso del los usuarios, los detalles de los elementos de la biblioteca, la configuración del servidor y las imágenes en <code>/metadata/items</code> y <code>/metadata/authors</code>. Los Respaldos <strong>no</strong> incluyen ningún archivo guardado en la carpeta de tu biblioteca.",
|
||||||
"MessageBackupsLocationEditNote": "Nota: actualizar la ubicación de la copia de respaldo no moverá ni modificará los respaldos existentes",
|
"MessageBackupsLocationEditNote": "Nota: actualizar la ubicación de la copia de respaldo no moverá ni modificará los respaldos existentes",
|
||||||
"MessageBackupsLocationNoEditNote": "Nota: la ubicación de la copia de respaldo se establece a través de una variable de entorno y no se puede cambiar aquí.",
|
"MessageBackupsLocationNoEditNote": "Nota: la ubicación de la copia de respaldo se establece a través de una variable de entorno y no se puede cambiar aquí.",
|
||||||
"MessageBackupsLocationPathEmpty": "La ruta de la copia de seguridad no puede estar vacía",
|
"MessageBackupsLocationPathEmpty": "La ruta de la copia de seguridad no puede estar vacía",
|
||||||
@@ -750,6 +762,7 @@
|
|||||||
"MessageChaptersNotFound": "Capítulos no encontrados",
|
"MessageChaptersNotFound": "Capítulos no encontrados",
|
||||||
"MessageCheckingCron": "Revisando cron...",
|
"MessageCheckingCron": "Revisando cron...",
|
||||||
"MessageConfirmCloseFeed": "¿Confirma que quiere cerrar este suministro?",
|
"MessageConfirmCloseFeed": "¿Confirma que quiere cerrar este suministro?",
|
||||||
|
"MessageConfirmDeleteApiKey": "¿Está seguro que desea eliminar la clave API «{0}»?",
|
||||||
"MessageConfirmDeleteBackup": "¿Confirma que quiere eliminar el respaldo de {0}?",
|
"MessageConfirmDeleteBackup": "¿Confirma que quiere eliminar el respaldo de {0}?",
|
||||||
"MessageConfirmDeleteDevice": "¿Confirma que quiere eliminar el lector electrónico «{0}»?",
|
"MessageConfirmDeleteDevice": "¿Confirma que quiere eliminar el lector electrónico «{0}»?",
|
||||||
"MessageConfirmDeleteFile": "Esto eliminará el archivo del sistema de archivos. ¿Quiere continuar?",
|
"MessageConfirmDeleteFile": "Esto eliminará el archivo del sistema de archivos. ¿Quiere continuar?",
|
||||||
@@ -768,8 +781,8 @@
|
|||||||
"MessageConfirmMarkSeriesFinished": "¿Confirma que quiere marcar todos los libros de esta serie como terminados?",
|
"MessageConfirmMarkSeriesFinished": "¿Confirma que quiere marcar todos los libros de esta serie como terminados?",
|
||||||
"MessageConfirmMarkSeriesNotFinished": "¿Confirma que quiere marcar todos los libros de esta serie como no terminados?",
|
"MessageConfirmMarkSeriesNotFinished": "¿Confirma que quiere marcar todos los libros de esta serie como no terminados?",
|
||||||
"MessageConfirmNotificationTestTrigger": "¿Activar esta notificación con datos de prueba?",
|
"MessageConfirmNotificationTestTrigger": "¿Activar esta notificación con datos de prueba?",
|
||||||
"MessageConfirmPurgeCache": "Purgar la antememoria eliminará el directorio completo ubicado en <code>/metadata/cache</code>. <br /><br />¿Confirma que quiere eliminar el directorio de antememoria?",
|
"MessageConfirmPurgeCache": "La purga del caché eliminará el directorio completo en <code>/metadata/cache</code>. <br /><br />¿Confirma que desea quitar el directorio de caché?",
|
||||||
"MessageConfirmPurgeItemsCache": "Purgar la antememoria de elementos eliminará el directorio completo ubicado en <code>/metadata/cache/items</code>.<br />¿Lo confirma?",
|
"MessageConfirmPurgeItemsCache": "Purgar el caché de elementos eliminará el directorio completo ubicado en <code>/metadata/cache/items</code>.<br />¿Lo confirma?",
|
||||||
"MessageConfirmQuickEmbed": "Atención: la incrustación rápida no realiza copias de respaldo a ninguno de sus archivos de audio. Cerciórese de haber realizado una copia de los mismos previamente. <br><br>¿Quiere continuar?",
|
"MessageConfirmQuickEmbed": "Atención: la incrustación rápida no realiza copias de respaldo a ninguno de sus archivos de audio. Cerciórese de haber realizado una copia de los mismos previamente. <br><br>¿Quiere continuar?",
|
||||||
"MessageConfirmQuickMatchEpisodes": "El reconocimiento rápido de extensiones sobrescribirá los detalles si se encuentra una coincidencia. Se actualizarán las extensiones no reconocidas. ¿Quiere continuar?",
|
"MessageConfirmQuickMatchEpisodes": "El reconocimiento rápido de extensiones sobrescribirá los detalles si se encuentra una coincidencia. Se actualizarán las extensiones no reconocidas. ¿Quiere continuar?",
|
||||||
"MessageConfirmReScanLibraryItems": "¿Confirma que quiere volver a analizar {0} elementos?",
|
"MessageConfirmReScanLibraryItems": "¿Confirma que quiere volver a analizar {0} elementos?",
|
||||||
@@ -795,14 +808,16 @@
|
|||||||
"MessageDaysListenedInTheLastYear": "{0} días escuchados el año pasado",
|
"MessageDaysListenedInTheLastYear": "{0} días escuchados el año pasado",
|
||||||
"MessageDownloadingEpisode": "Descargando episodio",
|
"MessageDownloadingEpisode": "Descargando episodio",
|
||||||
"MessageDragFilesIntoTrackOrder": "Arrastre los archivos al orden correcto de las pistas",
|
"MessageDragFilesIntoTrackOrder": "Arrastre los archivos al orden correcto de las pistas",
|
||||||
"MessageEmbedFailed": "Falló la incrustación.",
|
"MessageEmbedFailed": "Incorporación incorrecta.",
|
||||||
"MessageEmbedFinished": "Finalizó la incrustación.",
|
"MessageEmbedFinished": "Incorporación finalizada.",
|
||||||
"MessageEmbedQueue": "En cola para incrustar metadatos ({0} en cola)",
|
"MessageEmbedQueue": "En cola para incrustar metadatos ({0} en cola)",
|
||||||
"MessageEpisodesQueuedForDownload": "{0} episodio(s) en cola para descargar",
|
"MessageEpisodesQueuedForDownload": "{0} episodio(s) en cola para descargar",
|
||||||
"MessageEreaderDevices": "Para garantizar la entrega de libros electrónicos, es posible que tenga que agregar la dirección de correo electrónico anterior como remitente válido para cada dispositivo enumerado a continuación.",
|
"MessageEreaderDevices": "Para garantizar la entrega de libros electrónicos, es posible que tenga que agregar la dirección de correo electrónico anterior como remitente válido para cada dispositivo enumerado a continuación.",
|
||||||
"MessageFeedURLWillBe": "El URL del suministro será {0}",
|
"MessageFeedURLWillBe": "El URL del suministro será {0}",
|
||||||
"MessageFetching": "Recuperando...",
|
"MessageFetching": "Recuperando...",
|
||||||
"MessageForceReScanDescription": "Escaneará todos los archivos como un nuevo escaneo. Archivos de audio con etiquetas ID3, archivos OPF y archivos de texto serán escaneados como nuevos.",
|
"MessageForceReScanDescription": "Escaneará todos los archivos como un nuevo escaneo. Archivos de audio con etiquetas ID3, archivos OPF y archivos de texto serán escaneados como nuevos.",
|
||||||
|
"MessageHeatmapListeningTimeTooltip": "<strong>{0} escuchando</strong> en {1}",
|
||||||
|
"MessageHeatmapNoListeningSessions": "No enumera sesiones en {0}",
|
||||||
"MessageImportantNotice": "¡Notificación importante!",
|
"MessageImportantNotice": "¡Notificación importante!",
|
||||||
"MessageInsertChapterBelow": "Insertar capítulo debajo",
|
"MessageInsertChapterBelow": "Insertar capítulo debajo",
|
||||||
"MessageInvalidAsin": "ASIN no válido",
|
"MessageInvalidAsin": "ASIN no válido",
|
||||||
@@ -835,7 +850,7 @@
|
|||||||
"MessageNoEpisodes": "Ningún episodio",
|
"MessageNoEpisodes": "Ningún episodio",
|
||||||
"MessageNoFoldersAvailable": "Ninguna carpeta disponible",
|
"MessageNoFoldersAvailable": "Ninguna carpeta disponible",
|
||||||
"MessageNoGenres": "Ningún género",
|
"MessageNoGenres": "Ningún género",
|
||||||
"MessageNoIssues": "Ningún número",
|
"MessageNoIssues": "Sin incidencias",
|
||||||
"MessageNoItems": "Ningún elemento",
|
"MessageNoItems": "Ningún elemento",
|
||||||
"MessageNoItemsFound": "Ningún elemento encontrado",
|
"MessageNoItemsFound": "Ningún elemento encontrado",
|
||||||
"MessageNoListeningSessions": "Ninguna sesión de escucha",
|
"MessageNoListeningSessions": "Ninguna sesión de escucha",
|
||||||
@@ -873,7 +888,7 @@
|
|||||||
"MessageResetChaptersConfirm": "¿Confirma que quiere deshacer los cambios y restablecer los capítulos a su estado original?",
|
"MessageResetChaptersConfirm": "¿Confirma que quiere deshacer los cambios y restablecer los capítulos a su estado original?",
|
||||||
"MessageRestoreBackupConfirm": "¿Confirma que quiere restaurar el respaldo creado el",
|
"MessageRestoreBackupConfirm": "¿Confirma que quiere restaurar el respaldo creado el",
|
||||||
"MessageRestoreBackupWarning": "Restaurar sobrescribirá toda la base de datos localizada en /config y las imágenes de portadas en /metadata/items y /metadata/authors.<br /><br />El respaldo no modifica ningún archivo en las carpetas de su biblioteca. Si ha habilitado la opción del servidor para almacenar portadas y metadata en las carpetas de su biblioteca, esos archivos no se respaldan o sobrescriben.<br /><br />Todos los clientes que usen su servidor se actualizarán automáticamente.",
|
"MessageRestoreBackupWarning": "Restaurar sobrescribirá toda la base de datos localizada en /config y las imágenes de portadas en /metadata/items y /metadata/authors.<br /><br />El respaldo no modifica ningún archivo en las carpetas de su biblioteca. Si ha habilitado la opción del servidor para almacenar portadas y metadata en las carpetas de su biblioteca, esos archivos no se respaldan o sobrescriben.<br /><br />Todos los clientes que usen su servidor se actualizarán automáticamente.",
|
||||||
"MessageScheduleLibraryScanNote": "Para la mayoría de los usuarios, se recomienda dejar esta función desactivada y mantener activada la configuración del observador de carpetas. El observador de carpetas detectará automáticamente los cambios en las carpetas de la biblioteca. El observador de carpetas no funciona para todos los sistemas de archivos (como NFS), por lo que se pueden utilizar exploraciones programadas de la biblioteca en su lugar.",
|
"MessageScheduleLibraryScanNote": "Para muchos usuarios, es recomendado dejar esta característica inhabilitada y mantener habilitados los ajustes de la «Vigía automática de cambio de biblioteca»: detectará automáticamente los cambios en sus carpetas de bibliotecas. Habilitar esta características si «Vigía automática de cambio de biblioteca» no funciona en su sistema de archivo (como NFS).",
|
||||||
"MessageScheduleRunEveryWeekdayAtTime": "Ejecutar cada {0} a las {1}",
|
"MessageScheduleRunEveryWeekdayAtTime": "Ejecutar cada {0} a las {1}",
|
||||||
"MessageSearchResultsFor": "Resultados de la búsqueda de",
|
"MessageSearchResultsFor": "Resultados de la búsqueda de",
|
||||||
"MessageSelected": "{0} seleccionado(s)",
|
"MessageSelected": "{0} seleccionado(s)",
|
||||||
@@ -999,6 +1014,8 @@
|
|||||||
"ToastBulkChapterInvalidCount": "Por favor ingrese un número válido entre 1 y 150",
|
"ToastBulkChapterInvalidCount": "Por favor ingrese un número válido entre 1 y 150",
|
||||||
"ToastCachePurgeFailed": "No se pudo purgar la antememoria",
|
"ToastCachePurgeFailed": "No se pudo purgar la antememoria",
|
||||||
"ToastCachePurgeSuccess": "Se purgó la antememoria correctamente",
|
"ToastCachePurgeSuccess": "Se purgó la antememoria correctamente",
|
||||||
|
"ToastChapterLocked": "El capítulo está bloqueado.",
|
||||||
|
"ToastChapterStartTimeAdjusted": "El capítulo inicia el tiempo ajustado en {0} segundos",
|
||||||
"ToastChaptersAllLocked": "Todos los capítulos están bloqueados. Desbloquee algunos capítulos para cambiar sus tiempos.",
|
"ToastChaptersAllLocked": "Todos los capítulos están bloqueados. Desbloquee algunos capítulos para cambiar sus tiempos.",
|
||||||
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
|
"ToastChaptersHaveErrors": "Los capítulos tienen errores",
|
||||||
"ToastChaptersInvalidShiftAmountLast": "Cantidad de desplazamiento no válida. La hora de inicio del último capítulo se extendería más allá de la duración de este audiolibro.",
|
"ToastChaptersInvalidShiftAmountLast": "Cantidad de desplazamiento no válida. La hora de inicio del último capítulo se extendería más allá de la duración de este audiolibro.",
|
||||||
@@ -1009,6 +1026,8 @@
|
|||||||
"ToastCollectionItemsAddFailed": "Artículo(s) añadido(s) a la colección fallido(s)",
|
"ToastCollectionItemsAddFailed": "Artículo(s) añadido(s) a la colección fallido(s)",
|
||||||
"ToastCollectionRemoveSuccess": "Colección quitada",
|
"ToastCollectionRemoveSuccess": "Colección quitada",
|
||||||
"ToastCollectionUpdateSuccess": "Colección actualizada",
|
"ToastCollectionUpdateSuccess": "Colección actualizada",
|
||||||
|
"ToastConnectionNotAvailable": "Conexión no disponible. Intenta de nuevo más tarde",
|
||||||
|
"ToastCoverSearchFailed": "Cobertura de búsqueda incorrecta",
|
||||||
"ToastCoverUpdateFailed": "Error al actualizar la cubierta",
|
"ToastCoverUpdateFailed": "Error al actualizar la cubierta",
|
||||||
"ToastDateTimeInvalidOrIncomplete": "Fecha y hora no válidas o incompletas",
|
"ToastDateTimeInvalidOrIncomplete": "Fecha y hora no válidas o incompletas",
|
||||||
"ToastDeleteFileFailed": "Falló la eliminación del archivo",
|
"ToastDeleteFileFailed": "Falló la eliminación del archivo",
|
||||||
@@ -1024,6 +1043,8 @@
|
|||||||
"ToastEpisodeDownloadQueueClearSuccess": "Se borró la cola de descargas de los episodios",
|
"ToastEpisodeDownloadQueueClearSuccess": "Se borró la cola de descargas de los episodios",
|
||||||
"ToastEpisodeUpdateSuccess": "{0} episodio(s) actualizado(s)",
|
"ToastEpisodeUpdateSuccess": "{0} episodio(s) actualizado(s)",
|
||||||
"ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo",
|
"ToastErrorCannotShare": "No se puede compartir de forma nativa en este dispositivo",
|
||||||
|
"ToastFailedToCreate": "Ha fallado al crear",
|
||||||
|
"ToastFailedToDelete": "Ha fallado al eliminar",
|
||||||
"ToastFailedToLoadData": "Error al cargar data",
|
"ToastFailedToLoadData": "Error al cargar data",
|
||||||
"ToastFailedToMatch": "Error al emparejar",
|
"ToastFailedToMatch": "Error al emparejar",
|
||||||
"ToastFailedToShare": "Error al compartir",
|
"ToastFailedToShare": "Error al compartir",
|
||||||
@@ -1031,6 +1052,7 @@
|
|||||||
"ToastInvalidImageUrl": "URL de la imagen no válida",
|
"ToastInvalidImageUrl": "URL de la imagen no válida",
|
||||||
"ToastInvalidMaxEpisodesToDownload": "Número máximo de episodios para descargar no válidos",
|
"ToastInvalidMaxEpisodesToDownload": "Número máximo de episodios para descargar no válidos",
|
||||||
"ToastInvalidUrl": "URL no válida",
|
"ToastInvalidUrl": "URL no válida",
|
||||||
|
"ToastInvalidUrls": "Una o más URL son inválidas",
|
||||||
"ToastItemCoverUpdateSuccess": "Cubierta del elemento actualizada",
|
"ToastItemCoverUpdateSuccess": "Cubierta del elemento actualizada",
|
||||||
"ToastItemDeletedFailed": "Error al eliminar el elemento",
|
"ToastItemDeletedFailed": "Error al eliminar el elemento",
|
||||||
"ToastItemDeletedSuccess": "Elemento borrado",
|
"ToastItemDeletedSuccess": "Elemento borrado",
|
||||||
@@ -1055,6 +1077,7 @@
|
|||||||
"ToastMustHaveAtLeastOnePath": "Debe tener al menos una ruta",
|
"ToastMustHaveAtLeastOnePath": "Debe tener al menos una ruta",
|
||||||
"ToastNameEmailRequired": "Son obligatorios el nombre y el correo electrónico",
|
"ToastNameEmailRequired": "Son obligatorios el nombre y el correo electrónico",
|
||||||
"ToastNameRequired": "Nombre obligatorio",
|
"ToastNameRequired": "Nombre obligatorio",
|
||||||
|
"ToastNewApiKeyUserError": "Debe seleccionar un usuario",
|
||||||
"ToastNewEpisodesFound": "{0} nuevo(s) episodio(s) encontrado(s)",
|
"ToastNewEpisodesFound": "{0} nuevo(s) episodio(s) encontrado(s)",
|
||||||
"ToastNewUserCreatedFailed": "No se pudo crear la cuenta: «{0}»",
|
"ToastNewUserCreatedFailed": "No se pudo crear la cuenta: «{0}»",
|
||||||
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
|
"ToastNewUserCreatedSuccess": "Nueva cuenta creada",
|
||||||
@@ -1093,8 +1116,8 @@
|
|||||||
"ToastRemoveFailed": "Error al eliminar",
|
"ToastRemoveFailed": "Error al eliminar",
|
||||||
"ToastRemoveItemFromCollectionFailed": "Error al eliminar el elemento de la colección",
|
"ToastRemoveItemFromCollectionFailed": "Error al eliminar el elemento de la colección",
|
||||||
"ToastRemoveItemFromCollectionSuccess": "Elemento eliminado de la colección",
|
"ToastRemoveItemFromCollectionSuccess": "Elemento eliminado de la colección",
|
||||||
"ToastRemoveItemsWithIssuesFailed": "Error en la eliminación de artículos de biblioteca incorrectos",
|
"ToastRemoveItemsWithIssuesFailed": "Error en la eliminación de artículos de biblioteca con incidencias",
|
||||||
"ToastRemoveItemsWithIssuesSuccess": "Se eliminaron artículos de biblioteca incorrectos",
|
"ToastRemoveItemsWithIssuesSuccess": "Se eliminaron artículos de biblioteca con incidencias",
|
||||||
"ToastRenameFailed": "Error al cambiar el nombre",
|
"ToastRenameFailed": "Error al cambiar el nombre",
|
||||||
"ToastRescanFailed": "Error al volver a escanear para {0}",
|
"ToastRescanFailed": "Error al volver a escanear para {0}",
|
||||||
"ToastRescanRemoved": "Se eliminó el elemento reescaneado",
|
"ToastRescanRemoved": "Se eliminó el elemento reescaneado",
|
||||||
@@ -1133,6 +1156,7 @@
|
|||||||
"ToastUserRootRequireName": "Debe introducir un nombre de usuario administrativo",
|
"ToastUserRootRequireName": "Debe introducir un nombre de usuario administrativo",
|
||||||
"TooltipAddChapters": "Añadir capítulo(s)",
|
"TooltipAddChapters": "Añadir capítulo(s)",
|
||||||
"TooltipAddOneSecond": "Añadir 1 segundo",
|
"TooltipAddOneSecond": "Añadir 1 segundo",
|
||||||
|
"TooltipAdjustChapterStart": "Pulse para ajustar la hora de inicio",
|
||||||
"TooltipLockAllChapters": "Bloquear todos los capítulos",
|
"TooltipLockAllChapters": "Bloquear todos los capítulos",
|
||||||
"TooltipLockChapter": "Bloquear capítulo (Mayús+clic para rango)",
|
"TooltipLockChapter": "Bloquear capítulo (Mayús+clic para rango)",
|
||||||
"TooltipSubtractOneSecond": "Restar 1 segundo",
|
"TooltipSubtractOneSecond": "Restar 1 segundo",
|
||||||
|
|||||||
@@ -622,7 +622,7 @@
|
|||||||
"LabelSettingsStoreMetadataWithItemHelp": "Par défaut, les fichiers de métadonnées sont stockés dans /metadata/items. En activant ce paramètre, les fichiers de métadonnées seront stockés dans les dossiers des éléments de votre bibliothèque",
|
"LabelSettingsStoreMetadataWithItemHelp": "Par défaut, les fichiers de métadonnées sont stockés dans /metadata/items. En activant ce paramètre, les fichiers de métadonnées seront stockés dans les dossiers des éléments de votre bibliothèque",
|
||||||
"LabelSettingsTimeFormat": "Format d’heure",
|
"LabelSettingsTimeFormat": "Format d’heure",
|
||||||
"LabelShare": "Partager",
|
"LabelShare": "Partager",
|
||||||
"LabelShareDownloadableHelp": "Permet aux utilisateurs de télécharger un fichier ZIP de l'élément de la bibliothèque.",
|
"LabelShareDownloadableHelp": "Permet aux utilisateurs disposant du lien de partage de télécharger un fichier zip contenant l'élément de la bibliothèque.",
|
||||||
"LabelShareOpen": "Ouvrir le partage",
|
"LabelShareOpen": "Ouvrir le partage",
|
||||||
"LabelShareURL": "Partager l’URL",
|
"LabelShareURL": "Partager l’URL",
|
||||||
"LabelShowAll": "Tout afficher",
|
"LabelShowAll": "Tout afficher",
|
||||||
|
|||||||
+12
-12
@@ -34,7 +34,7 @@
|
|||||||
"ButtonEditChapters": "Modifica Capitoli",
|
"ButtonEditChapters": "Modifica Capitoli",
|
||||||
"ButtonEditPodcast": "Modifica Podcast",
|
"ButtonEditPodcast": "Modifica Podcast",
|
||||||
"ButtonEnable": "Abilita",
|
"ButtonEnable": "Abilita",
|
||||||
"ButtonFireAndFail": "Fire and Fail",
|
"ButtonFireAndFail": "Centro e fallimento",
|
||||||
"ButtonFireOnTest": "Fire onTest event",
|
"ButtonFireOnTest": "Fire onTest event",
|
||||||
"ButtonForceReScan": "Forza Re-Scan",
|
"ButtonForceReScan": "Forza Re-Scan",
|
||||||
"ButtonFullPath": "Percorso Completo",
|
"ButtonFullPath": "Percorso Completo",
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
"HeaderPlaylist": "Playlist",
|
"HeaderPlaylist": "Playlist",
|
||||||
"HeaderPlaylistItems": "Elementi della playlist",
|
"HeaderPlaylistItems": "Elementi della playlist",
|
||||||
"HeaderPodcastsToAdd": "Podcasts da Aggiungere",
|
"HeaderPodcastsToAdd": "Podcasts da Aggiungere",
|
||||||
"HeaderPresets": "Presets",
|
"HeaderPresets": "Preimpostazioni",
|
||||||
"HeaderPreviewCover": "Anteprima Cover",
|
"HeaderPreviewCover": "Anteprima Cover",
|
||||||
"HeaderRSSFeedGeneral": "Dettagli RSS",
|
"HeaderRSSFeedGeneral": "Dettagli RSS",
|
||||||
"HeaderRSSFeedIsOpen": "RSS Feed è aperto",
|
"HeaderRSSFeedIsOpen": "RSS Feed è aperto",
|
||||||
@@ -306,7 +306,7 @@
|
|||||||
"LabelCustomCronExpression": "Espressione Cron personalizzata:",
|
"LabelCustomCronExpression": "Espressione Cron personalizzata:",
|
||||||
"LabelDatetime": "Data & Ora",
|
"LabelDatetime": "Data & Ora",
|
||||||
"LabelDays": "Giorni",
|
"LabelDays": "Giorni",
|
||||||
"LabelDeleteFromFileSystemCheckbox": "Elimina dal file system (togli la spunta per eliminarla solo dal DB)",
|
"LabelDeleteFromFileSystemCheckbox": "Elimina dal file system (despunta per rimuoverla solo dal database)",
|
||||||
"LabelDescription": "Descrizione",
|
"LabelDescription": "Descrizione",
|
||||||
"LabelDeselectAll": "Deseleziona Tutto",
|
"LabelDeselectAll": "Deseleziona Tutto",
|
||||||
"LabelDetectedPattern": "Trovato pattern:",
|
"LabelDetectedPattern": "Trovato pattern:",
|
||||||
@@ -436,9 +436,9 @@
|
|||||||
"LabelLibraryFilterSublistEmpty": "Nessuno {0}",
|
"LabelLibraryFilterSublistEmpty": "Nessuno {0}",
|
||||||
"LabelLibraryItem": "Elementi della biblioteca",
|
"LabelLibraryItem": "Elementi della biblioteca",
|
||||||
"LabelLibraryName": "Nome della biblioteca",
|
"LabelLibraryName": "Nome della biblioteca",
|
||||||
"LabelLibrarySortByProgress": "Progressi: Ultimi aggiornamenti",
|
"LabelLibrarySortByProgress": "Progresso: ultimo aggiornamento",
|
||||||
"LabelLibrarySortByProgressFinished": "Progressi: Completati",
|
"LabelLibrarySortByProgressFinished": "Progresso: finito",
|
||||||
"LabelLibrarySortByProgressStarted": "Progressi: Iniziati",
|
"LabelLibrarySortByProgressStarted": "Progresso: iniziato",
|
||||||
"LabelLimit": "Limiti",
|
"LabelLimit": "Limiti",
|
||||||
"LabelLineSpacing": "Interlinea",
|
"LabelLineSpacing": "Interlinea",
|
||||||
"LabelListenAgain": "Ascolta ancora",
|
"LabelListenAgain": "Ascolta ancora",
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
"LabelNumberOfBooks": "Numero di libri",
|
"LabelNumberOfBooks": "Numero di libri",
|
||||||
"LabelNumberOfChapters": "Numero di capitoli:",
|
"LabelNumberOfChapters": "Numero di capitoli:",
|
||||||
"LabelNumberOfEpisodes": "Numero di episodi",
|
"LabelNumberOfEpisodes": "Numero di episodi",
|
||||||
"LabelOpenIDAdvancedPermsClaimDescription": "Nome dell'attestazione OpenID che contiene autorizzazioni avanzate per le azioni dell'utente all'interno dell'applicazione che verranno applicate ai ruoli non amministratori (<b>se configurato</b>). Se il reclamo manca nella risposta, l'accesso ad ABS verrà negato. Se manca una singola opzione, verrà trattata come<code>falsa</code>. Assicurati che l'attestazione del provider di identità corrisponda alla struttura prevista:",
|
"LabelOpenIDAdvancedPermsClaimDescription": "Nome dell'attestazione OpenID che contiene autorizzazioni avanzate per le azioni dell'utente all'interno dell'applicazione che verranno applicate ai ruoli non amministrativi (<b>se configurato</b>). Se il reclamo manca nella risposta, l'accesso ad ABS verrà negato. Se manca una singola opzione, verrà trattata come <code>falso</code>. Assicurati che l'attestazione del provider di identità corrisponda alla struttura prevista:",
|
||||||
"LabelOpenIDClaims": "Lasciare vuote le seguenti opzioni per disabilitare l'assegnazione avanzata di gruppi e autorizzazioni, assegnando quindi automaticamente il gruppo \"Utente\".",
|
"LabelOpenIDClaims": "Lasciare vuote le seguenti opzioni per disabilitare l'assegnazione avanzata di gruppi e autorizzazioni, assegnando quindi automaticamente il gruppo \"Utente\".",
|
||||||
"LabelOpenIDGroupClaimDescription": "Nome dell'attestazione OpenID che contiene un elenco dei gruppi dell'utente. Comunemente indicato come <code>gruppo</code>. <b>se configurato</b>, l'applicazione assegnerà automaticamente i ruoli in base alle appartenenze ai gruppi dell'utente, a condizione che tali gruppi siano denominati \"admin\", \"utente\" o \"ospite\" senza distinzione tra maiuscole e minuscole nell'attestazione. L'attestazione deve contenere un elenco e, se un utente appartiene a più gruppi, l'applicazione assegnerà il ruolo corrispondente al livello di accesso più alto. Se nessun gruppo corrisponde, l'accesso verrà negato.",
|
"LabelOpenIDGroupClaimDescription": "Nome dell'attestazione OpenID che contiene un elenco dei gruppi dell'utente. Comunemente indicato come <code>gruppo</code>. <b>se configurato</b>, l'applicazione assegnerà automaticamente i ruoli in base alle appartenenze ai gruppi dell'utente, a condizione che tali gruppi siano denominati \"admin\", \"utente\" o \"ospite\" senza distinzione tra maiuscole e minuscole nell'attestazione. L'attestazione deve contenere un elenco e, se un utente appartiene a più gruppi, l'applicazione assegnerà il ruolo corrispondente al livello di accesso più alto. Se nessun gruppo corrisponde, l'accesso verrà negato.",
|
||||||
"LabelOpenRSSFeed": "Apri RSS Feed",
|
"LabelOpenRSSFeed": "Apri RSS Feed",
|
||||||
@@ -530,7 +530,7 @@
|
|||||||
"LabelPrimaryEbook": "Libro principale",
|
"LabelPrimaryEbook": "Libro principale",
|
||||||
"LabelProgress": "Cominciati",
|
"LabelProgress": "Cominciati",
|
||||||
"LabelProvider": "Fornitore",
|
"LabelProvider": "Fornitore",
|
||||||
"LabelProviderAuthorizationValue": "Authorization Header Value",
|
"LabelProviderAuthorizationValue": "Valore intestazione di autorizzazione",
|
||||||
"LabelPubDate": "Data di pubblicazione",
|
"LabelPubDate": "Data di pubblicazione",
|
||||||
"LabelPublishYear": "Anno di pubblicazione",
|
"LabelPublishYear": "Anno di pubblicazione",
|
||||||
"LabelPublishedDate": "Pubblicati {0}",
|
"LabelPublishedDate": "Pubblicati {0}",
|
||||||
@@ -674,7 +674,7 @@
|
|||||||
"LabelTimeDurationXMinutes": "{0} minuti",
|
"LabelTimeDurationXMinutes": "{0} minuti",
|
||||||
"LabelTimeDurationXSeconds": "{0} secondi",
|
"LabelTimeDurationXSeconds": "{0} secondi",
|
||||||
"LabelTimeInMinutes": "Tempo in minuti",
|
"LabelTimeInMinutes": "Tempo in minuti",
|
||||||
"LabelTimeLeft": "{0} sinistra",
|
"LabelTimeLeft": "{0} rimasti",
|
||||||
"LabelTimeListened": "Tempo di Ascolto",
|
"LabelTimeListened": "Tempo di Ascolto",
|
||||||
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
"LabelTimeListenedToday": "Tempo di Ascolto Oggi",
|
||||||
"LabelTimeRemaining": "{0} rimanente",
|
"LabelTimeRemaining": "{0} rimanente",
|
||||||
@@ -682,7 +682,7 @@
|
|||||||
"LabelTitle": "Titolo",
|
"LabelTitle": "Titolo",
|
||||||
"LabelToolsEmbedMetadata": "Incorpora Metadata",
|
"LabelToolsEmbedMetadata": "Incorpora Metadata",
|
||||||
"LabelToolsEmbedMetadataDescription": "Incorpora i metadati nei file audio, inclusi l'immagine di copertina e i capitoli.",
|
"LabelToolsEmbedMetadataDescription": "Incorpora i metadati nei file audio, inclusi l'immagine di copertina e i capitoli.",
|
||||||
"LabelToolsM4bEncoder": "M4B Encoder",
|
"LabelToolsM4bEncoder": "Codificatore M4B",
|
||||||
"LabelToolsMakeM4b": "Crea un file M4B",
|
"LabelToolsMakeM4b": "Crea un file M4B",
|
||||||
"LabelToolsMakeM4bDescription": "Genera un file audiolibro M4B con metadati incorporati, immagine di copertina e capitoli.",
|
"LabelToolsMakeM4bDescription": "Genera un file audiolibro M4B con metadati incorporati, immagine di copertina e capitoli.",
|
||||||
"LabelToolsSplitM4b": "Converti M4B in MP3",
|
"LabelToolsSplitM4b": "Converti M4B in MP3",
|
||||||
@@ -854,7 +854,7 @@
|
|||||||
"MessageNoItems": "Nessun oggetto",
|
"MessageNoItems": "Nessun oggetto",
|
||||||
"MessageNoItemsFound": "Nessun oggetto trovato",
|
"MessageNoItemsFound": "Nessun oggetto trovato",
|
||||||
"MessageNoListeningSessions": "Nessuna sessione di ascolto",
|
"MessageNoListeningSessions": "Nessuna sessione di ascolto",
|
||||||
"MessageNoLogs": "Nessun Log",
|
"MessageNoLogs": "Nessun rapporto",
|
||||||
"MessageNoMediaProgress": "Nessun progresso multimediale",
|
"MessageNoMediaProgress": "Nessun progresso multimediale",
|
||||||
"MessageNoNotifications": "Nessuna notifica",
|
"MessageNoNotifications": "Nessuna notifica",
|
||||||
"MessageNoPodcastFeed": "Podcast non valido: nessun feed",
|
"MessageNoPodcastFeed": "Podcast non valido: nessun feed",
|
||||||
@@ -1109,7 +1109,7 @@
|
|||||||
"ToastProgressIsNotBeingSynced": "L'avanzamento non è sincronizzato, riavviare la riproduzione",
|
"ToastProgressIsNotBeingSynced": "L'avanzamento non è sincronizzato, riavviare la riproduzione",
|
||||||
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
|
"ToastProviderCreatedFailed": "Impossibile aggiungere il provider",
|
||||||
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
|
"ToastProviderCreatedSuccess": "Aggiunto nuovo provider",
|
||||||
"ToastProviderNameAndUrlRequired": "Nome e URL richiesti",
|
"ToastProviderNameAndUrlRequired": "Nome e Url richiesti",
|
||||||
"ToastProviderRemoveSuccess": "Provider rimosso",
|
"ToastProviderRemoveSuccess": "Provider rimosso",
|
||||||
"ToastRSSFeedCloseFailed": "Errore chiusura flusso RSS",
|
"ToastRSSFeedCloseFailed": "Errore chiusura flusso RSS",
|
||||||
"ToastRSSFeedCloseSuccess": "Flusso RSS chiuso",
|
"ToastRSSFeedCloseSuccess": "Flusso RSS chiuso",
|
||||||
|
|||||||
@@ -392,7 +392,7 @@
|
|||||||
"LabelGenre": "Жанр",
|
"LabelGenre": "Жанр",
|
||||||
"LabelGenres": "Жанры",
|
"LabelGenres": "Жанры",
|
||||||
"LabelHardDeleteFile": "Жесткое удаление файла",
|
"LabelHardDeleteFile": "Жесткое удаление файла",
|
||||||
"LabelHasEbook": "Есть e-книга",
|
"LabelHasEbook": "Есть электронная книга",
|
||||||
"LabelHasSupplementaryEbook": "Есть дополнительная e-книга",
|
"LabelHasSupplementaryEbook": "Есть дополнительная e-книга",
|
||||||
"LabelHideSubtitles": "Скрыть серии",
|
"LabelHideSubtitles": "Скрыть серии",
|
||||||
"LabelHighestPriority": "Наивысший приоритет",
|
"LabelHighestPriority": "Наивысший приоритет",
|
||||||
@@ -437,8 +437,8 @@
|
|||||||
"LabelLibraryItem": "Элемент библиотеки",
|
"LabelLibraryItem": "Элемент библиотеки",
|
||||||
"LabelLibraryName": "Имя библиотеки",
|
"LabelLibraryName": "Имя библиотеки",
|
||||||
"LabelLibrarySortByProgress": "Прогресс: Последнее обновление",
|
"LabelLibrarySortByProgress": "Прогресс: Последнее обновление",
|
||||||
"LabelLibrarySortByProgressFinished": "Прогресс: Завершено",
|
"LabelLibrarySortByProgressFinished": "Прогресс: Закончена",
|
||||||
"LabelLibrarySortByProgressStarted": "Прогресс: Начато",
|
"LabelLibrarySortByProgressStarted": "Прогресс: Начата",
|
||||||
"LabelLimit": "Лимит",
|
"LabelLimit": "Лимит",
|
||||||
"LabelLineSpacing": "Межстрочный интервал",
|
"LabelLineSpacing": "Межстрочный интервал",
|
||||||
"LabelListenAgain": "Послушать снова",
|
"LabelListenAgain": "Послушать снова",
|
||||||
|
|||||||
@@ -275,7 +275,7 @@
|
|||||||
"LabelBonus": "Bonus",
|
"LabelBonus": "Bonus",
|
||||||
"LabelBooks": "Knihy",
|
"LabelBooks": "Knihy",
|
||||||
"LabelButtonText": "Text tlačidla",
|
"LabelButtonText": "Text tlačidla",
|
||||||
"LabelByAuthor": "od",
|
"LabelByAuthor": "od {0}",
|
||||||
"LabelChangePassword": "Zmeniť heslo",
|
"LabelChangePassword": "Zmeniť heslo",
|
||||||
"LabelChannels": "Kanály",
|
"LabelChannels": "Kanály",
|
||||||
"LabelChapterCount": "{0} kapitol",
|
"LabelChapterCount": "{0} kapitol",
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "audiobookshelf",
|
"name": "audiobookshelf",
|
||||||
"version": "2.33.0",
|
"version": "2.33.2",
|
||||||
"buildNumber": 1,
|
"buildNumber": 1,
|
||||||
"description": "Self-hosted audiobook and podcast server",
|
"description": "Self-hosted audiobook and podcast server",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
|
|||||||
@@ -234,6 +234,13 @@ class TokenManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const user = await Database.userModel.getUserById(apiKey.userId)
|
const user = await Database.userModel.getUserById(apiKey.userId)
|
||||||
|
|
||||||
|
if (!user?.isActive) {
|
||||||
|
// deny login
|
||||||
|
done(null, null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
done(null, user)
|
done(null, user)
|
||||||
} else {
|
} else {
|
||||||
// JWT based authentication
|
// JWT based authentication
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const CacheManager = require('../managers/CacheManager')
|
|||||||
const CoverManager = require('../managers/CoverManager')
|
const CoverManager = require('../managers/CoverManager')
|
||||||
const AuthorFinder = require('../finders/AuthorFinder')
|
const AuthorFinder = require('../finders/AuthorFinder')
|
||||||
|
|
||||||
const { reqSupportsWebp, isValidASIN } = require('../utils/index')
|
const { reqSupportsWebp, isValidASIN, clampPositiveInt } = require('../utils/index')
|
||||||
|
|
||||||
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
|
||||||
@@ -412,8 +412,8 @@ class AuthorController {
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
format: format || (reqSupportsWebp(req) ? 'webp' : 'jpeg'),
|
format: format || (reqSupportsWebp(req) ? 'webp' : 'jpeg'),
|
||||||
height: height ? parseInt(height) : null,
|
height: clampPositiveInt(height ? parseInt(height) : null, 4096),
|
||||||
width: width ? parseInt(width) : null
|
width: clampPositiveInt(width ? parseInt(width) : null, 4096)
|
||||||
}
|
}
|
||||||
return CacheManager.handleAuthorCache(res, authorId, options)
|
return CacheManager.handleAuthorCache(res, authorId, options)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const Sequelize = require('sequelize')
|
|||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
const htmlSanitizer = require('../utils/htmlSanitizer')
|
||||||
|
|
||||||
const RssFeedManager = require('../managers/RssFeedManager')
|
const RssFeedManager = require('../managers/RssFeedManager')
|
||||||
|
|
||||||
@@ -31,8 +32,10 @@ class CollectionController {
|
|||||||
async create(req, res) {
|
async create(req, res) {
|
||||||
const reqBody = req.body || {}
|
const reqBody = req.body || {}
|
||||||
|
|
||||||
|
const nameCleaned = htmlSanitizer.stripAllTags(reqBody.name)
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (!reqBody.name || !reqBody.libraryId) {
|
if (!nameCleaned || !reqBody.libraryId) {
|
||||||
return res.status(400).send('Invalid collection data')
|
return res.status(400).send('Invalid collection data')
|
||||||
}
|
}
|
||||||
if (reqBody.description && typeof reqBody.description !== 'string') {
|
if (reqBody.description && typeof reqBody.description !== 'string') {
|
||||||
@@ -65,7 +68,7 @@ class CollectionController {
|
|||||||
newCollection = await Database.collectionModel.create(
|
newCollection = await Database.collectionModel.create(
|
||||||
{
|
{
|
||||||
libraryId: reqBody.libraryId,
|
libraryId: reqBody.libraryId,
|
||||||
name: reqBody.name,
|
name: nameCleaned,
|
||||||
description: reqBody.description || null
|
description: reqBody.description || null
|
||||||
},
|
},
|
||||||
{ transaction }
|
{ transaction }
|
||||||
@@ -145,9 +148,12 @@ class CollectionController {
|
|||||||
collectionUpdatePayload.description = req.body.description
|
collectionUpdatePayload.description = req.body.description
|
||||||
wasUpdated = true
|
wasUpdated = true
|
||||||
}
|
}
|
||||||
if (req.body.name !== undefined && req.body.name !== req.collection.name) {
|
if (req.body.name !== undefined && typeof req.body.name === 'string') {
|
||||||
collectionUpdatePayload.name = req.body.name
|
const nameCleaned = htmlSanitizer.stripAllTags(req.body.name)
|
||||||
wasUpdated = true
|
if (nameCleaned !== req.collection.name) {
|
||||||
|
collectionUpdatePayload.name = nameCleaned
|
||||||
|
wasUpdated = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wasUpdated) {
|
if (wasUpdated) {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ class FileSystemController {
|
|||||||
filepath = fileUtils.filePathToPOSIX(filepath)
|
filepath = fileUtils.filePathToPOSIX(filepath)
|
||||||
|
|
||||||
// Ensure filepath is inside library folder (prevents directory traversal)
|
// Ensure filepath is inside library folder (prevents directory traversal)
|
||||||
if (!filepath.startsWith(libraryFolder.path)) {
|
if (!fileUtils.isSameOrSubPath(libraryFolder.path, filepath)) {
|
||||||
Logger.error(`[FileSystemController] Filepath is not inside library folder: ${filepath}`)
|
Logger.error(`[FileSystemController] Filepath is not inside library folder: ${filepath}`)
|
||||||
return res.sendStatus(400)
|
return res.sendStatus(400)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from folder "${folder.path}"`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from folder "${folder.path}"`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds, req.library.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authorIds.length) {
|
if (authorIds.length) {
|
||||||
@@ -563,7 +563,7 @@ class LibraryController {
|
|||||||
mediaItemIds.push(libraryItem.mediaId)
|
mediaItemIds.push(libraryItem.mediaId)
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from library "${req.library.name}"`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" from library "${req.library.name}"`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds, req.library.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set PlaybackSessions libraryId to null
|
// Set PlaybackSessions libraryId to null
|
||||||
@@ -714,7 +714,7 @@ class LibraryController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" with issue`)
|
Logger.info(`[LibraryController] Removing library item "${libraryItem.id}" with issue`)
|
||||||
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds, req.library.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authorIds.length) {
|
if (authorIds.length) {
|
||||||
@@ -1435,10 +1435,15 @@ class LibraryController {
|
|||||||
const libraryItems = await Database.libraryItemModel.findAll({
|
const libraryItems = await Database.libraryItemModel.findAll({
|
||||||
attributes: ['id', 'libraryId', 'path', 'isFile'],
|
attributes: ['id', 'libraryId', 'path', 'isFile'],
|
||||||
where: {
|
where: {
|
||||||
id: itemIds
|
id: itemIds,
|
||||||
|
libraryId: req.library.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (libraryItems.length < itemIds.length) {
|
||||||
|
Logger.warn(`[LibraryController] User "${req.user.username}" requested ${itemIds.length} items but only ${libraryItems.length} are in library "${req.library.id}"`)
|
||||||
|
}
|
||||||
|
|
||||||
Logger.info(`[LibraryController] User "${req.user.username}" requested download for items "${itemIds}"`)
|
Logger.info(`[LibraryController] User "${req.user.username}" requested download for items "${itemIds}"`)
|
||||||
|
|
||||||
const filename = `LibraryItems-${Date.now()}.zip`
|
const filename = `LibraryItems-${Date.now()}.zip`
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const SocketAuthority = require('../SocketAuthority')
|
|||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
|
||||||
const zipHelpers = require('../utils/zipHelpers')
|
const zipHelpers = require('../utils/zipHelpers')
|
||||||
const { reqSupportsWebp } = require('../utils/index')
|
const { reqSupportsWebp, clampPositiveInt } = require('../utils/index')
|
||||||
const { ScanResult, AudioMimeType } = require('../utils/constants')
|
const { ScanResult, AudioMimeType } = require('../utils/constants')
|
||||||
const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUtils')
|
const { getAudioMimeTypeFromExtname, encodeUriPath } = require('../utils/fileUtils')
|
||||||
const LibraryItemScanner = require('../scanner/LibraryItemScanner')
|
const LibraryItemScanner = require('../scanner/LibraryItemScanner')
|
||||||
@@ -111,7 +111,7 @@ class LibraryItemController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.handleDeleteLibraryItem(req.libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(req.libraryItem.id, mediaItemIds, req.libraryItem.libraryId)
|
||||||
if (hardDelete) {
|
if (hardDelete) {
|
||||||
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
await fs.remove(libraryItemPath).catch((error) => {
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
@@ -398,8 +398,8 @@ class LibraryItemController {
|
|||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
format: format || (reqSupportsWebp(req) ? 'webp' : 'jpeg'),
|
format: format || (reqSupportsWebp(req) ? 'webp' : 'jpeg'),
|
||||||
height: height ? parseInt(height) : null,
|
height: clampPositiveInt(height ? parseInt(height) : null, 4096),
|
||||||
width: width ? parseInt(width) : null
|
width: clampPositiveInt(width ? parseInt(width) : null, 4096)
|
||||||
}
|
}
|
||||||
return CacheManager.handleCoverCache(res, libraryItemId, options)
|
return CacheManager.handleCoverCache(res, libraryItemId, options)
|
||||||
}
|
}
|
||||||
@@ -565,7 +565,7 @@ class LibraryItemController {
|
|||||||
authorIds.push(...libraryItem.media.authors.map((au) => au.id))
|
authorIds.push(...libraryItem.media.authors.map((au) => au.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds)
|
await this.handleDeleteLibraryItem(libraryItem.id, mediaItemIds, libraryItem.libraryId)
|
||||||
if (hardDelete) {
|
if (hardDelete) {
|
||||||
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
Logger.info(`[LibraryItemController] Deleting library item from file system at "${libraryItemPath}"`)
|
||||||
await fs.remove(libraryItemPath).catch((error) => {
|
await fs.remove(libraryItemPath).catch((error) => {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const { Request, Response, NextFunction } = require('express')
|
|||||||
const Logger = require('../Logger')
|
const Logger = require('../Logger')
|
||||||
const SocketAuthority = require('../SocketAuthority')
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
const Database = require('../Database')
|
const Database = require('../Database')
|
||||||
|
const htmlSanitizer = require('../utils/htmlSanitizer')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef RequestUserObject
|
* @typedef RequestUserObject
|
||||||
@@ -29,7 +30,8 @@ class PlaylistController {
|
|||||||
const reqBody = req.body || {}
|
const reqBody = req.body || {}
|
||||||
|
|
||||||
// Validation
|
// Validation
|
||||||
if (!reqBody.name || !reqBody.libraryId) {
|
const nameCleaned = htmlSanitizer.stripAllTags(reqBody.name)
|
||||||
|
if (!nameCleaned || !reqBody.libraryId) {
|
||||||
return res.status(400).send('Invalid playlist data')
|
return res.status(400).send('Invalid playlist data')
|
||||||
}
|
}
|
||||||
if (reqBody.description && typeof reqBody.description !== 'string') {
|
if (reqBody.description && typeof reqBody.description !== 'string') {
|
||||||
@@ -84,7 +86,7 @@ class PlaylistController {
|
|||||||
{
|
{
|
||||||
libraryId: reqBody.libraryId,
|
libraryId: reqBody.libraryId,
|
||||||
userId: req.user.id,
|
userId: req.user.id,
|
||||||
name: reqBody.name,
|
name: nameCleaned,
|
||||||
description: reqBody.description || null
|
description: reqBody.description || null
|
||||||
},
|
},
|
||||||
{ transaction }
|
{ transaction }
|
||||||
@@ -174,7 +176,11 @@ class PlaylistController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const playlistUpdatePayload = {}
|
const playlistUpdatePayload = {}
|
||||||
if (reqBody.name) playlistUpdatePayload.name = reqBody.name
|
|
||||||
|
const nameCleaned = htmlSanitizer.stripAllTags(reqBody.name)
|
||||||
|
if (nameCleaned) {
|
||||||
|
playlistUpdatePayload.name = nameCleaned
|
||||||
|
}
|
||||||
if (reqBody.description) playlistUpdatePayload.description = reqBody.description
|
if (reqBody.description) playlistUpdatePayload.description = reqBody.description
|
||||||
|
|
||||||
// Update name and description
|
// Update name and description
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const Database = require('../Database')
|
|||||||
const fs = require('../libs/fsExtra')
|
const fs = require('../libs/fsExtra')
|
||||||
|
|
||||||
const { getPodcastFeed, findMatchingEpisodes } = require('../utils/podcastUtils')
|
const { getPodcastFeed, findMatchingEpisodes } = require('../utils/podcastUtils')
|
||||||
const { getFileTimestampsWithIno, filePathToPOSIX } = require('../utils/fileUtils')
|
const { getFileTimestampsWithIno, filePathToPOSIX, isSameOrSubPath } = require('../utils/fileUtils')
|
||||||
const { validateUrl } = require('../utils/index')
|
const { validateUrl } = require('../utils/index')
|
||||||
const htmlSanitizer = require('../utils/htmlSanitizer')
|
const htmlSanitizer = require('../utils/htmlSanitizer')
|
||||||
|
|
||||||
@@ -58,8 +58,18 @@ class PodcastController {
|
|||||||
return res.status(404).send('Folder not found')
|
return res.status(404).send('Folder not found')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof payload.path !== 'string' || !payload.path.trim()) {
|
||||||
|
return res.status(400).send('Invalid request body. "path" must be a non-empty string')
|
||||||
|
}
|
||||||
|
|
||||||
|
const libraryFolderPath = filePathToPOSIX(folder.path)
|
||||||
const podcastPath = filePathToPOSIX(payload.path)
|
const podcastPath = filePathToPOSIX(payload.path)
|
||||||
|
|
||||||
|
if (!isSameOrSubPath(libraryFolderPath, podcastPath)) {
|
||||||
|
Logger.error(`[PodcastController] Create: Podcast path is outside library folder "${libraryFolderPath}": "${podcastPath}"`)
|
||||||
|
return res.status(400).send('Podcast path must be inside the selected library folder')
|
||||||
|
}
|
||||||
|
|
||||||
// Check if a library item with this podcast folder exists already
|
// Check if a library item with this podcast folder exists already
|
||||||
const existingLibraryItem =
|
const existingLibraryItem =
|
||||||
(await Database.libraryItemModel.count({
|
(await Database.libraryItemModel.count({
|
||||||
@@ -83,7 +93,7 @@ class PodcastController {
|
|||||||
|
|
||||||
const libraryItemFolderStats = await getFileTimestampsWithIno(podcastPath)
|
const libraryItemFolderStats = await getFileTimestampsWithIno(podcastPath)
|
||||||
|
|
||||||
let relPath = payload.path.replace(folder.fullPath, '')
|
let relPath = podcastPath.replace(libraryFolderPath, '')
|
||||||
if (relPath.startsWith('/')) relPath = relPath.slice(1)
|
if (relPath.startsWith('/')) relPath = relPath.slice(1)
|
||||||
|
|
||||||
let newLibraryItem = null
|
let newLibraryItem = null
|
||||||
@@ -412,6 +422,12 @@ class PodcastController {
|
|||||||
Logger.debug(`[PodcastController] Sanitized description from "${req.body[key]}" to "${sanitizedDescription}"`)
|
Logger.debug(`[PodcastController] Sanitized description from "${req.body[key]}" to "${sanitizedDescription}"`)
|
||||||
req.body[key] = sanitizedDescription
|
req.body[key] = sanitizedDescription
|
||||||
}
|
}
|
||||||
|
} else if (key === 'subtitle' && req.body[key]) {
|
||||||
|
const sanitizedSubtitle = htmlSanitizer.sanitize(req.body[key])
|
||||||
|
if (sanitizedSubtitle !== req.body[key]) {
|
||||||
|
Logger.debug(`[PodcastController] Sanitized subtitle from "${req.body[key]}" to "${sanitizedSubtitle}"`)
|
||||||
|
req.body[key] = sanitizedSubtitle
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePayload[key] = req.body[key]
|
updatePayload[key] = req.body[key]
|
||||||
|
|||||||
@@ -126,13 +126,31 @@ class BackupManager {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Not a valid zip file
|
// Not a valid zip file
|
||||||
Logger.error('[BackupManager] Failed to read backup file - backup might not be a valid .zip file', tempPath, error)
|
Logger.error('[BackupManager] Failed to read backup file - backup might not be a valid .zip file', tempPath, error)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
await fs.remove(tempPath).catch((err) => Logger.error(`[BackupManager] Failed to remove rejected backup file "${tempPath}"`, err))
|
||||||
return res.status(400).send('Failed to read backup file - backup might not be a valid .zip file')
|
return res.status(400).send('Failed to read backup file - backup might not be a valid .zip file')
|
||||||
}
|
}
|
||||||
if (!Object.keys(entries).includes('absdatabase.sqlite')) {
|
if (!entries['absdatabase.sqlite']) {
|
||||||
Logger.error(`[BackupManager] Invalid backup with no absdatabase.sqlite file - might be a backup created on an old Audiobookshelf server.`)
|
Logger.error(`[BackupManager] Invalid backup with no absdatabase.sqlite file - might be a backup created on an old Audiobookshelf server.`)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
await fs.remove(tempPath).catch((err) => Logger.error(`[BackupManager] Failed to remove rejected backup file "${tempPath}"`, err))
|
||||||
return res.status(500).send('Invalid backup with no absdatabase.sqlite file - might be a backup created on an old Audiobookshelf server.')
|
return res.status(500).send('Invalid backup with no absdatabase.sqlite file - might be a backup created on an old Audiobookshelf server.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const detailsEntry = entries['details']
|
||||||
|
if (!detailsEntry) {
|
||||||
|
Logger.error('[BackupManager] Invalid backup - missing details entry')
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
await fs.remove(tempPath).catch((err) => Logger.error(`[BackupManager] Failed to remove rejected backup file "${tempPath}"`, err))
|
||||||
|
return res.status(400).send('Invalid backup file - missing details entry')
|
||||||
|
}
|
||||||
|
if (detailsEntry.size > 1024 * 1024) {
|
||||||
|
Logger.error(`[BackupManager] Backup details entry too large: ${detailsEntry.size} bytes`)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
await fs.remove(tempPath).catch((err) => Logger.error(`[BackupManager] Failed to remove rejected backup file "${tempPath}"`, err))
|
||||||
|
return res.status(400).send('Invalid backup file - details entry too large')
|
||||||
|
}
|
||||||
|
|
||||||
const data = await zip.entryData('details')
|
const data = await zip.entryData('details')
|
||||||
const details = data.toString('utf8').split('\n')
|
const details = data.toString('utf8').split('\n')
|
||||||
|
|
||||||
@@ -140,9 +158,13 @@ class BackupManager {
|
|||||||
|
|
||||||
if (!backup.serverVersion) {
|
if (!backup.serverVersion) {
|
||||||
Logger.error(`[BackupManager] Invalid backup with no server version - might be a backup created before version 2.0.0`)
|
Logger.error(`[BackupManager] Invalid backup with no server version - might be a backup created before version 2.0.0`)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
await fs.remove(tempPath).catch((err) => Logger.error(`[BackupManager] Failed to remove rejected backup file "${tempPath}"`, err))
|
||||||
return res.status(500).send('Invalid backup. Might be a backup created before version 2.0.0.')
|
return res.status(500).send('Invalid backup. Might be a backup created before version 2.0.0.')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
|
||||||
backup.fileSize = await getFileSize(backup.fullPath)
|
backup.fileSize = await getFileSize(backup.fullPath)
|
||||||
|
|
||||||
const existingBackupIndex = this.backups.findIndex((b) => b.id === backup.id)
|
const existingBackupIndex = this.backups.findIndex((b) => b.id === backup.id)
|
||||||
@@ -257,9 +279,24 @@ class BackupManager {
|
|||||||
let data = null
|
let data = null
|
||||||
try {
|
try {
|
||||||
zip = new StreamZip.async({ file: fullFilePath })
|
zip = new StreamZip.async({ file: fullFilePath })
|
||||||
|
const entries = await zip.entries()
|
||||||
|
|
||||||
|
const detailsEntry = entries['details']
|
||||||
|
if (!detailsEntry) {
|
||||||
|
Logger.error(`[BackupManager] Backup "${fullFilePath}" missing details entry - skipping`)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (detailsEntry.size > 1024 * 1024) {
|
||||||
|
Logger.error(`[BackupManager] Backup "${fullFilePath}" details entry too large (${detailsEntry.size} bytes) - skipping`)
|
||||||
|
await zip.close().catch(() => {})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
data = await zip.entryData('details')
|
data = await zip.entryData('details')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error(`[BackupManager] Failed to unzip backup "${fullFilePath}"`, error)
|
Logger.error(`[BackupManager] Failed to unzip backup "${fullFilePath}"`, error)
|
||||||
|
if (zip) await zip.close().catch(() => {})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,16 +111,17 @@ class Author extends Model {
|
|||||||
*
|
*
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {string} libraryId
|
* @param {string} libraryId
|
||||||
* @returns {Promise<Author>}
|
* @returns {Promise<{ author: Author, created: boolean }>}
|
||||||
*/
|
*/
|
||||||
static async findOrCreateByNameAndLibrary(name, libraryId) {
|
static async findOrCreateByNameAndLibrary(name, libraryId) {
|
||||||
const author = await this.getByNameAndLibrary(name, libraryId)
|
const author = await this.getByNameAndLibrary(name, libraryId)
|
||||||
if (author) return author
|
if (author) return { author, created: false }
|
||||||
return this.create({
|
const newAuthor = await this.create({
|
||||||
name,
|
name,
|
||||||
lastFirst: this.getLastFirst(name),
|
lastFirst: this.getLastFirst(name),
|
||||||
libraryId
|
libraryId
|
||||||
})
|
})
|
||||||
|
return { author: newAuthor, created: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+12
-1
@@ -4,6 +4,7 @@ const { getTitlePrefixAtEnd, getTitleIgnorePrefix } = require('../utils')
|
|||||||
const parseNameString = require('../utils/parsers/parseNameString')
|
const parseNameString = require('../utils/parsers/parseNameString')
|
||||||
const htmlSanitizer = require('../utils/htmlSanitizer')
|
const htmlSanitizer = require('../utils/htmlSanitizer')
|
||||||
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
const libraryItemsBookFilters = require('../utils/queries/libraryItemsBookFilters')
|
||||||
|
const SocketAuthority = require('../SocketAuthority')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef EBookFileObject
|
* @typedef EBookFileObject
|
||||||
@@ -470,13 +471,23 @@ class Book extends Model {
|
|||||||
|
|
||||||
for (const author of authorsRemoved) {
|
for (const author of authorsRemoved) {
|
||||||
await bookAuthorModel.removeByIds(author.id, this.id)
|
await bookAuthorModel.removeByIds(author.id, this.id)
|
||||||
|
const numBooks = await bookAuthorModel.getCountForAuthor(author.id)
|
||||||
|
if (numBooks > 0) {
|
||||||
|
SocketAuthority.emitter('author_updated', author.toOldJSONExpanded(numBooks))
|
||||||
|
}
|
||||||
Logger.debug(`[Book] "${this.title}" Removed author "${author.name}"`)
|
Logger.debug(`[Book] "${this.title}" Removed author "${author.name}"`)
|
||||||
this.authors = this.authors.filter((au) => au.id !== author.id)
|
this.authors = this.authors.filter((au) => au.id !== author.id)
|
||||||
}
|
}
|
||||||
const authorsAdded = []
|
const authorsAdded = []
|
||||||
for (const authorName of newAuthorNames) {
|
for (const authorName of newAuthorNames) {
|
||||||
const author = await authorModel.findOrCreateByNameAndLibrary(authorName, libraryId)
|
const { author, created } = await authorModel.findOrCreateByNameAndLibrary(authorName, libraryId)
|
||||||
await bookAuthorModel.create({ bookId: this.id, authorId: author.id })
|
await bookAuthorModel.create({ bookId: this.id, authorId: author.id })
|
||||||
|
if (created) {
|
||||||
|
SocketAuthority.emitter('author_added', author.toOldJSON())
|
||||||
|
} else {
|
||||||
|
const numBooks = await bookAuthorModel.getCountForAuthor(author.id)
|
||||||
|
SocketAuthority.emitter('author_updated', author.toOldJSONExpanded(numBooks))
|
||||||
|
}
|
||||||
Logger.debug(`[Book] "${this.title}" Added author "${author.name}"`)
|
Logger.debug(`[Book] "${this.title}" Added author "${author.name}"`)
|
||||||
this.authors.push(author)
|
this.authors.push(author)
|
||||||
authorsAdded.push(author)
|
authorsAdded.push(author)
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ class PlaybackSession {
|
|||||||
startedAt: this.startedAt,
|
startedAt: this.startedAt,
|
||||||
updatedAt: this.updatedAt,
|
updatedAt: this.updatedAt,
|
||||||
audioTracks: this.audioTracks.map((at) => at.toJSON?.() || { ...at }),
|
audioTracks: this.audioTracks.map((at) => at.toJSON?.() || { ...at }),
|
||||||
libraryItem: libraryItem?.toOldJSONExpanded() || null
|
libraryItem: libraryItem?.toOldJSONExpanded() || null,
|
||||||
|
coverAspectRatio: this.coverAspectRatio !== null ? this.coverAspectRatio : undefined // Used for share sessions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class Stream extends EventEmitter {
|
|||||||
return [AudioMimeType.FLAC, AudioMimeType.OPUS, AudioMimeType.WMA, AudioMimeType.AIFF, AudioMimeType.WEBM, AudioMimeType.WEBMA, AudioMimeType.AWB, AudioMimeType.CAF]
|
return [AudioMimeType.FLAC, AudioMimeType.OPUS, AudioMimeType.WMA, AudioMimeType.AIFF, AudioMimeType.WEBM, AudioMimeType.WEBMA, AudioMimeType.AWB, AudioMimeType.CAF]
|
||||||
}
|
}
|
||||||
get codecsToForceAAC() {
|
get codecsToForceAAC() {
|
||||||
return ['alac', 'ac3', 'eac3']
|
return ['alac', 'ac3', 'eac3', 'opus']
|
||||||
}
|
}
|
||||||
get userToken() {
|
get userToken() {
|
||||||
return this.user.token
|
return this.user.token
|
||||||
|
|||||||
@@ -363,8 +363,9 @@ class ApiRouter {
|
|||||||
* Remove library item and associated entities
|
* Remove library item and associated entities
|
||||||
* @param {string} libraryItemId
|
* @param {string} libraryItemId
|
||||||
* @param {string[]} mediaItemIds array of bookId or podcastEpisodeId
|
* @param {string[]} mediaItemIds array of bookId or podcastEpisodeId
|
||||||
|
* @param {string} libraryId
|
||||||
*/
|
*/
|
||||||
async handleDeleteLibraryItem(libraryItemId, mediaItemIds) {
|
async handleDeleteLibraryItem(libraryItemId, mediaItemIds, libraryId) {
|
||||||
const numProgressRemoved = await Database.mediaProgressModel.destroy({
|
const numProgressRemoved = await Database.mediaProgressModel.destroy({
|
||||||
where: {
|
where: {
|
||||||
mediaItemId: mediaItemIds
|
mediaItemId: mediaItemIds
|
||||||
@@ -395,7 +396,8 @@ class ApiRouter {
|
|||||||
await Database.libraryItemModel.removeById(libraryItemId)
|
await Database.libraryItemModel.removeById(libraryItemId)
|
||||||
|
|
||||||
SocketAuthority.emitter('item_removed', {
|
SocketAuthority.emitter('item_removed', {
|
||||||
id: libraryItemId
|
id: libraryItemId,
|
||||||
|
libraryId
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ module.exports.AudioMimeType = {
|
|||||||
AIF: 'audio/x-aiff',
|
AIF: 'audio/x-aiff',
|
||||||
WEBM: 'audio/webm',
|
WEBM: 'audio/webm',
|
||||||
WEBMA: 'audio/webm',
|
WEBMA: 'audio/webm',
|
||||||
|
// TODO: Switch to `audio/matroska`? marked as deprecated in IANA registry
|
||||||
|
// ref: https://datatracker.ietf.org/doc/html/rfc9559
|
||||||
MKA: 'audio/x-matroska',
|
MKA: 'audio/x-matroska',
|
||||||
AWB: 'audio/amr-wb',
|
AWB: 'audio/amr-wb',
|
||||||
CAF: 'audio/x-caf',
|
CAF: 'audio/x-caf',
|
||||||
|
|||||||
@@ -54,6 +54,16 @@ module.exports.isNullOrNaN = (num) => {
|
|||||||
return num === null || isNaN(num)
|
return num === null || isNaN(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number|null|undefined} value
|
||||||
|
* @param {number} max
|
||||||
|
* @returns {number|null}
|
||||||
|
*/
|
||||||
|
module.exports.clampPositiveInt = (value, max) => {
|
||||||
|
if (value == null || !Number.isFinite(value) || value <= 0) return null
|
||||||
|
return Math.min(Math.floor(value), max)
|
||||||
|
}
|
||||||
|
|
||||||
const xmlToJSON = (xml) => {
|
const xmlToJSON = (xml) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
parseString(xml, (err, results) => {
|
parseString(xml, (err, results) => {
|
||||||
|
|||||||
@@ -217,6 +217,10 @@ function extractEpisodeData(item) {
|
|||||||
episode[cleanKey] = extractFirstArrayItemString(item, key)
|
episode[cleanKey] = extractFirstArrayItemString(item, key)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (episode.subtitle) {
|
||||||
|
episode.subtitle = htmlSanitizer.sanitize(episode.subtitle.trim())
|
||||||
|
}
|
||||||
|
|
||||||
// Extract psc:chapters if duration is set
|
// Extract psc:chapters if duration is set
|
||||||
episode.durationSeconds = episode.duration ? timestampToSeconds(episode.duration) : null
|
episode.durationSeconds = episode.duration ? timestampToSeconds(episode.duration) : null
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user