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

This commit is contained in:
Toni Barth 2024-12-08 20:40:11 +01:00
commit 956f475a6e
45 changed files with 1995 additions and 370 deletions

View file

@ -10,9 +10,9 @@
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedIsOpen }}</p>
<div class="w-full relative">
<ui-text-input v-model="currentFeed.feedUrl" readonly />
<ui-text-input :value="feedUrl" readonly />
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(currentFeed.feedUrl)">content_copy</span>
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
</div>
<div v-if="currentFeed.meta" class="mt-5">
@ -111,8 +111,11 @@ export default {
userIsAdminOrUp() {
return this.$store.getters['user/getIsAdminOrUp']
},
feedUrl() {
return this.currentFeed ? `${window.origin}${this.$config.routerBasePath}${this.currentFeed.feedUrl}` : ''
},
demoFeedUrl() {
return `${window.origin}/feed/${this.newFeedSlug}`
return `${window.origin}${this.$config.routerBasePath}/feed/${this.newFeedSlug}`
},
isHttp() {
return window.origin.startsWith('http://')

View file

@ -5,8 +5,8 @@
<p class="text-lg font-semibold mb-4">{{ $strings.HeaderRSSFeedGeneral }}</p>
<div class="w-full relative">
<ui-text-input v-model="feed.feedUrl" readonly />
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feed.feedUrl)">content_copy</span>
<ui-text-input :value="feedUrl" readonly />
<span class="material-symbols absolute right-2 bottom-2 p-0.5 text-base transition-transform duration-100 text-gray-300 hover:text-white transform hover:scale-125 cursor-pointer" @click="copyToClipboard(feedUrl)">content_copy</span>
</div>
<div v-if="feed.meta" class="mt-5">
@ -70,6 +70,9 @@ export default {
},
_feed() {
return this.feed || {}
},
feedUrl() {
return this.feed ? `${window.origin}${this.$config.routerBasePath}${this.feed.feedUrl}` : ''
}
},
methods: {

View file

@ -120,6 +120,7 @@ export default {
this.users = res.users.sort((a, b) => {
return a.createdAt - b.createdAt
})
this.$emit('numUsers', this.users.length)
})
.catch((error) => {
console.error('Failed', error)

View file

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

View file

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

View file

@ -64,6 +64,20 @@
<ui-multi-select ref="redirectUris" v-model="newAuthSettings.authOpenIDMobileRedirectURIs" :items="newAuthSettings.authOpenIDMobileRedirectURIs" :label="$strings.LabelMobileRedirectURIs" class="mb-2" :menuDisabled="true" :disabled="savingSettings" />
<p class="sm:pl-4 text-sm text-gray-300 mb-2" v-html="$strings.LabelMobileRedirectURIsDescription" />
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
<div class="w-44">
<ui-dropdown v-model="newAuthSettings.authOpenIDSubfolderForRedirectURLs" small :items="subfolderOptions" :label="$strings.LabelWebRedirectURLsSubfolder" :disabled="savingSettings" />
</div>
<div class="mt-2 sm:mt-5">
<p class="sm:pl-4 text-sm text-gray-300">{{ $strings.LabelWebRedirectURLsDescription }}</p>
<p class="sm:pl-4 text-sm text-gray-300 mb-2">
<code>{{ webCallbackURL }}</code>
<br />
<code>{{ mobileAppCallbackURL }}</code>
</p>
</div>
</div>
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" />
<div class="flex sm:items-center flex-col sm:flex-row pt-1 mb-2">
@ -164,6 +178,27 @@ export default {
value: 'username'
}
]
},
subfolderOptions() {
const options = [
{
text: 'None',
value: ''
}
]
if (this.$config.routerBasePath) {
options.push({
text: this.$config.routerBasePath,
value: this.$config.routerBasePath
})
}
return options
},
webCallbackURL() {
return `https://<your.server.com>${this.newAuthSettings.authOpenIDSubfolderForRedirectURLs ? this.newAuthSettings.authOpenIDSubfolderForRedirectURLs : ''}/auth/openid/callback`
},
mobileAppCallbackURL() {
return `https://<your.server.com>${this.newAuthSettings.authOpenIDSubfolderForRedirectURLs ? this.newAuthSettings.authOpenIDSubfolderForRedirectURLs : ''}/auth/openid/mobile-redirect`
}
},
methods: {
@ -325,7 +360,8 @@ export default {
},
init() {
this.newAuthSettings = {
...this.authSettings
...this.authSettings,
authOpenIDSubfolderForRedirectURLs: this.authSettings.authOpenIDSubfolderForRedirectURLs === undefined ? this.$config.routerBasePath : this.authSettings.authOpenIDSubfolderForRedirectURLs
}
this.enableLocalAuth = this.authMethods.includes('local')
this.enableOpenIDAuth = this.authMethods.includes('openid')

View file

@ -42,11 +42,6 @@
</div>
</div>
<div class="flex items-center py-2 mb-2">
<ui-toggle-switch labeledBy="settings-chromecast-support" v-model="newServerSettings.chromecastEnabled" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
</div>
<div class="pt-4">
<h2 class="font-semibold">{{ $strings.HeaderSettingsScanner }}</h2>
</div>
@ -94,6 +89,20 @@
</p>
</ui-tooltip>
</div>
<div class="pt-4">
<h2 class="font-semibold">{{ $strings.HeaderSettingsWebClient }}</h2>
</div>
<div class="flex items-center py-2">
<ui-toggle-switch labeledBy="settings-chromecast-support" v-model="newServerSettings.chromecastEnabled" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('chromecastEnabled', val)" />
<p class="pl-4" id="settings-chromecast-support">{{ $strings.LabelSettingsChromecastSupport }}</p>
</div>
<div class="flex items-center py-2 mb-2">
<ui-toggle-switch labeledBy="settings-allow-iframe" v-model="newServerSettings.allowIframe" :disabled="updatingServerSettings" @input="(val) => updateSettingsKey('allowIframe', val)" />
<p class="pl-4" id="settings-allow-iframe">{{ $strings.LabelSettingsAllowIframe }}</p>
</div>
</div>
<div class="flex-1">
@ -324,21 +333,21 @@ export default {
},
updateServerSettings(payload) {
this.updatingServerSettings = true
this.$store
.dispatch('updateServerSettings', payload)
.then(() => {
this.updatingServerSettings = false
this.$store.dispatch('updateServerSettings', payload).then((response) => {
this.updatingServerSettings = false
if (payload.language) {
// Updating language after save allows for re-rendering
this.$setLanguageCode(payload.language)
}
})
.catch((error) => {
console.error('Failed to update server settings', error)
this.updatingServerSettings = false
this.$toast.error(this.$strings.ToastFailedToUpdate)
})
if (response.error) {
console.error('Failed to update server settins', response.error)
this.$toast.error(response.error)
this.initServerSettings()
return
}
if (payload.language) {
// Updating language after save allows for re-rendering
this.$setLanguageCode(payload.language)
}
})
},
initServerSettings() {
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}

View file

@ -126,7 +126,7 @@ export default {
},
coverUrl(feed) {
if (!feed.coverPath) return `${this.$config.routerBasePath}/Logo.png`
return `${feed.feedUrl}/cover`
return `${this.$config.routerBasePath}${feed.feedUrl}/cover`
},
async loadFeeds() {
const data = await this.$axios.$get(`/api/feeds`).catch((err) => {

View file

@ -2,6 +2,10 @@
<div>
<app-settings-content :header-text="$strings.HeaderUsers">
<template #header-items>
<div v-if="numUsers" class="mx-2 px-1.5 rounded-lg bg-primary/50 text-gray-300/90 text-sm inline-flex items-center justify-center">
<span>{{ numUsers }}</span>
</div>
<ui-tooltip :text="$strings.LabelClickForMoreInfo" class="inline-flex ml-2">
<a href="https://www.audiobookshelf.org/guides/users" target="_blank" class="inline-flex">
<span class="material-symbols text-xl w-5 text-gray-200">help_outline</span>
@ -13,7 +17,7 @@
<ui-btn color="primary" small @click="setShowUserModal()">{{ $strings.ButtonAddUser }}</ui-btn>
</template>
<tables-users-table class="pt-2" @edit="setShowUserModal" />
<tables-users-table class="pt-2" @edit="setShowUserModal" @numUsers="(count) => (numUsers = count)" />
</app-settings-content>
<modals-account-modal ref="accountModal" v-model="showAccountModal" :account="selectedAccount" />
</div>
@ -29,7 +33,8 @@ export default {
data() {
return {
selectedAccount: null,
showAccountModal: false
showAccountModal: false,
numUsers: 0
}
},
computed: {},

View file

@ -7,6 +7,7 @@ const defaultCode = 'en-us'
const languageCodeMap = {
bg: { label: 'Български', dateFnsLocale: 'bg' },
bn: { label: 'বাংলা', dateFnsLocale: 'bn' },
ca: { label: 'Català', dateFnsLocale: 'ca' },
cs: { label: 'Čeština', dateFnsLocale: 'cs' },
da: { label: 'Dansk', dateFnsLocale: 'da' },
de: { label: 'Deutsch', dateFnsLocale: 'de' },

View file

@ -72,16 +72,17 @@ export const actions = {
return this.$axios
.$patch('/api/settings', updatePayload)
.then((result) => {
if (result.success) {
if (result.serverSettings) {
commit('setServerSettings', result.serverSettings)
return true
} else {
return false
}
return result
})
.catch((error) => {
console.error('Failed to update server settings', error)
return false
const errorMsg = error.response?.data || 'Unknown error'
return {
error: errorMsg
}
})
},
checkForUpdate({ commit }) {

1027
client/strings/ca.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -584,7 +584,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",
"LabelSettingsTimeFormat": "Zeitformat",
"LabelShare": "Freigeben",
"LabelShareOpen": "Freigabe",
"LabelShareOpen": "Freigeben",
"LabelShareURL": "Freigabe URL",
"LabelShowAll": "Alles anzeigen",
"LabelShowSeconds": "Zeige Sekunden",
@ -679,6 +679,8 @@
"LabelViewPlayerSettings": "Zeige player Einstellungen",
"LabelViewQueue": "Player-Warteschlange anzeigen",
"LabelVolume": "Lautstärke",
"LabelWebRedirectURLsDescription": "Autorisieren Sie diese URLs bei ihrem OAuth-Anbieter, um die Weiterleitung zurück zur Webanwendung nach dem Login zu ermöglichen:",
"LabelWebRedirectURLsSubfolder": "Unterordner für Weiterleitung-URLs",
"LabelWeekdaysToRun": "Wochentage für die Ausführung",
"LabelXBooks": "{0} Bücher",
"LabelXItems": "{0} Medien",
@ -728,7 +730,7 @@
"MessageConfirmPurgeCache": "Cache leeren wird das ganze Verzeichnis <code>/metadata/cache</code> löschen. <br /><br />Bist du dir sicher, dass das Cache Verzeichnis gelöscht werden soll?",
"MessageConfirmPurgeItemsCache": "Durch Elementcache leeren wird das gesamte Verzeichnis unter <code>/metadata/cache/items</code> gelöscht.<br />Bist du dir sicher?",
"MessageConfirmQuickEmbed": "Warnung! Audiodateien werden bei der Schnelleinbettung nicht gesichert! Achte darauf, dass du eine Sicherungskopie der Audiodateien besitzt. <br><br>Möchtest du fortfahren?",
"MessageConfirmQuickMatchEpisodes": "Schnelles Zuordnen von Episoden überschreibt die Details, wenn eine Übereinstimmung gefunden wird. Nur nicht zugeordnete Episoden werden aktualisiert. Bist du sicher?",
"MessageConfirmQuickMatchEpisodes": "Schnellabgleich von Episoden überschreibt deren Details, wenn ein passender Eintrag gefunden wurde, wird aber nur auf bisher unbearbeitete Episoden angewendet. Wirklich fortfahren?",
"MessageConfirmReScanLibraryItems": "{0} Elemente werden erneut gescannt! Bist du dir sicher?",
"MessageConfirmRemoveAllChapters": "Alle Kapitel werden entfernt! Bist du dir sicher?",
"MessageConfirmRemoveAuthor": "Autor \"{0}\" wird enfernt! Bist du dir sicher?",
@ -833,7 +835,7 @@
"MessageSetChaptersFromTracksDescription": "Kaitelerstellung basiert auf den existierenden einzelnen Audiodateien. Pro existierende Audiodatei wird 1 Kapitel erstellt, wobei deren Kapitelname aus dem Audiodateinamen extrahiert wird",
"MessageShareExpirationWillBe": "Läuft am <strong>{0}</strong> ab",
"MessageShareExpiresIn": "Läuft in {0} ab",
"MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein.",
"MessageShareURLWillBe": "Der Freigabe Link wird <strong>{0}</strong> sein",
"MessageStartPlaybackAtTime": "Start der Wiedergabe für \"{0}\" bei {1}?",
"MessageTaskAudioFileNotWritable": "Die Audiodatei \"{0}\" ist schreibgeschützt",
"MessageTaskCanceledByUser": "Aufgabe vom Benutzer abgebrochen",
@ -1041,7 +1043,7 @@
"ToastRenameFailed": "Umbenennen fehlgeschlagen",
"ToastRescanFailed": "Erneut scannen fehlgeschlagen für {0}",
"ToastRescanRemoved": "Erneut scannen erledigt, Artikel wurde entfernt",
"ToastRescanUpToDate": "Erneut scannen erledigt, Artikel wahr auf dem neusten Stand",
"ToastRescanUpToDate": "Erneut scannen erledigt, Artikel war auf dem neusten Stand",
"ToastRescanUpdated": "Erneut scannen erledigt, Artikel wurde verändert",
"ToastScanFailed": "Fehler beim scannen des Artikels der Bibliothek",
"ToastSelectAtLeastOneUser": "Wähle mindestens einen Benutzer aus",

View file

@ -190,6 +190,7 @@
"HeaderSettingsExperimental": "Experimental Features",
"HeaderSettingsGeneral": "General",
"HeaderSettingsScanner": "Scanner",
"HeaderSettingsWebClient": "Web Client",
"HeaderSleepTimer": "Sleep Timer",
"HeaderStatsLargestItems": "Largest Items",
"HeaderStatsLongestItems": "Longest Items (hrs)",
@ -542,6 +543,7 @@
"LabelServerYearReview": "Server Year in Review ({0})",
"LabelSetEbookAsPrimary": "Set as primary",
"LabelSetEbookAsSupplementary": "Set as supplementary",
"LabelSettingsAllowIframe": "Allow embedding in an iframe",
"LabelSettingsAudiobooksOnly": "Audiobooks only",
"LabelSettingsAudiobooksOnlyHelp": "Enabling this setting will ignore ebook files unless they are inside an audiobook folder in which case they will be set as supplementary ebooks",
"LabelSettingsBookshelfViewHelp": "Skeumorphic design with wooden shelves",
@ -679,6 +681,8 @@
"LabelViewPlayerSettings": "View player settings",
"LabelViewQueue": "View player queue",
"LabelVolume": "Volume",
"LabelWebRedirectURLsDescription": "Authorize these URLs in your OAuth provider to allow redirection back to the web app after login:",
"LabelWebRedirectURLsSubfolder": "Subfolder for Redirect URLs",
"LabelWeekdaysToRun": "Weekdays to run",
"LabelXBooks": "{0} books",
"LabelXItems": "{0} items",

View file

@ -679,6 +679,8 @@
"LabelViewPlayerSettings": "Ver los ajustes del reproductor",
"LabelViewQueue": "Ver Fila del Reproductor",
"LabelVolume": "Volumen",
"LabelWebRedirectURLsDescription": "Autorice estas URL en su proveedor OAuth para permitir la redirección a la aplicación web después de iniciar sesión:",
"LabelWebRedirectURLsSubfolder": "Subcarpeta para URL de redireccionamiento",
"LabelWeekdaysToRun": "Correr en Días de la Semana",
"LabelXBooks": "{0} libros",
"LabelXItems": "{0} elementos",

View file

@ -271,7 +271,7 @@
"LabelCollapseSubSeries": "Podserijale prikaži sažeto",
"LabelCollection": "Zbirka",
"LabelCollections": "Zbirke",
"LabelComplete": "Dovršeno",
"LabelComplete": "Potpuno",
"LabelConfirmPassword": "Potvrda zaporke",
"LabelContinueListening": "Nastavi slušati",
"LabelContinueReading": "Nastavi čitati",
@ -532,7 +532,7 @@
"LabelSelectAllEpisodes": "Označi sve nastavke",
"LabelSelectEpisodesShowing": "Prikazujem {0} odabranih nastavaka",
"LabelSelectUsers": "Označi korisnike",
"LabelSendEbookToDevice": "Pošalji e-knjigu",
"LabelSendEbookToDevice": "Pošalji e-knjigu",
"LabelSequence": "Slijed",
"LabelSerial": "Serijal",
"LabelSeries": "Serijal",
@ -567,7 +567,7 @@
"LabelSettingsLibraryMarkAsFinishedTimeRemaining": "Preostalo vrijeme je manje od (sekundi)",
"LabelSettingsLibraryMarkAsFinishedWhen": "Označi medij dovršenim kada",
"LabelSettingsOnlyShowLaterBooksInContinueSeries": "Preskoči ranije knjige u funkciji Nastavi serijal",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako uključite ovu opciju, serijal će vam se nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.",
"LabelSettingsOnlyShowLaterBooksInContinueSeriesHelp": "Na polici početne stranice Nastavi serijal prikazuje se prva nezapočeta knjiga serijala koji imaju barem jednu dovršenu knjigu i nijednu započetu knjigu. Ako se ova opcija uključi serijal će nastaviti od zadnje dovršene knjige umjesto od prve nezapočete knjige.",
"LabelSettingsParseSubtitles": "Raščlani podnaslove",
"LabelSettingsParseSubtitlesHelp": "Iz naziva mape zvučne knjige raščlanjuje podnaslov.<br>Podnaslov mora biti odvojen s \" - \"<br>npr. \"Naslov knjige - Ovo je podnaslov\" imat će podnaslov \"Ovo je podnaslov\"",
"LabelSettingsPreferMatchedMetadata": "Daj prednost meta-podatcima prepoznatih stavki",
@ -679,6 +679,8 @@
"LabelViewPlayerSettings": "Pogledaj postavke reproduktora",
"LabelViewQueue": "Pogledaj redoslijed izvođenja reproduktora",
"LabelVolume": "Glasnoća",
"LabelWebRedirectURLsDescription": "Autoriziraj ove URL-ove u svom pružatelju OAuth ovjere kako bi omogućio preusmjeravanje natrag na web-aplikaciju nakon prijave:",
"LabelWebRedirectURLsSubfolder": "Podmapa za URL-ove preusmjeravanja",
"LabelWeekdaysToRun": "Dani u tjednu za pokretanje",
"LabelXBooks": "{0} knjiga",
"LabelXItems": "{0} stavki",

View file

@ -184,7 +184,7 @@
"HeaderScheduleEpisodeDownloads": "Načrtovanje samodejnega prenosa epizod",
"HeaderScheduleLibraryScans": "Načrtuj samodejno pregledovanje knjižnice",
"HeaderSession": "Seja",
"HeaderSetBackupSchedule": "Nastavite urnik varnostnega kopiranja",
"HeaderSetBackupSchedule": "Nastavi urnik varnostnega kopiranja",
"HeaderSettings": "Nastavitve",
"HeaderSettingsDisplay": "Zaslon",
"HeaderSettingsExperimental": "Eksperimentalne funkcije",
@ -679,6 +679,8 @@
"LabelViewPlayerSettings": "Ogled nastavitev predvajalnika",
"LabelViewQueue": "Ogled čakalno vrsto predvajalnika",
"LabelVolume": "Glasnost",
"LabelWebRedirectURLsDescription": "Avtorizirajte URL-je pri svojem ponudniku OAuth ter s tem omogočite preusmeritev nazaj v spletno aplikacijo po prijavi:",
"LabelWebRedirectURLsSubfolder": "Podmapa za URL-je preusmeritve",
"LabelWeekdaysToRun": "Delovni dnevi predvajanja",
"LabelXBooks": "{0} knjig",
"LabelXItems": "{0} elementov",
@ -830,7 +832,7 @@
"MessageSearchResultsFor": "Rezultati iskanja za",
"MessageSelected": "{0} izbrano",
"MessageServerCouldNotBeReached": "Strežnika ni bilo mogoče doseči",
"MessageSetChaptersFromTracksDescription": "Nastavite poglavja z uporabo vsake zvočne datoteke kot poglavja in naslova poglavja kot imena zvočne datoteke",
"MessageSetChaptersFromTracksDescription": "Nastavi poglavja z uporabo vsake zvočne datoteke kot poglavja in naslova poglavja kot imena zvočne datoteke",
"MessageShareExpirationWillBe": "Potečeno bo <strong>{0}</strong>",
"MessageShareExpiresIn": "Poteče čez {0}",
"MessageShareURLWillBe": "URL za skupno rabo bo <strong>{0}</strong>",

View file

@ -679,6 +679,8 @@
"LabelViewPlayerSettings": "Переглянути налаштування програвача",
"LabelViewQueue": "Переглянути чергу відтворення",
"LabelVolume": "Гучність",
"LabelWebRedirectURLsDescription": "Авторизуйте ці URL у вашому OAuth постачальнику, щоб дозволити редирекцію назад до веб-додатку після входу:",
"LabelWebRedirectURLsSubfolder": "Підпапка для Redirect URL",
"LabelWeekdaysToRun": "Виконувати у дні",
"LabelXBooks": "{0} книг",
"LabelXItems": "{0} елементів",

View file

@ -663,6 +663,7 @@
"LabelUpdateDetailsHelp": "找到匹配项时允许覆盖所选书籍存在的详细信息",
"LabelUpdatedAt": "更新时间",
"LabelUploaderDragAndDrop": "拖放文件或文件夹",
"LabelUploaderDragAndDropFilesOnly": "拖放文件",
"LabelUploaderDropFiles": "删除文件",
"LabelUploaderItemFetchMetadataHelp": "自动获取标题, 作者和系列",
"LabelUseAdvancedOptions": "使用高级选项",
@ -678,6 +679,8 @@
"LabelViewPlayerSettings": "查看播放器设置",
"LabelViewQueue": "查看播放列表",
"LabelVolume": "音量",
"LabelWebRedirectURLsDescription": "在你的 OAuth 提供商中授权这些链接,以允许在登录后重定向回 Web 应用程序:",
"LabelWebRedirectURLsSubfolder": "重定向 URL 的子文件夹",
"LabelWeekdaysToRun": "工作日运行",
"LabelXBooks": "{0} 本书",
"LabelXItems": "{0} 项目",