Compare commits

...

8 Commits

15 changed files with 584 additions and 82 deletions

View File

@@ -1,15 +1,12 @@
<template>
<div id="bookshelf" class="w-full overflow-y-auto">
<template v-for="shelf in totalShelves">
<div :key="shelf" :id="`shelf-${shelf - 1}`" class="w-full px-4 sm:px-8 relative"
:class="{ bookshelfRow: !isAlternativeBookshelfView }" :style="{ height: shelfHeight + 'px' }">
<div v-if="!isAlternativeBookshelfView" class="bookshelfDivider w-full absolute bottom-0 left-0 right-0 z-20"
:class="`h-${shelfDividerHeightIndex}`" />
<div :key="shelf" :id="`shelf-${shelf - 1}`" class="w-full px-4 sm:px-8 relative" :class="{ bookshelfRow: !isAlternativeBookshelfView }" :style="{ height: shelfHeight + 'px' }">
<div v-if="!isAlternativeBookshelfView" class="bookshelfDivider w-full absolute bottom-0 left-0 right-0 z-20" :class="`h-${shelfDividerHeightIndex}`" />
</div>
</template>
<div v-if="initialized && !totalShelves && !hasFilter && entityName === 'books'"
class="w-full flex flex-col items-center justify-center py-12">
<div v-if="initialized && !totalShelves && !hasFilter && entityName === 'books'" class="w-full flex flex-col items-center justify-center py-12">
<p class="text-center text-2xl font-book mb-4 py-4">{{ libraryName }} Library is empty!</p>
<div v-if="userIsAdminOrUp" class="flex">
<ui-btn to="/config" color="primary" class="w-52 mr-2">Configure Scanner</ui-btn>
@@ -335,20 +332,9 @@ export default {
}
}
this.$eventBus.$emit('bookshelf-total-entities', this.getEntitiesCount())
this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities)
}
},
getEntitiesCount() {
let uniqueEntities = new Set()
this.entities.forEach(entity => {
if (entity.collapsedSeries) {
entity.collapsedSeries.libraryItemIds.forEach(uniqueEntities.add, uniqueEntities)
} else {
uniqueEntities.add(entity.id)
}
});
return uniqueEntities.size
},
loadPage(page) {
this.pagesLoaded[page] = true
this.fetchEntites(page)
@@ -531,8 +517,8 @@ export default {
var indexOf = this.entities.findIndex((ent) => ent && ent.id === libraryItem.id)
if (indexOf >= 0) {
this.entities = this.entities.filter((ent) => ent.id !== libraryItem.id)
this.totalEntities = this.entities.length
this.$eventBus.$emit('bookshelf-total-entities', this.getEntitiesCount())
this.totalEntities--
this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities)
this.executeRebuild()
}
}
@@ -569,8 +555,8 @@ export default {
var indexOf = this.entities.findIndex((ent) => ent && ent.id === collection.id)
if (indexOf >= 0) {
this.entities = this.entities.filter((ent) => ent.id !== collection.id)
this.totalEntities = this.entities.length
this.$eventBus.$emit('bookshelf-total-entities', this.getEntitiesCount())
this.totalEntities--
this.$eventBus.$emit('bookshelf-total-entities', this.totalEntities)
this.executeRebuild()
}
},

View File

@@ -9,7 +9,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonHome }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonHome }}</p>
<div v-show="homePage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -17,7 +17,7 @@
<nuxt-link v-if="isPodcastLibrary" :to="`/library/${currentLibraryId}/podcast/latest`" class="w-full h-20 flex flex-col items-center justify-center text-white border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastLatestPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons">format_list_bulleted</span>
<p class="font-book pt-1" style="font-size: 0.9rem">{{ $strings.ButtonLatest }}</p>
<p class="font-book pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLatest }}</p>
<div v-show="isPodcastLatestPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -27,7 +27,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" />
</svg>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonLibrary }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonLibrary }}</p>
<div v-show="showLibrary" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -37,7 +37,7 @@
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17V7m0 10a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h2a2 2 0 012 2m0 10a2 2 0 002 2h2a2 2 0 002-2M9 7a2 2 0 012-2h2a2 2 0 012 2m0 10V7m0 10a2 2 0 002 2h2a2 2 0 002-2V7a2 2 0 00-2-2h-2a2 2 0 00-2 2" />
</svg>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonSeries }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonSeries }}</p>
<div v-show="isSeriesPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -45,7 +45,7 @@
<nuxt-link v-if="!isPodcastLibrary" :to="`/library/${currentLibraryId}/bookshelf/collections`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="paramId === 'collections' ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="material-icons-outlined">collections_bookmark</span>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonCollections }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonCollections }}</p>
<div v-show="paramId === 'collections'" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -58,7 +58,7 @@
/>
</svg>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonAuthors }}</p>
<p class="font-book pt-1 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonAuthors }}</p>
<div v-show="isAuthorsPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -66,7 +66,7 @@
<nuxt-link v-if="isPodcastLibrary && userIsAdminOrUp" :to="`/library/${currentLibraryId}/podcast/search`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-primary cursor-pointer relative" :class="isPodcastSearchPage ? 'bg-primary bg-opacity-80' : 'bg-bg bg-opacity-60'">
<span class="abs-icons icon-podcast text-xl"></span>
<p class="font-book pt-1.5" style="font-size: 0.9rem">{{ $strings.ButtonSearch }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 0.9rem">{{ $strings.ButtonSearch }}</p>
<div v-show="isPodcastSearchPage" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
</nuxt-link>
@@ -74,7 +74,7 @@
<nuxt-link v-if="numIssues" :to="`/library/${currentLibraryId}/bookshelf?filter=issues`" class="w-full h-20 flex flex-col items-center justify-center text-white text-opacity-80 border-b border-primary border-opacity-70 hover:bg-opacity-40 cursor-pointer relative" :class="showingIssues ? 'bg-error bg-opacity-40' : ' bg-error bg-opacity-20'">
<span class="material-icons text-2xl">warning</span>
<p class="font-book pt-1.5" style="font-size: 1rem">{{ $strings.ButtonIssues }}</p>
<p class="font-book pt-1.5 text-center leading-4" style="font-size: 1rem">{{ $strings.ButtonIssues }}</p>
<div v-show="showingIssues" class="h-full w-0.5 bg-yellow-400 absolute top-0 left-0" />
<div class="absolute top-1 right-1 w-4 h-4 rounded-full bg-white bg-opacity-30 flex items-center justify-center">

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "audiobookshelf-client",
"version": "2.2.3",
"version": "2.2.4",
"description": "Self-hosted audiobook and podcast client",
"main": "index.js",
"scripts": {

View File

@@ -10,7 +10,7 @@ const languageCodeMap = {
// 'es': 'Español',
'hr': 'Hrvatski',
'it': 'Italiano',
// 'pl': 'Polski',
'pl': 'Polski',
'zh-cn': '简体中文 (Simplified Chinese)'
}
Vue.prototype.$languageCodeOptions = Object.keys(languageCodeMap).map(code => {

View File

@@ -42,6 +42,8 @@
"ButtonPurgeAllCache": "Bereinige alle Zwischenspeicher",
"ButtonPurgeItemsCache": "Bereinige den Hörbuch/Podcast-Zwischenspeicher",
"ButtonPurgeMediaProgress": "Bereinige die Hörfortschritte",
"ButtonQueueAddItem": "Add to queue",
"ButtonQueueRemoveItem": "Remove from queue",
"ButtonQuickMatch": "Schnellabgleich",
"ButtonRead": "Lese",
"ButtonRemove": "Löschen",
@@ -105,6 +107,7 @@
"HeaderOtherFiles": "Sonstige Dateien",
"HeaderOpenRSSFeed": "RSS-Feed öffnen",
"HeaderPermissions": "Berechtigungen",
"HeaderPlayerQueue": "Player Queue",
"HeaderPodcastsToAdd": "Podcasts zum Hinzufügen",
"HeaderPreviewCover": "Vorschau Cover",
"HeaderRemoveEpisode": "Episode löschen",

View File

@@ -42,6 +42,8 @@
"ButtonPurgeAllCache": "Isprazni sav cache",
"ButtonPurgeItemsCache": "Isprazni Items Cache",
"ButtonPurgeMediaProgress": "Purge Media Progress",
"ButtonQueueAddItem": "Add to queue",
"ButtonQueueRemoveItem": "Remove from queue",
"ButtonQuickMatch": "Brzi match",
"ButtonRead": "Pročitaj",
"ButtonRemove": "Ukloni",
@@ -105,6 +107,7 @@
"HeaderOtherFiles": "Druge datoteke",
"HeaderOpenRSSFeed": "Otvori RSS Feed",
"HeaderPermissions": "Dozvole",
"HeaderPlayerQueue": "Player Queue",
"HeaderPodcastsToAdd": "Podcasti za dodati",
"HeaderPreviewCover": "Pregledaj Cover",
"HeaderRemoveEpisode": "Ukloni epizodu",

View File

@@ -42,6 +42,8 @@
"ButtonPurgeAllCache": "Elimina tutta la Cache",
"ButtonPurgeItemsCache": "Elimina la Cache selezionata",
"ButtonPurgeMediaProgress": "elimina info sui media ascoltati",
"ButtonQueueAddItem": "Add to queue",
"ButtonQueueRemoveItem": "Remove from queue",
"ButtonQuickMatch": "Ricerca meta Rapido",
"ButtonRead": "Leggi",
"ButtonRemove": "Rimuovi",
@@ -105,6 +107,7 @@
"HeaderOtherFiles": "Altri File",
"HeaderOpenRSSFeed": "Apri RSS Feed",
"HeaderPermissions": "Permessi",
"HeaderPlayerQueue": "Player Queue",
"HeaderPodcastsToAdd": "Podcasts da Aggiungere",
"HeaderPreviewCover": "Anteprima Cover",
"HeaderRemoveEpisode": "Rimuovi Episodi",

View File

@@ -1,54 +1,516 @@
{
"ButtonHome": "Home",
"ButtonLatest": "Aktualna wersja:",
"ButtonLibrary": "Biblioteka",
"ButtonSeries": "Serie",
"ButtonCollections": "Kolekcje",
"ButtonAdd": "Dodaj",
"ButtonAddChapters": "Dodaj rozdziały",
"ButtonAddPodcasts": "Dodaj podcasty",
"ButtonAddYourFirstLibrary": "Dodaj swoją pierwszą bibliotekę",
"ButtonApply": "Zatwierdź",
"ButtonApplyChapters": "Zatwierdź rozdziały",
"ButtonAuthors": "Autorzy",
"ButtonSearch": "Szukaj",
"ButtonBrowseForFolder": "Wyszukaj folder",
"ButtonCancel": "Anuluj",
"ButtonCancelEncode": "Anuluj enkodowanie",
"ButtonChangeRootPassword": "Zmień hasło roota",
"ButtonCheckAndDownloadNewEpisodes": "Sprawdź i pobierz nowe odcinki",
"ButtonChooseAFolder": "Wybierz folder",
"ButtonChooseFiles": "Wybierz pliki",
"ButtonCloseFeed": "Zamknij kanał",
"ButtonCollections": "Kolekcje",
"ButtonCreate": "Utwórz",
"ButtonCreateBackup": "Utwórz kopię zapasową",
"ButtonDelete": "Usuń",
"ButtonEditChapters": "Edytuj rozdziały",
"ButtonEditPodcast": "Edytuj podcast",
"ButtonForceReScan": "Wymuś ponowne skanowanie",
"ButtonFullPath": "Pełna ścieżka",
"ButtonHide": "Ukryj",
"ButtonHome": "Strona główna",
"ButtonIssues": "Błędy",
"ButtonChangePasswordSubmit": "Zatwierdź",
"ButtonLatest": "Aktualna wersja:",
"ButtonLogout": "Wyloguj",
"ButtonLookup": "Importuj",
"ButtonLibrary": "Biblioteka",
"ButtonManageTracks": "Zarządzaj ścieżkami",
"ButtonMapChapterTitles": "Mapuj nazwy rozdziałów",
"ButtonMatchAllAuthors": "Dopasuj wszystkich autorów",
"ButtonMatchBooks": "Dopasuj książki",
"ButtonNevermind": "Anuluj",
"ButtonOk": "Ok",
"ButtonOpenFeed": "Otwórz feed",
"ButtonOpenManager": "Otwórz menadżera",
"ButtonPlay": "Odtwarzaj",
"ButtonPlaying": "Odtwarzane",
"ButtonPurgeAllCache": "Wyczyść dane tymczasowe",
"ButtonPurgeItemsCache": "Wyczyść dane tymczasowe pozycji",
"ButtonPurgeMediaProgress": "Wyczyść postęp",
"ButtonQueueAddItem": "Add to queue",
"ButtonQueueRemoveItem": "Remove from queue",
"ButtonQuickMatch": "Szybkie dopasowanie",
"ButtonRead": "Czytaj",
"ButtonRemove": "Usuń",
"ButtonRemoveAll": "Usuń wszystko",
"ButtonRemoveAllLibraryItems": "Usuń wszystkie elementy z biblioteki",
"ButtonRemoveFromContinueListening": "Usuń z listy odtwarzania",
"ButtonRemoveSeriesFromContinueSeries": "Usuń serię z listy odtwarzania",
"ButtonReScan": "Ponowne skanowanie",
"ButtonReset": "Resetowanie",
"ButtonRestore": "Przywróć",
"ButtonSave": "Zapisz",
"ButtonSaveAndClose": "Zapisz i zamknij",
"ButtonSaveTracklist": "Zapisz listę odtwarzania",
"ButtonScan": "Zeskanuj",
"ButtonSearch": "Szukaj",
"ButtonSelectFolderPath": "Wybierz ścieżkę folderu",
"ButtonSeries": "Seria",
"ButtonShiftTimes": "Przesunięcie czasowe",
"ButtonShow": "Pokaż",
"ButtonStartM4BEncode": "Eksportuj jako plik M4B",
"ButtonStartMetadataEmbed": "Osadź metadane",
"ButtonSubmit": "Zgłoś",
"ButtonUpload": "Wgraj",
"ButtonUploadBackup": "Wgraj kopię zapasową",
"ButtonUploadCover": "Wgraj okładkę",
"ButtonUploadOPMLFile": "Wgraj plik OPML",
"ButtonViewAll": "Zobacz wszystko",
"ButtonYes": "Tak",
"HeaderAccount": "Konto",
"HeaderChangePassword": "Zmień hasło",
"HeaderSettings": "Ustawienia",
"HeaderLibraries": "Biblioteki",
"HeaderUsers": "Użytkownicy",
"HeaderListeningSessions": "Sesje słuchania",
"HeaderAdvanced": "Zaawansowane",
"HeaderAppriseNotificationSettings": "Ustawienia powiadomień Apprise",
"HeaderAudiobookTools": "Narzędzia do zarządzania audiobookami",
"HeaderAudioTracks": "Ścieżki audio",
"HeaderBackups": "Kopie zapasowe",
"HeaderLogs": "Logi",
"HeaderNotifications": "Powiadomienia",
"HeaderChangePassword": "Zmień hasło",
"HeaderChapters": "Rozdziały",
"HeaderChooseAFolder": "Wybierz folder",
"HeaderCollection": "Kolekcja",
"HeaderCollectionItems": "Elementy kolekcji",
"HeaderCover": "Okładka",
"HeaderDetails": "Szczegóły",
"HeaderEpisodes": "Rozdziały",
"HeaderFiles": "Pliki",
"HeaderFindChapters": "Wyszukaj rozdziały",
"HeaderIgnoredFiles": "Zignoruj pliki",
"HeaderItemFiles": "Pliki",
"HeaderLastListeningSession": "Ostatnio odtwarzana sesja",
"HeaderLatestEpisodes": "Najnowsze odcinki",
"HeaderLibraries": "Biblioteki",
"HeaderLibraryFiles": "Library Files",
"HeaderLibraryStats": "Statystyki biblioteki",
"HeaderYourStats": "Twoje statystyki",
"HeaderSettingsGeneral": "Ogólne",
"HeaderSettingsScanner": "Skanowanie",
"HeaderListeningSessions": "Sesje słuchania",
"HeaderListeningStats": "Statystyki odtwarzania",
"HeaderLogin": "Zaloguj się",
"HeaderLogs": "Logi",
"HeaderMatch": "Dopasuj",
"HeaderMetadataToEmbed": "Osadź metadane",
"HeaderNewAccount": "Nowe konto",
"HeaderNewLibrary": "Nowa biblioteka",
"HeaderNotifications": "Powiadomienia",
"HeaderOtherFiles": "Inne pliki",
"HeaderOpenRSSFeed": "Utwórz kanał RSS",
"HeaderPermissions": "Uprawnienia",
"HeaderPlayerQueue": "Player Queue",
"HeaderPodcastsToAdd": "Podcasty do dodania",
"HeaderPreviewCover": "Podgląd okładki",
"HeaderRemoveEpisode": "Usuń odcinek",
"HeaderRemoveEpisodes": "Usuń {0} odcinków",
"HeaderRSSFeedIsOpen": "Kanał RSS jest otwarty",
"HeaderSavedMediaProgress": "Zapisany postęp",
"HeaderSchedule": "Harmonogram",
"HeaderScheduleLibraryScans": "Zaplanuj automatyczne skanowanie biblioteki",
"HeaderSession": "Sesja",
"HeaderSetBackupSchedule": "Ustaw harmonogram tworzenia kopii zapasowej",
"HeaderSettings": "Ustawienia",
"HeaderSettingsDisplay": "Wyświetlanie",
"HeaderSettingsExperimental": "Funkcje eksperymentalne",
"LabelUsername": "Nazwa użytkownika",
"HeaderSettingsGeneral": "Ogólne",
"HeaderSettingsScanner": "Skanowanie",
"HeaderSleepTimer": "Wyłącznik czasowy",
"HeaderStatsLongestItems": "Najdłuższe pozycje (hrs)",
"HeaderStatsMinutesListeningChart": "Czas słuchania w minutach (ostatnie 7 dni)",
"HeaderStatsRecentSessions": "Ostatnie sesje",
"HeaderStatsTop10Authors": "Top 10 Autorów",
"HeaderStatsTop5Genres": "Top 5 Gatunków",
"HeaderTools": "Narzędzia",
"HeaderUpdateAccount": "Zaktualizuj konto",
"HeaderUpdateAuthor": "Zaktualizuj autorów",
"HeaderUpdateDetails": "Zaktualizuj szczegóły",
"HeaderUpdateLibrary": "Zaktualizuj bibliotekę",
"HeaderUsers": "Użytkownicy",
"HeaderYourStats": "Twoje statystyki",
"LabelAccountType": "Typ konta",
"LabelPassword": "Hasło",
"LabelNewPassword": "Nowe hasło",
"LabelAccountTypeAdmin": "Administrator",
"LabelAccountTypeGuest": "Gość",
"LabelAccountTypeUser": "Użytkownik",
"LabelActivity": "Aktywność",
"LabelAddToCollection": "Dodaj do kolekcji",
"LabelAddToCollectionBatch": "Dodaj {0} książki do kolekcji",
"LabelAllUsers": "Wszyscy użytkownicy",
"LabelAuthor": "Autor",
"LabelAuthors": "Autorzy",
"LabelAutoDownloadEpisodes": "Automatyczne pobieranie odcinków",
"LabelBackToUser": "Powrót",
"LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe",
"LabelBackupsEnableAutomaticBackupsHelp": "Kopie zapasowe są zapisywane w folderze /metadata/backups",
"LabelBackupsMaxBackupSize": "Maksymalny łączny rozmiar backupów (w GB)",
"LabelBackupsMaxBackupSizeHelp": "Jako zabezpieczenie przed błędną konfiguracją, kopie zapasowe nie będą wykonywane, jeśli przekroczą skonfigurowany rozmiar.",
"LabelBackupsNumberToKeep": "Liczba kopii zapasowych do przechowywania",
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
"LabelBooks": "Książki",
"LabelChangePassword": "Zmień hasło",
"LabelChaptersFound": "Znalezione rozdziały",
"LabelChapterTitle": "Tytuł rozdziału",
"LabelCollapseSeries": "Podsumuj serię",
"LabelCollections": "Kolekcje",
"LabelComplete": "Ukończone",
"LabelConfirmPassword": "Potwierdź hasło",
"LabelContinueListening": "Kontynuuj odtwarzanie",
"LabelContinueSeries": "Kontynuuj serię",
"LabelCover": "Okładka",
"LabelCoverImageURL": "URL okładki",
"LabelCreatedAt": "Utworzone",
"LabelCronExpression": "Wyrażenie CRON",
"LabelCurrent": "Aktualny",
"LabelCurrently": "Obecnie:",
"LabelDatetime": "Data i godzina",
"LabelDescription": "Opis",
"LabelDeselectAll": "Odznacz wszystko",
"LabelDevice": "Urządzenie",
"LabelDeviceInfo": "Informacja o urządzeniu",
"LabelDirectory": "Katalog",
"LabelDiscFromFilename": "Oznaczenie dysku z nazwy pliku",
"LabelDiscFromMetadata": "Oznaczenie dysku z metadanych",
"LabelDownload": "Pobierz",
"LabelDuration": "Czas trwania",
"LabelDurationFound": "Znaleziona długość:",
"LabelEdit": "Edytuj",
"LabelEnable": "Włącz",
"LabelEnd": "Zakończ",
"LabelEpisode": "Odcinek",
"LabelEpisodeTitle": "Tytuł odcinka",
"LabelEpisodeType": "Typ odcinka",
"LabelExplicit": "Nieprzyzwoite",
"LabelFeedURL": "URL kanału",
"LabelFile": "Plik",
"LabelFilename": "Nazwa pliku",
"LabelFilterByUser": "Filtruj według danego użytkownika",
"LabelFindEpisodes": "Znajdź odcinki",
"LabelFinished": "Zakończone",
"LabelFolder": "Folder",
"LabelFolders": "Foldery",
"LabelGenres": "Gatunki",
"LabelHardDeleteFile": "Usuń trwale plik",
"LabelHour": "Godzina",
"LabelIcon": "Ikona",
"LabelIncludeInTracklist": "Dołącz do listy odtwarzania",
"LabelIncomplete": "Nieukończone",
"LabelInProgress": "W trakcie",
"LabelInterval": "Interwał",
"LabelInvalidParts": "Nieprawidłowe części",
"LabelItem": "Pozycja",
"LabelLanguage": "Język",
"LabelLanguageDefaultServer": "Domyślny język serwera",
"LabelLastSeen": "Ostatnio widziany",
"LabelLastTime": "Ostatni czas",
"LabelLastUpdate": "Ostatnia aktualizacja",
"LabelLess": "Mniej",
"LabelLibrariesAccessibleToUser": "Biblioteki dostępne dla użytkownika",
"LabelLibrary": "Biblioteka",
"LabelLibraryItem": "Element biblioteki",
"LabelLibraryName": "Nazwa biblioteki",
"LabelLimit": "Limit",
"LabelListenAgain": "Słuchaj ponownie",
"LabelLookForNewEpisodesAfterDate": "Szukaj nowych odcinków po dacie",
"LabelMarkSeries": "Oznacz serię",
"LabelMediaPlayer": "Odtwarzacz",
"LabelMediaType": "Typ mediów",
"LabelMetadataProvider": "Dostawca metadanych",
"LabelMetaTag": "Tag",
"LabelMinute": "Minuta",
"LabelMissing": "Brakujący",
"LabelMissingParts": "Brakujące cześci",
"LabelMore": "Więcej",
"LabelName": "Nazwa",
"LabelNarrators": "Lektorzy",
"LabelNew": "Nowy",
"LabelNewestAuthors": "Najnowsi autorzy",
"LabelNewestEpisodes": "Najnowsze odcinki",
"LabelNewPassword": "Nowe hasło",
"LabelNotes": "Uwagi",
"LabelNotFinished": "Nieukończone",
"LabelNotificationEvent": "Zdarzenie",
"LabelNotificationAppriseURL": "URLe Apprise",
"LabelNotificationAvailableVariables": "Dostępne zmienne",
"LabelNotificationBodyTemplate": "Szablon treści powiadomienia",
"LabelNotificationTitleTemplate": "Szablon tytułu powiadmienia",
"LabelNotificationsMaxFailedAttempts": "Maksymalna liczba nieudanych prób",
"LabelNotificationsMaxFailedAttemptsHelp": "Powiadomienia są wyłączane, gdy próba ich wysyłki nie powiedzie się kilkukrotnie",
"LabelNotificationsMaxQueueSize": "Maksymalny rozmiar kolejki dla powiadomień",
"LabelNotificationsMaxQueueSizeHelp": "Zdarzenia są ograniczone do 1 na sekundę. Zdarzenia będą ignorowane jeśli kolejka ma maksymalny rozmiar. Zapobiega to spamowaniu powiadomieniami.",
"LabelOpenRSSFeed": "Otwórz kanał RSS",
"LabelPassword": "Hasło",
"LabelPath": "Ścieżka",
"LabelPermissionsAccessAllLibraries": "Ma dostęp do wszystkich bibliotek",
"LabelPermissionsAccessAllTags": "Ma dostęp do wszystkich tagów",
"LabelPermissionsAccessExplicitContent": "Ma dostęp do treści oznacznych jako nieprzyzwoite",
"LabelPermissionsDelete": "Ma możliwość usuwania",
"LabelPermissionsDownload": "Ma możliwość pobierania",
"LabelPermissionsUpdate": "Ma możliwość aktualizowania",
"LabelPermissionsUpload": "Ma możliwość dodawania",
"LabelPhotoPathURL": "Scieżka/URL do zdjęcia",
"LabelPlayMethod": "Metoda odtwarzania",
"LabelPodcast": "Podcast",
"LabelPodcasts": "Podcasty",
"LabelPrefixesToIgnore": "Ignorowane prefiksy (wielkość liter nie ma znaczenia)",
"LabelProgress": "Postęp",
"LabelProvider": "Dostawca",
"LabelPubDate": "Data publikacji",
"LabelPublisher": "Wydawca",
"LabelPublishYear": "Rok publikacji",
"LabelRecentlyAdded": "Niedawno dodany",
"LabelRecentSeries": "Ostatnie serie",
"LabelRegion": "Region",
"LabelReleaseDate": "Data wydania",
"LabelRSSFeedSlug": "RSS Feed Slug",
"LabelRSSFeedURL": "URL kanały RSS",
"LabelSearchTerm": "Wyszukiwanie frazy",
"LabelSearchTitle": "Wyszukaj tytuł",
"LabelSearchTitleOrASIN": "Szukaj tytuł lub ASIN",
"LabelSeason": "Sezon",
"LabelSequence": "Kolejność",
"LabelSeries": "Serie",
"LabelSeriesName": "Nazwy serii",
"LabelSettingsBookshelfViewHelp": "Widok półki z ksiązkami",
"LabelSettingsChromecastSupport": "Wsparcie Chromecast",
"LabelSettingsDateFormat": "Format daty",
"LabelSettingsDisableWatcher": "Wyłącz monitorowanie",
"LabelSettingsDisableWatcherForLibrary": "Wyłącz monitorowanie folderów dla biblioteki",
"LabelSettingsDisableWatcherHelp": "Wyłącz automatyczne dodawanie/aktualizowanie elementów po wykryciu zmian w plikach. *Wymaga restartu serwera",
"LabelSettingsEnableEReader": "Włącz e-czytnika dla wszystkich użytkowników",
"LabelSettingsEnableEReaderHelp": "E-czytnik jest wciąż w fazie rozwoju, ale użyj tego ustawienia, aby udostępnić go wszystkim użytkownikom (lub użyj przełącznika \"Funkcje eksperymentalne\" aby włączyć funkcję tylko dla Ciebie)",
"LabelSettingsExperimentalFeatures": "Funkcje eksperymentalne",
"LabelSettingsExperimentalFeaturesHelp": "Funkcje w trakcie rozwoju, które mogą zyskanć na Twojej opinii i pomocy w testowaniu. Kliknij, aby otworzyć dyskusję na githubie.",
"LabelSettingsFindCovers": "Szukanie okładek",
"LabelSettingsFindCoversHelp": "Jeśli audiobook nie posiada zintegrowanej okładki albo w folderze nie zostanie znaleziony plik okładki, skaner podejmie próbę pobrania okładki z sieci. <br>Uwaga: może to wydłuzyć proces skanowania",
"LabelSettingsHomePageBookshelfView": "Widok półki z książkami na stronie głównej",
"LabelSettingsLibraryBookshelfView": "Widok półki z książkami na stronie biblioteki",
"LabelSettingsOverdriveMediaMarkers": "Użyj markerów Overdrive Media Markers dla rozdziałów",
"LabelSettingsOverdriveMediaMarkersHelp": "Pliki MP3 z serwisu Overdrive mają wbudowane znaczniki czasu rozdziałów jako niestandardowe metadane. Włączenie tej funkcji spowoduje automatyczne użycie tych znaczników do oznaczania czasu rozdziałów.",
"LabelSettingsParseSubtitles": "Przetwarzaj podtytuły",
"LabelSettingsParseSubtitlesHelp": "Opcja pozwala na pobranie podtytułu z nazwy folderu z audiobookiem. <br>Podtytuł musi być rozdzielony za pomocą separatora \" - \"<br>Przykład: \"Book Title - A Subtitle Here\" podtytuł \"A Subtitle Here\"",
"LabelSettingsPreferAudioMetadata": "Preferuj metadane audio",
"LabelSettingsPreferAudioMetadataHelp": "Znaczniki meta ID3 plików audio będą używane dla szczegółów książki zamiast nazw folderów",
"LabelSettingsPreferMatchedMetadata": "Preferowanie dopasowanych metadanych",
"LabelSettingsPreferMatchedMetadataHelp": "Dopasowane dane będą miały pierwszeństwo nad szczegółami pozycji podczas używania Szybkiego dopasowania. Domyślnie Szybkie dopasowanie uzupełnia tylko brakujące szczegóły.",
"LabelSettingsPreferOPFMetadata": "Preferowanie metadanych OPF",
"LabelSettingsPreferOPFMetadataHelp": "Metadane pliku OPF będą używane dla szczegółów książki zamiast nazw folderów",
"LabelSettingsSkipMatchingBooksWithASIN": "Pomiń dopasowanie książek, które już mają ASIN",
"LabelSettingsSkipMatchingBooksWithISBN": "Pomiń dopasowanie książek, które już mają ISBN",
"LabelSettingsSortingIgnorePrefixes": "Ignoruj prefiksy podczas sortowania",
"LabelSettingsSortingIgnorePrefixesHelp": "np. dla prefiksu \"the\" tytuł ksiązki \"The Book Title\" będzie sortowany jako \"Book Title, The\"",
"LabelSettingsStoreCoversWithItem": "Przechowuj okładkę w folderze książki",
"LabelSettingsStoreCoversWithItemHelp": "Domyślnie okładki są przechowywane w folderze /metadata/items, włączenie tej opcji spowoduje, że okładka będzie przechowywana w folderze ksiązki. Tylko jedna okładka o nazwie pliku \"cover\" będzie przechowywana.",
"LabelSettingsStoreMetadataWithItem": "Przechowuj metadane w folderze książki",
"LabelSettingsStoreMetadataWithItemHelp": "Domyślnie metadane są przechowywane w folderze /metadata/items, włączenie tej opcji spowoduje, że okładka będzie przechowywana w folderze ksiązki. Tylko jedna okładka o nazwie pliku \"cover\" będzie przechowywana. Rozszerzenie pliku metadanych: .abs",
"LabelSettingsSortingIgnorePrefixes": "Ignoruj prefiksy podczas sortowania",
"LabelSettingsSortingIgnorePrefixesHelp": "np. dla prefiksu \"the\" tytuł ksiązki \"The Book Title\" będzie sortowany jako \"Book Title, The\"",
"LabelPrefixesToIgnore": "Ignorowane prefiksy (wielkość liter nie ma znaczenia)",
"LabelSettingsChromecastSupport": "Wsparcie Chromecast",
"LabelSettingsHomePageBookshelfView": "Widok półki z książkami na stronie głównej",
"LabelSettingsLibraryBookshelfView": "Widok półki z książkami na stronie biblioteki",
"LabelSettingsBookshelfViewHelp": "Widok półki z ksiązkami",
"LabelSettingsDateFormat": "Format daty",
"LabelSettingsParseSubtitles": "Przetwarzaj podtytuły",
"LabelSettingsParseSubtitlesHelp": "Opcja pozwala na pobranie podtytułu z nazwy folderu z audiobookiem. <br>Podtytuł musi być rozdzielony za pomocą separatora \" - \"<br>Przykład: \"Book Title - A Subtitle Here\" podtytuł \"A Subtitle Here\"",
"LabelSettingsFindCovers": "Szukanie okładek",
"LabelSettingsFindCoversHelp": "Jeśli audiobook nie posiada zintegrowanej okładki albo w folderze nie zostanie znaleziony plik okładki, skaner podejmie próbę pobrania okładki z sieci. <br>Uwaga: może to wydłuzyć proces skanowania",
"LabelSettingsSquareBookCovers": "Używaj kwadratowych okładek książek",
"LabelSettingsSquareBookCoversHelp": "Preferuj stosowanie kwadratowych okładek zamiast standardowych okładek książkowych o propocji 1,6:1",
"LabelShowAll": "Pokaż wszystko",
"LabelSize": "Rozmiar",
"LabelStart": "Rozpocznij",
"LabelStarted": "Rozpoczęty",
"LabelStartedAt": "Rozpoczęto",
"LabelStartTime": "Czas rozpoczęcia",
"LabelStatsAudioTracks": "Ścieżki audio",
"LabelStatsAuthors": "Autorzy",
"LabelStatsBestDay": "Najlepszy dzień",
"LabelStatsDailyAverage": "Średnia dzienna",
"LabelStatsDays": "Dni",
"LabelStatsDaysListened": "Dni słuchania",
"LabelStatsHours": "Godziny",
"LabelStatsInARow": "z rzędu",
"LabelStatsItemsFinished": "Pozycje zakończone",
"LabelStatsItemsInLibrary": "Pozycje w bibliotece",
"LabelStatsMinutes": "Minuty",
"LabelStatsMinutesListening": "Minuty odtwarzania",
"LabelStatsOverall": "Ogólnie",
"LabelStatsWeekListening": "Tydzień odtwarzania",
"LabelSubtitle": "Podtytuł",
"LabelSupportedFileTypes": "Obsługiwane typy plików",
"LabelTags": "Tagi",
"LabelTagsAccessibleToUser": "Tagi dostępne dla użytkownika",
"LabelTimeListened": "Czas odtwarzania",
"LabelTimeListenedToday": "Czas odtwarzania dzisiaj",
"LabelTimeRemaining": "Pozostało {0}",
"LabelTimeToShift": "Czas do przesunięcia w sekundach",
"LabelTitle": "Tytuł",
"LabelTotalTimeListened": "Całkowity czas odtwarzania",
"LabelTrackFromFilename": "Ścieżka z nazwy pliku",
"LabelTrackFromMetadata": "Ścieżka z metadanych",
"LabelType": "Typ",
"LabelUnknown": "Nieznany",
"LabelUpdateCover": "Zaktalizuj odkładkę",
"LabelUpdateCoverHelp": "Umożliwienie nadpisania istniejących okładek dla wybranych książek w przypadku znalezienia dopasowania",
"LabelUpdatedAt": "Zaktualizaowano",
"LabelUpdateDetails": "Zaktualizuj szczegóły",
"LabelUpdateDetailsHelp": "Umożliwienie nadpisania istniejących szczegółów dla wybranych książek w przypadku znalezienia dopasowania",
"LabelUploaderDragAndDrop": "Przeciągnij i puść foldery lub pliki",
"LabelUploaderDropFiles": "Puść pliki",
"LabelUseChapterTrack": "Use chapter track",
"LabelUseFullTrack": "Użycie ścieżki rozdziału",
"LabelUser": "Użytkownik",
"LabelUsername": "Nazwa użytkownika",
"LabelValue": "Wartość",
"LabelVersion": "Wersja",
"Dni tygodnia": "Weekdays to run",
"LabelYourAudiobookDuration": "Czas trwania audiobooka",
"LabelYourBookmarks": "Twoje zakładki",
"LabelYourProgress": "Twój postęp",
"MessageBackupsDescription": "Kopie zapasowe obejmują użytkowników, postępy użytkowników, szczegóły pozycji biblioteki, ustawienia serwera i obrazy przechowywane w",
"MessageBackupsNote": "Kopie zapasowe nie obejmują żadnych plików przechowywanych w folderach biblioteki.",
"MessageBatchQuickMatchDescription": "Quick Match będzie próbował dodać brakujące okładki i metadane dla wybranych elementów. Włącz poniższe opcje, aby umożliwić Quick Match nadpisanie istniejących okładek i/lub metadanych.",
"MessageChapterEndIsAfter": "Koniec rozdziału następuje po zakończeniu audiobooka",
"MessageChapterStartIsAfter": "Początek rozdziału następuje po zakończeniu audiobooka",
"MessageCheckingCron": "Sprawdzanie cron...",
"MessageConfirmDeleteBackup": "Czy na pewno chcesz usunąć kopię zapasową dla {0}?",
"MessageConfirmDeleteSession": "Czy na pewno chcesz usunąć tę sesję?",
"MessageConfirmDeleteLibrary": "Czy na pewno chcesz trwale usunąć bibliotekę \"{0}\"?",
"MessageConfirmForceReScan": "Czy na pewno chcesz wymusić ponowne skanowanie?",
"MessageConfirmRemoveCollection": "Czy na pewno chcesz usunąć kolekcję \"{0}\"?",
"MessageConfirmRemoveEpisode": "Czy na pewno chcesz usunąć odcinek \"{0}\"?",
"MessageConfirmRemoveEpisodes": "Czy na pewno chcesz usunąć {0} odcinki?",
"MessageDownloadingEpisode": "Pobieranie odcinka",
"MessageDragFilesIntoTrackOrder": "przeciągnij pliki aby ustawić właściwą kolejność utworów",
"MessageEmbedFinished": "Osadzanie zakończone!",
"MessageEpisodesQueuedForDownload": "{0} odcinki w kolejce do pobrania",
"MessageFeedURLWillBe": "URL kanału: {0}",
"MessageFetching": "Pobieranie...",
"MessageForceReScanDescription": "przeskanuje wszystkie pliki ponownie, jak przy świeżym skanowaniu. Tagi ID3 plików audio, pliki OPF i pliki tekstowe będą skanowane jak nowe.",
"MessageImportantNotice": "Ważna informacja!",
"MessageInsertChapterBelow": "Wstaw rozdział poniżej",
"MessageItemsSelected": "{0} zaznaczone elementy",
"MessageJoinUsOn": "Dołącz do nas na",
"MessageListeningSessionsInTheLastYear": "{0} sesje odsłuchowe w ostatnim roku",
"MessageLoading": "Ładowanie...",
"MessageLoadingFolders": "Ładowanie folderów...",
"MessageM4BFailed": "Tworzenie pliku M4B nie powiodło się",
"MessageM4BFinished": "Tworzenie pliku M4B zakończyło się!",
"MessageMapChapterTitles": "Mapowanie tytułów rozdziałów do istniejących rozdziałów audiobooka bez dostosowywania znaczników czasu",
"MessageMarkAsFinished": "Oznacz jako ukończone",
"MessageMarkAsNotFinished": "Oznacz jako nieukończone",
"MessageMatchBooksDescription": "spróbuje dopasować książki w bibliotece bez plików audio, korzystając z wybranego dostawcy wyszukiwania i wypełnić puste szczegóły i okładki. Nie nadpisuje informacji.",
"MessageNoAudioTracks": "Brak ścieżek audio",
"MessageNoAuthors": "Brak autorów",
"MessageNoBackups": "Brak kopii zapasowych",
"MessageNoBookmarks": "Brak zakładek",
"MessageNoChapters": "Brak rozdziałów",
"MessageNoCollections": "Brak kolekcji",
"MessageNoCoversFound": "Okładki nieznalezione",
"MessageNoDescription": "Brak opisu",
"MessageNoEpisodeMatchesFound": "Nie znaleziono pasujących odcinków",
"MessageNoEpisodes": "Brak odcinków",
"MessageNoFoldersAvailable": "Brak dostępnych folderów",
"MessageNoGenres": "Brak gatunków",
"MessageNoItems": "Brak elementów",
"MessageNoItemsFound": "Nie znaleziono żadnych elemntów",
"MessageNoListeningSessions": "Brak sesji odtwarzania",
"MessageNoLogs": "Brak logów",
"MessageNoMediaProgress": "Brak postępu",
"MessageNoNotifications": "Brak powiadomień",
"MessageNoPodcastsFound": "Nie znaleziono podcastów",
"MessageNoResults": "Brak wyników",
"MessageNoSearchResultsFor": "Brak wyników wyszukiwania dla \"{0}\"",
"MessageNoUpdateNecessary": "Brak konieczności aktualizacji",
"MessageNoUpdatesWereNecessary": "Brak aktualizacji",
"MessagePodcastHasNoRSSFeedForMatching": "Podcast nie ma adresu url kanału RSS, który mógłby zostać użyty do dopasowania",
"MessageQuickMatchDescription": "Wypełnij puste informacje i okładkę pierwszym wynikiem dopasowania z '{0}'. Nie nadpisuje szczegółów, chyba że włączone jest ustawienie serwera 'Preferuj dopasowane metadane'.",
"MessageRemoveAllItemsWarning": "UWAGA! Ta akcja usunie wszystkie elementy biblioteki z bazy danych, w tym wszystkie aktualizacje lub dopasowania, które zostały wykonane. Pliki pozostaną niezmienione. Czy jesteś pewien?",
"MessageRemoveEpisodes": "Usuń {0} odcinków",
"MessageRemoveUserWarning": "Czy na pewno chcesz trwale usunąć użytkownika \"{0}\"?",
"MessageReportBugsAndContribute": "Zgłoś błędy, pomysły i pomóż rozwijać aplikację na",
"MessageRestoreBackupConfirm": "Czy na pewno chcesz przywrócić kopię zapasową utworzoną w dniu",
"MessageRestoreBackupWarning": "Przywrócenie kopii zapasowej spowoduje nadpisane bazy danych w folderze /config oraz okładke w folderze /metadata/items & /metadata/authors.<br /><br />Kopie zapasowe nie modyfikują żadnego pliku w folderach z plikami audio. Jeśli włączyłeś ustawienia serwera, aby przechowywać okładki i metadane w folderach biblioteki, to nie są one zapisywane w kopii zapasowej lub nadpisywane<br /><br />Wszyscy klienci korzystający z Twojego serwera będą automatycznie odświeżani",
"MessageSearchResultsFor": "Wyniki wyszukiwania dla",
"MessageServerCouldNotBeReached": "Nie udało się uzyskać połączenia z serwerem",
"MessageStartPlaybackAtTime": "Rozpoczęcie odtwarzania \"{0}\" od {1}?",
"MessageThinking": "Myślę...",
"MessageUploaderItemFailed": "Nie udało się przesłać",
"MessageUploaderItemSuccess": "Przesłanie powiodło się!",
"MessageUploading": "Przesyłanie...",
"MessageValidCronExpression": "Sprawdź wyrażenie CRON",
"MessageWatcherIsDisabledGlobally": "Watcher jest wyłączony globalnie w ustawieniach serwera",
"MessageYourAudiobookDurationIsLonger": "Czas trwania Twojego audiobooka jest dłuższy niż znaleziony czas trwania",
"MessageYourAudiobookDurationIsShorter": "Czas trwania Twojego audiobooka jest krótszy niż znaleziony czas trwania",
"NoteChangeRootPassword": "Tylko użytkownik root, może posiadać puste hasło",
"SearchPlaceholder": "Wyszukaj.."
"NoteChapterEditorTimes": "Uwaga: Czas rozpoczęcia pierwszego rozdziału musi pozostać na poziomie 0:00, a czas rozpoczęcia ostatniego rozdziału nie może przekroczyć czasu trwania audiobooka.",
"NoteFolderPicker": "Note: folders already mapped will not be shown",
"NoteFolderPickerDebian": "Uwaga: Wybór folderu w instalcji opartej o system debian nie jest w pełni zaimplementowany. Powinieneś wprowadzić ścieżkę do swojej biblioteki bezpośrednio.",
"NoteRSSFeedPodcastAppsHttps": "Ostrzeżenie: Większość aplikacji do obsługi podcastów wymaga, aby adres URL kanału RSS korzystał z protokołu HTTPS.",
"NoteRSSFeedPodcastAppsPubDate": "Ostrzeżenie: 1 lub więcej odcinków nie ma daty publikacji. Niektóre aplikacje do słuchania podcastów tego wymagają.",
"NoteUploaderFoldersWithMediaFiles": "Foldery z plikami multimedialnymi będą traktowane jako osobne elementy w bibliotece.",
"NoteUploaderOnlyAudioFiles": "Jeśli przesyłasz tylko pliki audio, każdy plik audio będzie traktowany jako osobny audiobook.",
"NoteUploaderUnsupportedFiles": "Nieobsługiwane pliki są ignorowane. Podczas dodawania folderu, inne pliki, które nie znajdują się w folderze elementu, są ignorowane.",
"PlaceholderNewCollection": "Nowa nazwa kolekcji",
"PlaceholderNewFolderPath": "Nowa ścieżka folderu",
"PlaceholderSearch": "Szukanie..",
"ToastAccountUpdateFailed": "Nie udało się zaktualizować konta",
"ToastAccountUpdateSuccess": "Zaktualizowano konto",
"ToastAuthorImageRemoveFailed": "Nie udało się usunąć obrazu",
"ToastAuthorImageRemoveSuccess": "Zdjęcie autora usunięte",
"ToastAuthorUpdateFailed": "nie udało się zaktualizować autora",
"ToastAuthorUpdateMerged": "Autor scalony",
"ToastAuthorUpdateSuccess": "Autor zaktualizowany",
"ToastAuthorUpdateSuccessNoImageFound": "Autor zaktualizowany (nie znaleziono obrazu)",
"ToastBackupCreateFailed": "Nie udało się utworzyć kopii zapasowej",
"ToastBackupCreateSuccess": "Utworzono kopię zapasową",
"ToastBackupDeleteFailed": "Failed to delete backup",
"ToastBackupDeleteSuccess": "Nie udało się usunąć kopii zapasowej",
"ToastBackupRestoreFailed": "Nie udało się przywrócić kopii zapasowej",
"ToastBackupUploadFailed": "Nie udało się przesłać kopii zapasowej",
"ToastBackupUploadSuccess": "Kopia zapasowa została przesłana",
"ToastBatchUpdateFailed": "Aktualizacja wsadowa nie powiodła się",
"ToastBatchUpdateSuccess": "Aktualizacja wsadowa powiodła się",
"ToastBookmarkCreateFailed": "Nie udało się utworzyć zakładki",
"ToastBookmarkCreateSuccess": "Dodano zakładkę",
"ToastBookmarkRemoveFailed": "Nie udało się usunąć zakładki",
"ToastBookmarkRemoveSuccess": "Zakładka została usunięta",
"ToastBookmarkUpdateFailed": "Nie udało się zaktualizować zakładki",
"ToastBookmarkUpdateSuccess": "Zaktualizowano zakładkę",
"ToastCollectionItemsRemoveFailed": "Nie udało się usunąć pozycji z kolekcji",
"ToastCollectionItemsRemoveSuccess": "Przedmiot(y) zostały usunięte z kolekcji",
"ToastCollectionRemoveFailed": "Nie udało się usunąć kolekcji",
"ToastCollectionRemoveSuccess": "Kolekcja usunięta",
"ToastCollectionUpdateFailed": "Nie udało się zaktualizować kolekcji",
"ToastCollectionUpdateSuccess": "Zaktualizowano kolekcję",
"ToastItemCoverUpdateFailed": "Nie udało się zaktualizować okładki",
"ToastItemCoverUpdateSuccess": "Zaktualizowano okładkę",
"ToastItemDetailsUpdateFailed": "Nie udało się zaktualizować szczegółów",
"ToastItemDetailsUpdateSuccess": "Zaktualizowano szczegóły",
"ToastItemDetailsUpdateUnneeded": "Brak aktulizacji dla pozycji",
"ToastItemMarkedAsFinishedFailed": "Nie udało się oznaczyć jako zakończone",
"ToastItemMarkedAsFinishedSuccess": "Pozycja oznaczona jako ukończona",
"ToastItemMarkedAsNotFinishedFailed": "Oznaczenie pozycji jako ukończonej nie powiodło się",
"ToastItemMarkedAsNotFinishedSuccess": "Pozycja oznaczona jako ukończon",
"ToastLibraryCreateFailed": "Nie udało się utworzyć biblioteki",
"ToastLibraryCreateSuccess": "Biblioteka \"{0}\" stworzona",
"ToastLibraryDeleteFailed": "Nie udało się usunąć biblioteki",
"ToastLibraryDeleteSuccess": "Biblioteka usunięta",
"ToastLibraryScanFailedToStart": "Nie udało się rozpocząć skanowania",
"ToastLibraryScanStarted": "Rozpoczęto skanowanie biblioteki",
"ToastLibraryUpdateFailed": "Nie udało się zaktualizować biblioteki",
"ToastLibraryUpdateSuccess": "Zaktualizowano \"{0}\" pozycji",
"ToastPodcastCreateFailed": "Nie udało się utworzyć podcastu",
"ToastPodcastCreateSuccess": "Podcast został pomyślnie utworzony",
"ToastRemoveItemFromCollectionSuccess": "Pozycja usunięta z kolekcji",
"ToastRemoveItemFromCollectionFailed": "Nie udało się usunąć elementu z kolekcji",
"ToastRSSFeedCloseFailed": "Zamknięcie kanału RSS nie powiodło się",
"ToastRSSFeedCloseSuccess": "Zamknięcie kanału RSS powiodło się",
"ToastSessionDeleteFailed": "Nie udało się usunąć sesji",
"ToastSessionDeleteSuccess": "Sesja usunięta",
"ToastUserDeleteFailed": "Nie udało się usunąć użytkownika",
"ToastUserDeleteSuccess": "Użytkownik usunięty",
"WeekdayFriday": "Piątek",
"WeekdayMonday": "Poniedziałek",
"WeekdaySaturday": "Sobota",
"WeekdaySunday": "Niedziela",
"WeekdayThursday": "Czwartek",
"WeekdayTuesday": "Wtorek",
"WeekdayWednesday": "Środa"
}

View File

@@ -42,6 +42,8 @@
"ButtonPurgeAllCache": "清理所有缓存",
"ButtonPurgeItemsCache": "清理项目缓存",
"ButtonPurgeMediaProgress": "清理媒体进度",
"ButtonQueueAddItem": "Add to queue",
"ButtonQueueRemoveItem": "Remove from queue",
"ButtonQuickMatch": "快速匹配",
"ButtonRead": "读取",
"ButtonRemove": "移除",
@@ -105,6 +107,7 @@
"HeaderOtherFiles": "其他文件",
"HeaderOpenRSSFeed": "打开 RSS 源",
"HeaderPermissions": "权限",
"HeaderPlayerQueue": "Player Queue",
"HeaderPodcastsToAdd": "要添加的播客",
"HeaderPreviewCover": "预览封面",
"HeaderRemoveEpisode": "移除剧集",
@@ -510,4 +513,4 @@
"WeekdayThursday": "星期四",
"WeekdayTuesday": "星期二",
"WeekdayWednesday": "星期三"
}
}

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "audiobookshelf",
"version": "2.2.3",
"version": "2.2.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "audiobookshelf",
"version": "2.2.3",
"version": "2.2.4",
"license": "GPL-3.0",
"dependencies": {
"axios": "^0.26.1",

View File

@@ -1,6 +1,6 @@
{
"name": "audiobookshelf",
"version": "2.2.3",
"version": "2.2.4",
"description": "Self-hosted audiobook and podcast server",
"main": "index.js",
"scripts": {

View File

@@ -188,7 +188,17 @@ class LibraryController {
if (!(collapsedItems.length == 1 && collapsedItems[0].collapsedSeries)) {
libraryItems = collapsedItems
payload.total = libraryItems.length
// Get accurate total entities
let uniqueEntities = new Set()
libraryItems.forEach((item) => {
if (item.collapsedSeries) {
item.collapsedSeries.books.forEach(book => uniqueEntities.add(book.id))
} else {
uniqueEntities.add(item.id)
}
})
payload.total = uniqueEntities.size
}
}
@@ -265,6 +275,12 @@ class LibraryController {
libraryItems = naturalSort(libraryItems).by(sortArray)
}
// Step 3.5: Limit items
if (payload.limit) {
var startIndex = payload.page * payload.limit
libraryItems = libraryItems.slice(startIndex, startIndex + payload.limit)
}
// Step 4 - Transform the items to pass to the client side
payload.results = libraryItems.map(li => {
let json = payload.minified ? li.toJSONMinified() : li.toJSON()

View File

@@ -179,7 +179,7 @@ class UserController {
// POST: api/users/online (admin)
async getOnlineUsers(req, res) {
if (!req.user.isAdminOrUp) {
return res.sendStatus(404)
return res.sendStatus(403)
}
const usersOnline = this.getUsersOnline()

View File

@@ -130,8 +130,8 @@ class User {
toJSONForPublic(sessions, libraryItems) {
var userSession = sessions ? sessions.find(s => s.userId === this.id) : null
var session = null
if (session) {
var libraryItem = libraryItems.find(li => li.id === session.libraryItemId)
if (userSession) {
var libraryItem = libraryItems.find(li => li.id === userSession.libraryItemId)
if (libraryItem) {
session = userSession.toJSONForClient(libraryItem)
}
@@ -266,16 +266,42 @@ class User {
return firstAccessibleLibrary.id
}
// Returns most recent media progress w/ `media` object and optionally an `episode` object
getMostRecentItemProgress(libraryItems) {
if (!this.mediaProgress.length) return null
var lip = this.mediaProgress.map(lip => lip.toJSON())
lip.sort((a, b) => b.lastUpdate - a.lastUpdate)
var mostRecentWithLip = lip.find(li => libraryItems.find(_li => _li.id === li.id))
if (!mostRecentWithLip) return null
var libraryItem = libraryItems.find(li => li.id === mostRecentWithLip.id)
var mediaProgressObjects = this.mediaProgress.map(lip => lip.toJSON())
mediaProgressObjects.sort((a, b) => b.lastUpdate - a.lastUpdate)
var libraryItemMedia = null
var progressEpisode = null
// Find the most recent progress that still has a libraryItem and episode
var mostRecentProgress = mediaProgressObjects.find((progress) => {
const libraryItem = libraryItems.find(li => li.id === progress.libraryItemId)
if (!libraryItem) {
Logger.warn('[User] Library item not found for users progress ' + progress.libraryItemId)
return false
} else if (progress.episodeId) {
const episode = libraryItem.mediaType === 'podcast' ? libraryItem.media.getEpisode(progress.episodeId) : null
if (!episode) {
Logger.warn(`[User] Episode ${progress.episodeId} not found for user media progress, podcast: ${libraryItem.media.metadata.title}`)
return false
} else {
libraryItemMedia = libraryItem.media.toJSONExpanded()
progressEpisode = episode.toJSON()
return true
}
} else {
libraryItemMedia = libraryItem.media.toJSONExpanded()
return true
}
})
if (!mostRecentProgress) return null
return {
...mostRecentWithLip,
media: libraryItem.media.toJSONExpanded()
...mostRecentProgress,
media: libraryItemMedia,
episode: progressEpisode
}
}