From ba4061e5a406c03bffe178232a0a5f7172649ceb Mon Sep 17 00:00:00 2001
From: Hadrien Patte {{ title }} {{ $strings.MessageNoDescription }} {{ episode.subtitle }} Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }} Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }} {{ $strings.LabelDuration }}: {{ $elapsedPretty(Number(episode.duration)) }} {{ $strings.LabelSize }}: {{ $bytesPretty(Number(episode.enclosure.length)) }}
{{ $strings.LabelDuration }}
++ {{ audioFileDuration }} +
+Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}
-{{ $strings.LabelDuration }}: {{ $elapsedPretty(Number(episode.duration)) }}
+{{ $strings.LabelDuration }}: {{ $elapsedPretty(episode.durationSeconds) }}
{{ $strings.LabelSize }}: {{ $bytesPretty(Number(episode.enclosure.length)) }}
diff --git a/server/utils/podcastUtils.js b/server/utils/podcastUtils.js index 12469160e..b62e024f0 100644 --- a/server/utils/podcastUtils.js +++ b/server/utils/podcastUtils.js @@ -25,6 +25,7 @@ const Fuse = require('../libs/fusejs') * @property {string} episode * @property {string} author * @property {string} duration + * @property {number|null} durationSeconds - Parsed from duration string if duration is valid * @property {string} explicit * @property {number} publishedAt - Unix timestamp * @property {{ url: string, type?: string, length?: string }} enclosure @@ -217,8 +218,9 @@ function extractEpisodeData(item) { }) // Extract psc:chapters if duration is set - let episodeDuration = !isNaN(episode.duration) ? timestampToSeconds(episode.duration) : null - if (item['psc:chapters']?.[0]?.['psc:chapter']?.length && episodeDuration) { + episode.durationSeconds = episode.duration ? timestampToSeconds(episode.duration) : null + + if (item['psc:chapters']?.[0]?.['psc:chapter']?.length && episode.durationSeconds) { // Example chapter: // {"id":0,"start":0,"end":43.004286,"title":"chapter 1"} @@ -244,7 +246,7 @@ function extractEpisodeData(item) { } else { episode.chapters = cleanedChapters.map((chapter, index) => { const nextChapter = cleanedChapters[index + 1] - const end = nextChapter ? nextChapter.start : episodeDuration + const end = nextChapter ? nextChapter.start : episode.durationSeconds return { id: chapter.id, title: chapter.title, @@ -273,6 +275,7 @@ function cleanEpisodeData(data) { episode: data.episode || '', author: data.author || '', duration: data.duration || '', + durationSeconds: data.durationSeconds || null, explicit: data.explicit || '', publishedAt, enclosure: data.enclosure, From bb4eec935515f5fe945b970ec2cef2b3355a4e2d Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 21 Jun 2025 12:02:44 +0200 Subject: [PATCH 08/86] add explicit --- client/components/controls/LibraryFilterSelect.vue | 5 +++++ server/utils/queries/libraryItemsBookFilters.js | 2 ++ 2 files changed, 7 insertions(+) diff --git a/client/components/controls/LibraryFilterSelect.vue b/client/components/controls/LibraryFilterSelect.vue index f5eec41a2..7bfa1fe84 100644 --- a/client/components/controls/LibraryFilterSelect.vue +++ b/client/components/controls/LibraryFilterSelect.vue @@ -228,6 +228,11 @@ export default { value: 'abridged', sublist: false }, + { + text: this.$strings.LabelExplicit, + value: 'explicit', + sublist: false + }, { text: this.$strings.ButtonIssues, value: 'issues', diff --git a/server/utils/queries/libraryItemsBookFilters.js b/server/utils/queries/libraryItemsBookFilters.js index 7fa5eb41c..ded712cf1 100644 --- a/server/utils/queries/libraryItemsBookFilters.js +++ b/server/utils/queries/libraryItemsBookFilters.js @@ -186,6 +186,8 @@ module.exports = { mediaWhere['$series.id$'] = null } else if (group === 'abridged') { mediaWhere['abridged'] = true + } else if (group === 'explicit') { + mediaWhere['explicit'] = true } else if (['genres', 'tags', 'narrators'].includes(group)) { mediaWhere[group] = Sequelize.where(Sequelize.literal(`(SELECT count(*) FROM json_each(${group}) WHERE json_valid(${group}) AND json_each.value = :filterValue)`), { [Sequelize.Op.gte]: 1 From 5336d0525e7bd46150369f50e08d06e1145a55b3 Mon Sep 17 00:00:00 2001 From: Vito0912 <86927734+Vito0912@users.noreply.github.com> Date: Sat, 21 Jun 2025 12:29:54 +0200 Subject: [PATCH 09/86] add explicit to podcasts --- client/components/controls/LibraryFilterSelect.vue | 5 +++++ server/utils/queries/libraryItemsPodcastFilters.js | 2 ++ 2 files changed, 7 insertions(+) diff --git a/client/components/controls/LibraryFilterSelect.vue b/client/components/controls/LibraryFilterSelect.vue index 7bfa1fe84..32bb9a86b 100644 --- a/client/components/controls/LibraryFilterSelect.vue +++ b/client/components/controls/LibraryFilterSelect.vue @@ -277,6 +277,11 @@ export default { value: 'languages', sublist: true }, + { + text: this.$strings.LabelExplicit, + value: 'explicit', + sublist: false + }, { text: this.$strings.ButtonIssues, value: 'issues', diff --git a/server/utils/queries/libraryItemsPodcastFilters.js b/server/utils/queries/libraryItemsPodcastFilters.js index 33bac28f1..8bb5dc110 100644 --- a/server/utils/queries/libraryItemsPodcastFilters.js +++ b/server/utils/queries/libraryItemsPodcastFilters.js @@ -59,6 +59,8 @@ module.exports = { replacements.filterValue = value } else if (group === 'languages') { mediaWhere['language'] = value + } else if (group === 'explicit') { + mediaWhere['explicit'] = true } return { From af684e6a69bf4c0d58f2f3c019e9788d6e20876c Mon Sep 17 00:00:00 2001 From: advplyrhttp://192.168.1.1:8337 läuft, würdest du http://192.168.1.1:8337/notify eingeben.",
"MessageAsinCheck": "Stellen Sie sicher, dass Sie die ASIN aus der richtigen Audible Region verwenden, nicht Amazon.",
- "MessageAuthenticationOIDCChangesRestart": "Nach dem Speichern muß 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.",
"MessageBackupsDescription": "In einer Sicherung werden Benutzer, Benutzerfortschritte, Details zu den Bibliotheksobjekten, Servereinstellungen und Bilder welche in /metadata/items & /metadata/authors gespeichert sind gespeichert. Sicherungen enthalten keine Dateien welche in den einzelnen Bibliotheksordnern (Medien-Ordnern) gespeichert sind.",
"MessageBackupsLocationEditNote": "Hinweis: Durch das Aktualisieren des Backup-Speicherorts werden vorhandene Sicherungen nicht verschoben oder geändert",
"MessageBackupsLocationNoEditNote": "Hinweis: Der Sicherungsspeicherort wird über eine Umgebungsvariable festgelegt und kann hier nicht geändert werden.",
@@ -918,6 +918,7 @@
"NotificationOnBackupCompletedDescription": "Wird ausgeführt wenn ein Backup erstellt wurde",
"NotificationOnBackupFailedDescription": "Wird ausgeführt wenn ein Backup fehlgeschlagen ist",
"NotificationOnEpisodeDownloadedDescription": "Wird ausgeführt wenn eine Podcast Folge automatisch heruntergeladen wird",
+ "NotificationOnRSSFeedDisabledDescription": "Wird ausgeführt wenn automatische Downloads von Episoden wegen zu vielen fehlgeschlagenen Versuchen deaktiviert sind",
"NotificationOnTestDescription": "Wird ausgeführt wenn das Benachrichtigungssystem getestet wird",
"PlaceholderNewCollection": "Neuer Sammlungsname",
"PlaceholderNewFolderPath": "Neuer Ordnerpfad",
From b9969c78a68d614713e7628c0b914ba90dc5cfdf Mon Sep 17 00:00:00 2001
From: Stefan Ha http://192.168.1.1:8337 dan zou je http://192.168.1.1:8337/notify gebruiken.",
+ "MessageAsinCheck": "Zorg ervoor dat u de ASIN van de juiste Audible-regio gebruikt, niet die van Amazon.",
+ "MessageAuthenticationOIDCChangesRestart": "Start uw server opnieuw op nadat u het opslaan hebt uitgevoerd, om de OIDC-wijzigingen toe te passen.",
"MessageBackupsDescription": "Back-ups omvatten gebruikers, gebruikers' voortgang, bibliotheekonderdeeldetails, serverinstellingen en afbeeldingen bewaard in /metadata/items & /metadata/authors. Back-ups bevatten niet de bestanden bewaard in je bibliotheekmappen.",
"MessageBackupsLocationEditNote": "Let op: het bijwerken van de back-uplocatie zal bestaande back-ups niet verplaatsen of wijzigen",
"MessageBackupsLocationNoEditNote": "Let op: De back-uplocatie wordt ingesteld via een omgevingsvariabele en kan hier niet worden gewijzigd.",
@@ -781,8 +785,8 @@
"MessageImportantNotice": "Belangrijke opmerking!",
"MessageInsertChapterBelow": "Hoofdstuk hieronder invoegen",
"MessageInvalidAsin": "Ongeldige ASIN",
- "MessageItemsSelected": "{0} onderdelen geselecteerd",
- "MessageItemsUpdated": "{0} onderdelen bijgewerkt",
+ "MessageItemsSelected": "{0} items geselecteerd",
+ "MessageItemsUpdated": "{0} items bijgewerkt",
"MessageJoinUsOn": "Doe mee op",
"MessageLoading": "Aan het laden...",
"MessageLoadingFolders": "Mappen aan het laden...",
@@ -849,8 +853,10 @@
"MessageRestoreBackupConfirm": "Weet je zeker dat je wil herstellen met behulp van de back-up gemaakt op",
"MessageRestoreBackupWarning": "Herstellen met een back-up zal de volledige database in /config en de covers in /metadata/items & /metadata/authors overschrijven.http://192.168.1.1:8337, så skal du bruge http://192.168.1.1:8337/notify.",
+ "MessageAsinCheck": "Sikr dig at du bruger ASIN fra den korrekte Audible region, ikke Amazon.",
+ "MessageAuthenticationOIDCChangesRestart": "Genstart sin server efter du har gemt for at bekræfte OIDC ændringer.",
"MessageBackupsDescription": "Backups inkluderer brugere, brugerfremskridt, biblioteksvareoplysninger, serverindstillinger og billeder gemt i /metadata/items og /metadata/authors. Backups inkluderer ikke nogen filer gemt i dine biblioteksmapper.",
"MessageBackupsLocationEditNote": "Note: Opdatering af backup sti vil ikke fjerne eller modificere eksisterende backups",
"MessageBackupsLocationNoEditNote": "Note: Backup sti er sat igennem miljøvariabel og kan ikke ændres her.",
@@ -722,6 +727,7 @@
"MessageChapterErrorStartGteDuration": "Ugyldig starttid skal være mindre end lydbogens varighed",
"MessageChapterErrorStartLtPrev": "Ugyldig starttid skal være større end eller lig med den foregående kapitels starttid",
"MessageChapterStartIsAfter": "Kapitelstarten er efter slutningen af din lydbog",
+ "MessageChaptersNotFound": "Kapitler ikke fundet",
"MessageCheckingCron": "Tjekker cron...",
"MessageConfirmCloseFeed": "Er du sikker på, at du vil lukke dette feed?",
"MessageConfirmDeleteBackup": "Er du sikker på, at du vil slette backup for {0}?",
@@ -778,6 +784,7 @@
"MessageForceReScanDescription": "vil scanne alle filer igen som en frisk scanning. Lydfilens ID3-tags, OPF-filer og tekstfiler scannes som nye.",
"MessageImportantNotice": "Vigtig besked!",
"MessageInsertChapterBelow": "Indsæt kapitel nedenfor",
+ "MessageInvalidAsin": "Ugyldig ASIN",
"MessageItemsSelected": "{0} elementer valgt",
"MessageItemsUpdated": "{0} elementer opdateret",
"MessageJoinUsOn": "Deltag i os på",
@@ -849,6 +856,7 @@
"MessageScheduleRunEveryWeekdayAtTime": "Kør hvert {0} af {1}",
"MessageSearchResultsFor": "Søgeresultater for",
"MessageSelected": "{0} valgt",
+ "MessageSeriesSequenceCannotContainSpaces": "Serie sekvens kan ikke indeholde mellemrum",
"MessageServerCouldNotBeReached": "Serveren kunne ikke nås",
"MessageSetChaptersFromTracksDescription": "Indstil kapitler ved at bruge hver lydfil som et kapitel og kapiteloverskrift som lydfilnavn",
"MessageShareExpirationWillBe": "Udløb vil være {0}",
@@ -956,6 +964,7 @@
"ToastBackupRestoreFailed": "Mislykkedes gendannelse af sikkerhedskopi",
"ToastBackupUploadFailed": "Mislykkedes upload af sikkerhedskopi",
"ToastBackupUploadSuccess": "Sikkerhedskopi uploadet",
+ "ToastBatchApplyDetailsToItemsSuccess": "Detaljer bekræftet på element",
"ToastBatchDeleteFailed": "Batch slet fejlede",
"ToastBatchDeleteSuccess": "Batch slet succes",
"ToastBatchQuickMatchFailed": "Batch Hurtig Match fejlede!",
From d102065d025dda59f8d515ba53f9fe8114b98891 Mon Sep 17 00:00:00 2001
From: Eigen_art /metadata/cache. /metadata/cache/items. /metadata/cache. /metadata/cache/items./metadata/logs як JSON-файли. Журнали збоїв зберігаються у /metadata/logs/crash_logs.txt.",
"MessageM4BFailed": "Помилка M4B!",
"MessageM4BFinished": "M4B створено!",
- "MessageMapChapterTitles": "Встановіть назви глав вашої аудіокниги без визначення налаштувань тривалості",
+ "MessageMapChapterTitles": "Встановіть назви глав вашої аудіокниги без зміни часових міток",
"MessageMarkAllEpisodesFinished": "Позначити всі епізоди завершеними",
"MessageMarkAllEpisodesNotFinished": "Позначити всі епізоди незавершеними",
- "MessageMarkAsFinished": "Позначити завершеним",
- "MessageMarkAsNotFinished": "Позначити незавершеним",
- "MessageMatchBooksDescription": "Спробує віднайти книгу у вказаному джерелі пошуку та встановити подробиці та обкладинку, яких бракує. Не перезаписує подробиці.",
+ "MessageMarkAsFinished": "Позначити як завершене",
+ "MessageMarkAsNotFinished": "Позначити як незавершене",
+ "MessageMatchBooksDescription": "Спробує знайти книги у бібліотеці у вибраному джерелі пошуку та заповнити порожні подробиці й обкладинку. Не перезаписує подробиці.",
"MessageNoAudioTracks": "Аудіодоріжки відсутні",
"MessageNoAuthors": "Автори відсутні",
"MessageNoBackups": "Резервні копії відсутні",
@@ -808,8 +808,8 @@
"MessageNoCoversFound": "Обкладинок не знайдено",
"MessageNoDescription": "Без опису",
"MessageNoDevices": "Немає пристроїв",
- "MessageNoDownloadsInProgress": "Немає активних завантажень",
- "MessageNoDownloadsQueued": "Немає завантажень у черзі",
+ "MessageNoDownloadsInProgress": "Немає активних скачувань",
+ "MessageNoDownloadsQueued": "Немає скачувань у черзі",
"MessageNoEpisodeMatchesFound": "Відповідних епізодів не знайдено",
"MessageNoEpisodes": "Епізоди відсутні",
"MessageNoFoldersAvailable": "Немає доступних тек",
@@ -818,21 +818,21 @@
"MessageNoItems": "Елементи відсутні",
"MessageNoItemsFound": "Елементів не знайдено",
"MessageNoListeningSessions": "Сеанси прослуховування відсутні",
- "MessageNoLogs": "Немає журнали",
+ "MessageNoLogs": "Немає журналів",
"MessageNoMediaProgress": "Прогрес відсутній",
"MessageNoNotifications": "Сповіщення відсутні",
- "MessageNoPodcastFeed": "Невірний подкаст: Немає каналу",
+ "MessageNoPodcastFeed": "Некоректний подкаст: немає каналу",
"MessageNoPodcastsFound": "Подкастів не знайдено",
"MessageNoResults": "Немає результатів",
"MessageNoSearchResultsFor": "Немає результатів пошуку для \"{0}\"",
- "MessageNoSeries": "Без серії",
- "MessageNoTags": "Без міток",
+ "MessageNoSeries": "Немає серій",
+ "MessageNoTags": "Немає міток",
"MessageNoTasksRunning": "Немає активних завдань",
- "MessageNoUpdatesWereNecessary": "Оновлень не потрібно",
+ "MessageNoUpdatesWereNecessary": "Оновлення не потрібні",
"MessageNoUserPlaylists": "У вас немає списків відтворення",
- "MessageNoUserPlaylistsHelp": "Списки відтворення приватні. Лише користувач, який їх створює, може бачити їх.",
+ "MessageNoUserPlaylistsHelp": "Списки відтворення приватні. Лише користувач, який їх створив, може їх бачити.",
"MessageNotYetImplemented": "Ще не реалізовано",
- "MessageOpmlPreviewNote": "Примітка: це попередній перегляд OPML-файлу. Актуальна назва подкасту буде завантажена з RSS-каналу.",
+ "MessageOpmlPreviewNote": "Примітка: це попередній перегляд OPML-файлу. Актуальна назва подкасту буде взята з RSS-каналу.",
"MessageOr": "або",
"MessagePauseChapter": "Призупинити відтворення глави",
"MessagePlayChapter": "Слухати початок глави",
@@ -841,7 +841,7 @@
"MessagePodcastHasNoRSSFeedForMatching": "Подкаст не має RSS-каналу для пошуку",
"MessagePodcastSearchField": "Введіть пошуковий запит або URL RSS-стрічки",
"MessageQuickEmbedInProgress": "Швидке вбудовування в процесі",
- "MessageQuickEmbedQueue": "В черзі на швидке вбудовування ({0} в черзі)",
+ "MessageQuickEmbedQueue": "У черзі на швидке вбудовування ({0} в черзі)",
"MessageQuickMatchAllEpisodes": "Швидке співставлення всіх епізодів",
"MessageQuickMatchDescription": "Заповнити відсутні подробиці та обкладинку першим результатом пошуку '{0}'. Не перезаписує подробиці, якщо не увімкнено параметр \"Надавати перевагу віднайденим метаданим\".",
"MessageRemoveChapter": "Видалити главу",
@@ -849,9 +849,9 @@
"MessageRemoveFromPlayerQueue": "Вилучити з черги відтворення",
"MessageRemoveUserWarning": "Ви дійсно бажаєте назавжди видалити користувача \"{0}\"?",
"MessageReportBugsAndContribute": "Повідомляйте про помилки, пропонуйте функції та долучайтеся на",
- "MessageResetChaptersConfirm": "Ви дійсно бажаєте скинути глави та скасувати внесені зміни?",
- "MessageRestoreBackupConfirm": "Ви дійсно бажаєте відновити резервну копію від",
- "MessageRestoreBackupWarning": "Відновлення резервної копії перезапише всю базу даних, розташовану в /config, і зображення обкладинок в /metadata/items та /metadata/authors.{{ title }}
+{{ title }}
+| {{ $strings.LabelName }} | +{{ $strings.LabelExpiresAt }} | +{{ $strings.LabelLastUsed }} | +{{ $strings.LabelCreatedAt }} | ++ |
|---|---|---|---|---|
|
+
+
+ {{ apiKey.name }} + |
+ {{ apiKey.expiresAt ? $formatJsDatetime(new Date(apiKey.expiresAt), dateFormat, timeFormat) : $strings.LabelExpiresNever }} | +
+ |
+
+ |
+
+
+
+
+
+
+
+
+
+ |
+
{{ $strings.LabelNoApiKeys }}
+{{ $strings.LabelEnable }}
-{{ $strings.LabelExpired }}
{{ $strings.HeaderPermissions }}
-{{ $strings.LabelPermissionsDownload }}
-{{ $strings.LabelPermissionsUpdate }}
-{{ $strings.LabelPermissionsDelete }}
-{{ $strings.LabelPermissionsUpload }}
-{{ $strings.LabelPermissionsCreateEreader }}
-{{ $strings.LabelPermissionsAccessExplicitContent }}
-{{ $strings.LabelPermissionsAccessAllLibraries }}
-{{ $strings.LabelPermissionsAccessAllTags }}
-{{ $strings.LabelInvert }}
-{{ $strings.LabelApiKeyUser }}
+{{ $strings.LabelApiKeyUserDescription }}
+| {{ $strings.LabelName }} | +{{ $strings.LabelApiKeyUser }} | {{ $strings.LabelExpiresAt }} | -{{ $strings.LabelLastUsed }} | {{ $strings.LabelCreatedAt }} | {{ apiKey.expiresAt ? $formatJsDatetime(new Date(apiKey.expiresAt), dateFormat, timeFormat) : $strings.LabelExpiresNever }} |
- Error + |
+
+ {{ getExpiresAtText(apiKey) }} +{{ $strings.LabelExpiresNever }} |
-
@@ -21,6 +21,7 @@ export default {
type: String,
default: 'text'
},
+ min: [String, Number],
readonly: Boolean,
disabled: Boolean,
inputClass: String,
diff --git a/client/pages/config/api-keys/index.vue b/client/pages/config/api-keys/index.vue
index 99ae9c52b..edc4d59f0 100644
--- a/client/pages/config/api-keys/index.vue
+++ b/client/pages/config/api-keys/index.vue
@@ -14,12 +14,12 @@
- {{ label }} +{{ label }} {{ $getString('MessageConfirmRemoveEpisodes', [episodes.length]) }} -Note: This does not delete the audio file unless toggling "Hard delete file" +{{ $strings.MessageConfirmRemoveEpisodeNote }}
- | {{ narrator.name }} +{{ error }} +
+
+
+
+ Authentication has been improved for security. All users will be required to re-login. + More info + |
|---|