Merge master

This commit is contained in:
advplyr 2023-11-26 13:54:06 -06:00
commit 36e00e8d6a
29 changed files with 614 additions and 39 deletions

View File

@ -338,9 +338,15 @@ export default {
libraryItemsAdded(libraryItems) {
console.log('libraryItems added', libraryItems)
const isThisLibrary = !libraryItems.some((li) => li.libraryId !== this.currentLibraryId)
if (!this.search && isThisLibrary) {
this.fetchCategories()
const recentlyAddedShelf = this.shelves.find((shelf) => shelf.id === 'recently-added')
if (!recentlyAddedShelf) return
// Add new library item to the recently added shelf
for (const libraryItem of libraryItems) {
if (libraryItem.libraryId === this.currentLibraryId && !recentlyAddedShelf.entities.some((ent) => ent.id === libraryItem.id)) {
// Add to front of array
recentlyAddedShelf.entities.unshift(libraryItem)
}
}
},
libraryItemsUpdated(items) {

View File

@ -1,16 +1,16 @@
<template>
<div>
<div id="authentication-settings">
<app-settings-content :header-text="$strings.HeaderAuthentication">
<div class="w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25">
<div class="flex items-center">
<ui-checkbox v-model="enableLocalAuth" checkbox-bg="bg" />
<p class="text-lg pl-4">Password Authentication</p>
<p class="text-lg pl-4">{{ $strings.HeaderPasswordAuthentication }}</p>
</div>
</div>
<div class="w-full border border-white/10 rounded-xl p-4 my-4 bg-primary/25">
<div class="flex items-center">
<ui-checkbox v-model="enableOpenIDAuth" checkbox-bg="bg" />
<p class="text-lg pl-4">OpenID Connect Authentication</p>
<p class="text-lg pl-4">{{ $strings.HeaderOpenIDConnectAuthentication }}</p>
</div>
<transition name="slide">
@ -41,25 +41,25 @@
<ui-text-input-with-label ref="openidClientSecret" v-model="newAuthSettings.authOpenIDClientSecret" :disabled="savingSettings" :label="'Client Secret'" class="mb-2" />
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="'Button Text'" class="mb-2" />
<ui-text-input-with-label ref="buttonTextInput" v-model="newAuthSettings.authOpenIDButtonText" :disabled="savingSettings" :label="$strings.LabelButtonText" class="mb-2" />
<div class="flex items-center pt-1 mb-2">
<div class="w-44">
<ui-dropdown v-model="newAuthSettings.authOpenIDMatchExistingBy" small :items="matchingExistingOptions" label="Match existing users by" :disabled="savingSettings" />
<ui-dropdown v-model="newAuthSettings.authOpenIDMatchExistingBy" small :items="matchingExistingOptions" :label="$strings.LabelMatchExistingUsersBy" :disabled="savingSettings" />
</div>
<p class="pl-4 text-sm text-gray-300 mt-5">Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider</p>
<p class="pl-4 text-sm text-gray-300 mt-5">{{ $strings.LabelMatchExistingUsersByDescription }}</p>
</div>
<div class="flex items-center py-4 px-1">
<ui-toggle-switch labeledBy="auto-redirect-toggle" v-model="newAuthSettings.authOpenIDAutoLaunch" :disabled="savingSettings" />
<p id="auto-redirect-toggle" class="pl-4">Auto Launch</p>
<p class="pl-4 text-sm text-gray-300">Redirect to the auth provider automatically when navigating to the login page</p>
<p id="auto-redirect-toggle" class="pl-4 whitespace-nowrap">{{ $strings.LabelAutoLaunch }}</p>
<p class="pl-4 text-sm text-gray-300" v-html="$strings.LabelAutoLaunchDescription" />
</div>
<div class="flex items-center py-4 px-1">
<ui-toggle-switch labeledBy="auto-register-toggle" v-model="newAuthSettings.authOpenIDAutoRegister" :disabled="savingSettings" />
<p id="auto-register-toggle" class="pl-4">Auto Register</p>
<p class="pl-4 text-sm text-gray-300">Automatically create new users after logging in</p>
<p id="auto-register-toggle" class="pl-4 whitespace-nowrap">{{ $strings.LabelAutoRegister }}</p>
<p class="pl-4 text-sm text-gray-300">{{ $strings.LabelAutoRegisterDescription }}</p>
</div>
</div>
</transition>
@ -227,3 +227,13 @@ export default {
}
</script>
<style>
#authentication-settings code {
font-size: 0.8rem;
border-radius: 6px;
background-color: rgb(82, 82, 82);
color: white;
padding: 2px 4px;
white-space: nowrap;
}
</style>

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nový účet",
"HeaderNewLibrary": "Nová knihovna",
"HeaderNotifications": "Oznámení",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Otevřít RSS kanál",
"HeaderOtherFiles": "Ostatní soubory",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Oprávnění",
"HeaderPlayerQueue": "Fronta přehrávače",
"HeaderPlaylist": "Seznam skladeb",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Autor (příjmení a jméno)",
"LabelAuthors": "Autoři",
"LabelAutoDownloadEpisodes": "Automaticky stahovat epizody",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Zpět k uživateli",
"LabelBackupLocation": "Umístění zálohy",
"LabelBackupsEnableAutomaticBackups": "Povolit automatické zálohování",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Najednou bude odstraněna pouze 1 záloha, takže pokud již máte více záloh, měli byste je odstranit ručně.",
"LabelBitrate": "Datový tok",
"LabelBooks": "Knihy",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Změnit heslo",
"LabelChannels": "Kanály",
"LabelChapters": "Kapitoly",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Varovat",
"LabelLookForNewEpisodesAfterDate": "Hledat nové epizody po tomto datu",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Přehrávač médií",
"LabelMediaType": "Typ média",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Ny Konto",
"HeaderNewLibrary": "Nyt Bibliotek",
"HeaderNotifications": "Meddelelser",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Åbn RSS Feed",
"HeaderOtherFiles": "Andre Filer",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Tilladelser",
"HeaderPlayerQueue": "Afspilningskø",
"HeaderPlaylist": "Afspilningsliste",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Forfatter (Efternavn, Fornavn)",
"LabelAuthors": "Forfattere",
"LabelAutoDownloadEpisodes": "Auto Download Episoder",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Tilbage til Bruger",
"LabelBackupLocation": "Backup Placering",
"LabelBackupsEnableAutomaticBackups": "Aktivér automatisk sikkerhedskopiering",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Kun 1 sikkerhedskopi fjernes ad gangen, så hvis du allerede har flere sikkerhedskopier end dette, skal du fjerne dem manuelt.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Bøger",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Ændre Adgangskode",
"LabelChannels": "Kanaler",
"LabelChapters": "Kapitler",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Advarsel",
"LabelLookForNewEpisodesAfterDate": "Søg efter nye episoder efter denne dato",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Medieafspiller",
"LabelMediaType": "Medietype",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -92,7 +92,7 @@
"HeaderAppriseNotificationSettings": "Apprise Benachrichtigungseinstellungen",
"HeaderAudiobookTools": "Hörbuch-Dateiverwaltungstools",
"HeaderAudioTracks": "Audiodateien",
"HeaderAuthentication": "Authentication",
"HeaderAuthentication": "Authentifizierung",
"HeaderBackups": "Sicherungen",
"HeaderChangePassword": "Passwort ändern",
"HeaderChapters": "Kapitel",
@ -132,8 +132,10 @@
"HeaderNewAccount": "Neues Konto",
"HeaderNewLibrary": "Neue Bibliothek",
"HeaderNotifications": "Benachrichtigungen",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentifizierung",
"HeaderOpenRSSFeed": "RSS-Feed öffnen",
"HeaderOtherFiles": "Sonstige Dateien",
"HeaderPasswordAuthentication": "Password Authentifizierung",
"HeaderPermissions": "Berechtigungen",
"HeaderPlayerQueue": "Spieler Warteschlange",
"HeaderPlaylist": "Wiedergabeliste",
@ -182,11 +184,11 @@
"LabelAddToCollectionBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Sammlung hinzu",
"LabelAddToPlaylist": "Zur Wiedergabeliste hinzufügen",
"LabelAddToPlaylistBatch": "Füge {0} Hörbüch(er)/Podcast(s) der Wiedergabeliste hinzu",
"LabelAdminUsersOnly": "Admin users only",
"LabelAdminUsersOnly": "Nur Admin Benutzer",
"LabelAll": "Alle",
"LabelAllUsers": "Alle Benutzer",
"LabelAllUsersExcludingGuests": "All users excluding guests",
"LabelAllUsersIncludingGuests": "All users including guests",
"LabelAllUsersExcludingGuests": "Alle Benutzer außer Gästen",
"LabelAllUsersIncludingGuests": "All Benutzer und Gäste",
"LabelAlreadyInYourLibrary": "In der Bibliothek vorhanden",
"LabelAppend": "Anhängen",
"LabelAuthor": "Autor",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Autor (Nachname, Vorname)",
"LabelAuthors": "Autoren",
"LabelAutoDownloadEpisodes": "Episoden automatisch herunterladen",
"LabelAutoLaunch": "Automatischer Start",
"LabelAutoLaunchDescription": "Automatische Weiterleitung zum Authentifizierungsanbieter beim Navigieren zur Anmeldeseite (manueller Überschreibungspfad <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Automatische Registrierung",
"LabelAutoRegisterDescription": "Automatische neue Neutzer anlegen nach dem Einloggen",
"LabelBackToUser": "Zurück zum Benutzer",
"LabelBackupLocation": "Backup-Ort",
"LabelBackupsEnableAutomaticBackups": "Automatische Sicherung aktivieren",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Es wird immer nur 1 Sicherung auf einmal entfernt. Wenn Sie bereits mehrere Sicherungen als die definierte max. Anzahl haben, sollten Sie diese manuell entfernen.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Bücher",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Passwort ändern",
"LabelChannels": "Kanäle",
"LabelChapters": "Kapitel",
@ -233,7 +240,7 @@
"LabelDeselectAll": "Alles abwählen",
"LabelDevice": "Gerät",
"LabelDeviceInfo": "Geräteinformationen",
"LabelDeviceIsAvailableTo": "Device is available to...",
"LabelDeviceIsAvailableTo": "Dem Geärt ist es möglich zu ...",
"LabelDirectory": "Verzeichnis",
"LabelDiscFromFilename": "CD aus dem Dateinamen",
"LabelDiscFromMetadata": "CD aus den Metadaten",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warnungen",
"LabelLookForNewEpisodesAfterDate": "Suchen nach neuen Episoden nach diesem Datum",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Zuordnen existierender Benutzer mit",
"LabelMatchExistingUsersByDescription": "Wird zum Verbinden vorhandener Benutzer verwendet. Sobald die Verbindung hergestellt ist, wird den Benutzern eine eindeutige ID von Ihrem SSO-Anbieter zugeordnet",
"LabelMediaPlayer": "Mediaplayer",
"LabelMediaType": "Medientyp",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",
@ -401,7 +410,7 @@
"LabelSeason": "Staffel",
"LabelSelectAllEpisodes": "Alle Episoden auswählen",
"LabelSelectEpisodesShowing": "{0} ausgewählte Episoden werden angezeigt",
"LabelSelectUsers": "Select users",
"LabelSelectUsers": "Benutzer auswählen",
"LabelSendEbookToDevice": "E-Book senden an...",
"LabelSequence": "Reihenfolge",
"LabelSeries": "Serien",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password",
"LabelChannels": "Channels",
"LabelChapters": "Chapters",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nueva Cuenta",
"HeaderNewLibrary": "Nueva Biblioteca",
"HeaderNotifications": "Notificaciones",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Abrir fuente RSS",
"HeaderOtherFiles": "Otros Archivos",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permisos",
"HeaderPlayerQueue": "Fila del Reproductor",
"HeaderPlaylist": "Lista de Reproducción",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Autor (Apellido, Nombre)",
"LabelAuthors": "Autores",
"LabelAutoDownloadEpisodes": "Descargar Episodios Automáticamente",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Regresar a Usuario",
"LabelBackupLocation": "Ubicación del Respaldo",
"LabelBackupsEnableAutomaticBackups": "Habilitar Respaldo Automático",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Solamente 1 respaldo se removerá a la vez. Si tiene mas respaldos guardados, debe removerlos manualmente.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Libros",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Cambiar Contraseña",
"LabelChannels": "Canales",
"LabelChapters": "Capítulos",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Advertencia",
"LabelLookForNewEpisodesAfterDate": "Buscar Nuevos Episodios a partir de esta Fecha",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Reproductor de Medios",
"LabelMediaType": "Tipo de Multimedia",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nouveau compte",
"HeaderNewLibrary": "Nouvelle bibliothèque",
"HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Ouvrir Flux RSS",
"HeaderOtherFiles": "Autres fichiers",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Liste découte",
"HeaderPlaylist": "Liste de lecture",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Auteur (Nom, Prénom)",
"LabelAuthors": "Auteurs",
"LabelAutoDownloadEpisodes": "Téléchargement automatique dépisode",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Revenir à lUtilisateur",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Activer les sauvegardes automatiques",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Une seule sauvegarde sera effacée à la fois. Si vous avez plus de sauvegardes à effacer, vous devrez le faire manuellement.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Livres",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Modifier le mot de passe",
"LabelChannels": "Canaux",
"LabelChapters": "Chapitres",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Chercher de nouveaux épisode après cette date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Lecteur multimédia",
"LabelMediaType": "Type de média",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password",
"LabelChannels": "Channels",
"LabelChapters": "Chapters",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "New Account",
"HeaderNewLibrary": "New Library",
"HeaderNotifications": "Notifications",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS Feed",
"HeaderOtherFiles": "Other Files",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permissions",
"HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Authors",
"LabelAutoDownloadEpisodes": "Auto Download Episodes",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Back to User",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Enable automatic backups",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Only 1 backup will be removed at a time so if you already have more backups than this you should manually remove them.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Books",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Change Password",
"LabelChannels": "Channels",
"LabelChapters": "Chapters",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Look for new episodes after this date",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Novi korisnički račun",
"HeaderNewLibrary": "Nova biblioteka",
"HeaderNotifications": "Obavijesti",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Otvori RSS Feed",
"HeaderOtherFiles": "Druge datoteke",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Dozvole",
"HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Author (Last, First)",
"LabelAuthors": "Autori",
"LabelAutoDownloadEpisodes": "Automatski preuzmi epizode",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Nazad k korisniku",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Uključi automatski backup",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Samo 1 backup će biti odjednom obrisan. Ako koristite više njih, morati ćete ih ručno ukloniti.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Knjige",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Promijeni lozinku",
"LabelChannels": "Channels",
"LabelChapters": "Chapters",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Traži nove epizode nakon ovog datuma",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player",
"LabelMediaType": "Media Type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nuovo Account",
"HeaderNewLibrary": "Nuova Libreria",
"HeaderNotifications": "Notifiche",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Apri RSS Feed",
"HeaderOtherFiles": "Altri File",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Permessi",
"HeaderPlayerQueue": "Coda Riproduzione",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Autori (Per Cognome)",
"LabelAuthors": "Autori",
"LabelAutoDownloadEpisodes": "Auto Download Episodi",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Torna a Utenti",
"LabelBackupLocation": "Percorso del Backup",
"LabelBackupsEnableAutomaticBackups": "Abilita backup Automatico",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Verrà rimosso solo 1 backup alla volta, quindi se hai più backup, dovrai rimuoverli manualmente.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Libri",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Cambia Password",
"LabelChannels": "Canali",
"LabelChapters": "Capitoli",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Allarme",
"LabelLookForNewEpisodesAfterDate": "Cerca nuovi episodi dopo questa data",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Media Player",
"LabelMediaType": "Tipo Media",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nauja paskyra",
"HeaderNewLibrary": "Nauja biblioteka",
"HeaderNotifications": "Pranešimai",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Atidaryti RSS srautą",
"HeaderOtherFiles": "Kiti failai",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Leidimai",
"HeaderPlayerQueue": "Grotuvo eilė",
"HeaderPlaylist": "Grojaraštis",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Autorius (Pavardė, Vardas)",
"LabelAuthors": "Autoriai",
"LabelAutoDownloadEpisodes": "Automatiškai atsisiųsti epizodus",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Grįžti į naudotoją",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Įjungti automatinį atsarginių kopijų kūrimą",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Tik viena atsarginė kopija bus pašalinta vienu metu, todėl jei jau turite daugiau atsarginių kopijų nei nurodyta, turite jas pašalinti rankiniu būdu.",
"LabelBitrate": "Bitų sparta",
"LabelBooks": "Knygos",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Pakeisti slaptažodį",
"LabelChannels": "Kanalai",
"LabelChapters": "Skyriai",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Ieškoti naujų epizodų po šios datos",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Grotuvas",
"LabelMediaType": "Medijos tipas",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nieuwe account",
"HeaderNewLibrary": "Nieuwe bibliotheek",
"HeaderNotifications": "Notificaties",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Open RSS-feed",
"HeaderOtherFiles": "Andere bestanden",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Toestemmingen",
"HeaderPlayerQueue": "Afspeelwachtrij",
"HeaderPlaylist": "Afspeellijst",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Auteur (Achternaam, Voornaam)",
"LabelAuthors": "Auteurs",
"LabelAutoDownloadEpisodes": "Afleveringen automatisch downloaden",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Terug naar gebruiker",
"LabelBackupLocation": "Back-up locatie",
"LabelBackupsEnableAutomaticBackups": "Automatische back-ups inschakelen",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Er wordt slechts 1 back-up per keer verwijderd, dus als je reeds meer back-ups dan dit hebt moet je ze handmatig verwijderen.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Boeken",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Wachtwoord wijzigen",
"LabelChannels": "Kanalen",
"LabelChapters": "Hoofdstukken",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Waarschuwing",
"LabelLookForNewEpisodesAfterDate": "Zoek naar nieuwe afleveringen na deze datum",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Mediaspeler",
"LabelMediaType": "Mediatype",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Ny konto",
"HeaderNewLibrary": "Ny bibliotek",
"HeaderNotifications": "Notifikasjoner",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Åpne RSS Feed",
"HeaderOtherFiles": "Andre filer",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Rettigheter",
"HeaderPlayerQueue": "Spiller kø",
"HeaderPlaylist": "Spilleliste",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Forfatter (Etternavn Fornavn)",
"LabelAuthors": "Forfattere",
"LabelAutoDownloadEpisodes": "Last ned episoder automatisk",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Tilbake til bruker",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Aktiver automatisk sikkerhetskopi",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Kun 1 sikkerhetskopi vil bli fjernet om gangen, hvis du allerede har flere sikkerhetskopier enn dette bør du fjerne de manuelt.",
"LabelBitrate": "Bithastighet",
"LabelBooks": "Bøker",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Endre passord",
"LabelChannels": "Kanaler",
"LabelChapters": "Kapitler",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Se etter nye episoder etter denne datoen",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Mediespiller",
"LabelMediaType": "Medie type",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nowe konto",
"HeaderNewLibrary": "Nowa biblioteka",
"HeaderNotifications": "Powiadomienia",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Utwórz kanał RSS",
"HeaderOtherFiles": "Inne pliki",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Uprawnienia",
"HeaderPlayerQueue": "Player Queue",
"HeaderPlaylist": "Playlist",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Author (Malejąco)",
"LabelAuthors": "Autorzy",
"LabelAutoDownloadEpisodes": "Automatyczne pobieranie odcinków",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Powrót",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Włącz automatyczne kopie zapasowe",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Tylko 1 kopia zapasowa zostanie usunięta, więc jeśli masz już więcej kopii zapasowych, powinieneś je ręcznie usunąć.",
"LabelBitrate": "Bitrate",
"LabelBooks": "Książki",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Zmień hasło",
"LabelChannels": "Channels",
"LabelChapters": "Chapters",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Ostrzeżenie",
"LabelLookForNewEpisodesAfterDate": "Szukaj nowych odcinków po dacie",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Odtwarzacz",
"LabelMediaType": "Typ mediów",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Новая учетная запись",
"HeaderNewLibrary": "Новая библиотека",
"HeaderNotifications": "Уведомления",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Открыть RSS-канал",
"HeaderOtherFiles": "Другие файлы",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Разрешения",
"HeaderPlayerQueue": "Очередь воспроизведения",
"HeaderPlaylist": "Плейлист",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Автор (Фамилия, Имя)",
"LabelAuthors": "Авторы",
"LabelAutoDownloadEpisodes": "Скачивать эпизоды автоматически",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Назад к пользователю",
"LabelBackupLocation": "Backup Location",
"LabelBackupsEnableAutomaticBackups": "Включить автоматическое бэкапирование",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "За один раз только 1 бэкап будет удален, так что если у вас будет больше бэкапов, то их нужно удалить вручную.",
"LabelBitrate": "Битрейт",
"LabelBooks": "Книги",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Изменить пароль",
"LabelChannels": "Каналы",
"LabelChapters": "Главы",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Warn",
"LabelLookForNewEpisodesAfterDate": "Искать новые эпизоды после этой даты",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Медиа проигрыватель",
"LabelMediaType": "Тип медиа",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "Nytt konto",
"HeaderNewLibrary": "Nytt bibliotek",
"HeaderNotifications": "Meddelanden",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "Öppna RSS-flöde",
"HeaderOtherFiles": "Andra filer",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "Behörigheter",
"HeaderPlayerQueue": "Spelarkö",
"HeaderPlaylist": "Spellista",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "Författare (Efternamn, Förnamn)",
"LabelAuthors": "Författare",
"LabelAutoDownloadEpisodes": "Automatisk nedladdning av avsnitt",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "Tillbaka till användaren",
"LabelBackupLocation": "Säkerhetskopia Plats",
"LabelBackupsEnableAutomaticBackups": "Aktivera automatiska säkerhetskopior",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "Endast en säkerhetskopia tas bort åt gången, så om du redan har fler säkerhetskopior än detta bör du ta bort dem manuellt.",
"LabelBitrate": "Bitfrekvens",
"LabelBooks": "Böcker",
"LabelButtonText": "Button Text",
"LabelChangePassword": "Ändra lösenord",
"LabelChannels": "Kanaler",
"LabelChapters": "Kapitel",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "Felsökningsnivå: Varning",
"LabelLookForNewEpisodesAfterDate": "Sök efter nya avsnitt efter detta datum",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "Mediaspelare",
"LabelMediaType": "Mediatyp",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

View File

@ -132,8 +132,10 @@
"HeaderNewAccount": "新建帐户",
"HeaderNewLibrary": "新建媒体库",
"HeaderNotifications": "通知",
"HeaderOpenIDConnectAuthentication": "OpenID Connect Authentication",
"HeaderOpenRSSFeed": "打开 RSS 源",
"HeaderOtherFiles": "其他文件",
"HeaderPasswordAuthentication": "Password Authentication",
"HeaderPermissions": "权限",
"HeaderPlayerQueue": "播放队列",
"HeaderPlaylist": "播放列表",
@ -194,6 +196,10 @@
"LabelAuthorLastFirst": "作者 (名, 姓)",
"LabelAuthors": "作者",
"LabelAutoDownloadEpisodes": "自动下载剧集",
"LabelAutoLaunch": "Auto Launch",
"LabelAutoLaunchDescription": "Redirect to the auth provider automatically when navigating to the login page (manual override path <code>/login?autoLaunch=0</code>)",
"LabelAutoRegister": "Auto Register",
"LabelAutoRegisterDescription": "Automatically create new users after logging in",
"LabelBackToUser": "返回到用户",
"LabelBackupLocation": "备份位置",
"LabelBackupsEnableAutomaticBackups": "启用自动备份",
@ -204,6 +210,7 @@
"LabelBackupsNumberToKeepHelp": "一次只能删除一个备份, 因此如果你已经有超过此数量的备份, 则应手动删除它们.",
"LabelBitrate": "比特率",
"LabelBooks": "图书",
"LabelButtonText": "Button Text",
"LabelChangePassword": "修改密码",
"LabelChannels": "声道",
"LabelChapters": "章节",
@ -319,6 +326,8 @@
"LabelLogLevelWarn": "警告",
"LabelLookForNewEpisodesAfterDate": "在此日期后查找新剧集",
"LabelLowestPriority": "Lowest Priority",
"LabelMatchExistingUsersBy": "Match existing users by",
"LabelMatchExistingUsersByDescription": "Used for connecting existing users. Once connected, users will be matched by a unique id from your SSO provider",
"LabelMediaPlayer": "媒体播放器",
"LabelMediaType": "媒体类型",
"LabelMetadataOrderOfPrecedenceDescription": "Higher priority metadata sources will override lower priority metadata sources",

208
package-lock.json generated
View File

@ -15,6 +15,7 @@
"express-session": "^1.17.3",
"graceful-fs": "^4.2.10",
"htmlparser2": "^8.0.1",
"lru-cache": "^10.0.3",
"node-tone": "^1.0.1",
"nodemailer": "^6.9.2",
"openid-client": "^5.6.1",
@ -603,6 +604,17 @@
"node-pre-gyp": "bin/node-pre-gyp"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@mapbox/node-pre-gyp/node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -641,6 +653,18 @@
"semver": "^7.3.5"
}
},
"node_modules/@npmcli/fs/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@npmcli/fs/node_modules/semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
@ -1126,6 +1150,18 @@
"node": ">= 10"
}
},
"node_modules/cacache/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/caching-transform": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
@ -2619,6 +2655,18 @@
"node": ">=8"
}
},
"node_modules/istanbul-lib-report/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/istanbul-lib-report/node_modules/make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
@ -2783,6 +2831,17 @@
"npm": ">=6"
}
},
"node_modules/jsonwebtoken/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/jsonwebtoken/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -2917,14 +2976,11 @@
}
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz",
"integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==",
"engines": {
"node": ">=10"
"node": "14 || >=16.14"
}
},
"node_modules/make-dir": {
@ -2976,6 +3032,18 @@
"node": ">= 10"
}
},
"node_modules/make-fetch-happen/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -3552,6 +3620,18 @@
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/node-gyp/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-gyp/node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -3841,6 +3921,17 @@
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/openid-client/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@ -4386,6 +4477,17 @@
}
}
},
"node_modules/sequelize/node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/sequelize/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -5777,6 +5879,14 @@
"tar": "^6.1.11"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -5805,6 +5915,15 @@
"semver": "^7.3.5"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
},
"semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz",
@ -6192,6 +6311,17 @@
"ssri": "^8.0.1",
"tar": "^6.0.2",
"unique-filename": "^1.1.1"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"caching-transform": {
@ -7291,6 +7421,15 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"requires": {
"yallist": "^4.0.0"
}
},
"make-dir": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
@ -7408,6 +7547,14 @@
"semver": "^7.5.4"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@ -7529,12 +7676,9 @@
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz",
"integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg=="
},
"make-dir": {
"version": "3.1.0",
@ -7573,6 +7717,17 @@
"promise-retry": "^2.0.1",
"socks-proxy-agent": "^6.0.0",
"ssri": "^8.0.0"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"media-typer": {
@ -8000,6 +8155,15 @@
"wide-align": "^1.1.5"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"optional": true,
"requires": {
"yallist": "^4.0.0"
}
},
"nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@ -8220,6 +8384,16 @@
"lru-cache": "^6.0.0",
"object-hash": "^2.2.0",
"oidc-token-hash": "^5.0.3"
},
"dependencies": {
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"p-limit": {
@ -8588,6 +8762,14 @@
"ms": "2.1.2"
}
},
"lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"requires": {
"yallist": "^4.0.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",

View File

@ -42,6 +42,7 @@
"express-session": "^1.17.3",
"graceful-fs": "^4.2.10",
"htmlparser2": "^8.0.1",
"lru-cache": "^10.0.3",
"node-tone": "^1.0.1",
"nodemailer": "^6.9.2",
"openid-client": "^5.6.1",

View File

@ -566,6 +566,69 @@ class Auth {
Source: global.Source
}
}
/**
*
* @param {string} password
* @param {*} user
* @returns {boolean}
*/
comparePassword(password, user) {
if (user.type === 'root' && !password && !user.pash) return true
if (!password || !user.pash) return false
return bcrypt.compare(password, user.pash)
}
/**
* User changes their password from request
*
* @param {import('express').Request} req
* @param {import('express').Response} res
*/
async userChangePassword(req, res) {
let { password, newPassword } = req.body
newPassword = newPassword || ''
const matchingUser = req.user
// Only root can have an empty password
if (matchingUser.type !== 'root' && !newPassword) {
return res.json({
error: 'Invalid new password - Only root can have an empty password'
})
}
// Check password match
const compare = await this.comparePassword(password, matchingUser)
if (!compare) {
return res.json({
error: 'Invalid password'
})
}
let pw = ''
if (newPassword) {
pw = await this.hashPass(newPassword)
if (!pw) {
return res.json({
error: 'Hash failed'
})
}
}
matchingUser.pash = pw
const success = await Database.updateUser(matchingUser)
if (success) {
Logger.info(`[Auth] User "${matchingUser.username}" changed password`)
res.json({
success: true
})
} else {
res.json({
error: 'Unknown error'
})
}
}
}
module.exports = Auth

View File

@ -5,6 +5,7 @@ class Logger {
constructor() {
this.isDev = process.env.NODE_ENV !== 'production'
this.logLevel = !this.isDev ? LogLevel.INFO : LogLevel.TRACE
this.hideDevLogs = process.env.HIDE_DEV_LOGS === undefined ? !this.isDev : process.env.HIDE_DEV_LOGS === '1'
this.socketListeners = []
this.logManager = null
@ -92,7 +93,7 @@ class Logger {
* @param {...any} args
*/
dev(...args) {
if (!this.isDev || process.env.HIDE_DEV_LOGS === '1') return
if (this.hideDevLogs) return
console.log(`[${this.timestamp}] DEV:`, ...args)
}

View File

@ -32,13 +32,13 @@ const PodcastManager = require('./managers/PodcastManager')
const AudioMetadataMangaer = require('./managers/AudioMetadataManager')
const RssFeedManager = require('./managers/RssFeedManager')
const CronManager = require('./managers/CronManager')
const ApiCacheManager = require('./managers/ApiCacheManager')
const LibraryScanner = require('./scanner/LibraryScanner')
//Import the main Passport and Express-Session library
const passport = require('passport')
const expressSession = require('express-session')
class Server {
constructor(SOURCE, PORT, HOST, UID, GID, CONFIG_PATH, METADATA_PATH, ROUTER_BASE_PATH) {
this.Port = PORT
@ -73,6 +73,7 @@ class Server {
this.audioMetadataManager = new AudioMetadataMangaer()
this.rssFeedManager = new RssFeedManager()
this.cronManager = new CronManager(this.podcastManager)
this.apiCacheManager = new ApiCacheManager()
// Routers
this.apiRouter = new ApiRouter(this)
@ -117,6 +118,7 @@ class Server {
const libraries = await Database.libraryModel.getAllOldLibraries()
await this.cronManager.init(libraries)
this.apiCacheManager.init()
if (Database.serverSettings.scannerDisableWatcher) {
Logger.info(`[Server] Watcher is disabled`)
@ -138,11 +140,13 @@ class Server {
* The mobile app ereader is using fetch api in Capacitor that is currently difficult to switch to native requests
* so we have to allow cors for specific origins to the /api/items/:id/ebook endpoint
* @see https://ionicframework.com/docs/troubleshooting/cors
*
* Running in development allows cors to allow testing the mobile apps in the browser
*/
app.use((req, res, next) => {
if (req.path.match(/\/api\/items\/([a-z0-9-]{36})\/ebook(\/[0-9]+)?/)) {
if (Logger.isDev || req.path.match(/\/api\/items\/([a-z0-9-]{36})\/ebook(\/[0-9]+)?/)) {
const allowedOrigins = ['capacitor://localhost', 'http://localhost']
if (allowedOrigins.some(o => o === req.get('origin'))) {
if (Logger.isDev || allowedOrigins.some(o => o === req.get('origin'))) {
res.header('Access-Control-Allow-Origin', req.get('origin'))
res.header("Access-Control-Allow-Methods", 'GET, POST, PATCH, PUT, DELETE, OPTIONS')
res.header('Access-Control-Allow-Headers', '*')

View File

@ -192,9 +192,9 @@ class SocketAuthority {
this.adminEmitter('user_online', client.user.toJSONForPublic(this.Server.playbackSessionManager.sessions))
// Update user lastSeen
// Update user lastSeen without firing sequelize bulk update hooks
user.lastSeen = Date.now()
await Database.updateUser(user)
await Database.userModel.updateFromOld(user, false)
const initialPayload = {
userId: client.user.id,

View File

@ -0,0 +1,54 @@
const { LRUCache } = require('lru-cache')
const Logger = require('../Logger')
const Database = require('../Database')
class ApiCacheManager {
defaultCacheOptions = { max: 1000, maxSize: 10 * 1000 * 1000, sizeCalculation: item => (item.body.length + JSON.stringify(item.headers).length) }
defaultTtlOptions = { ttl: 30 * 60 * 1000 }
constructor(cache = new LRUCache(this.defaultCacheOptions), ttlOptions = this.defaultTtlOptions) {
this.cache = cache
this.ttlOptions = ttlOptions
}
init(database = Database) {
let hooks = ['afterCreate', 'afterUpdate', 'afterDestroy', 'afterBulkCreate', 'afterBulkUpdate', 'afterBulkDestroy']
hooks.forEach(hook => database.sequelize.addHook(hook, (model) => this.clear(model, hook)))
}
clear(model, hook) {
Logger.debug(`[ApiCacheManager] ${model.constructor.name}.${hook}: Clearing cache`)
this.cache.clear()
}
get middleware() {
return (req, res, next) => {
const key = { user: req.user.username, url: req.url }
const stringifiedKey = JSON.stringify(key)
Logger.debug(`[ApiCacheManager] count: ${this.cache.size} size: ${this.cache.calculatedSize}`)
const cached = this.cache.get(stringifiedKey)
if (cached) {
Logger.debug(`[ApiCacheManager] Cache hit: ${stringifiedKey}`)
res.set(cached.headers)
res.status(cached.statusCode)
res.send(cached.body)
return
}
res.originalSend = res.send
res.send = (body) => {
Logger.debug(`[ApiCacheManager] Cache miss: ${stringifiedKey}`)
const cached = { body, headers: res.getHeaders(), statusCode: res.statusCode }
if (key.url.search(/^\/libraries\/.*?\/personalized/) !== -1) {
Logger.debug(`[ApiCacheManager] Caching with ${this.ttlOptions.ttl} ms TTL`)
this.cache.set(stringifiedKey, cached, this.ttlOptions)
} else {
this.cache.set(stringifiedKey, cached)
}
res.originalSend(body)
}
next()
}
}
}
module.exports = ApiCacheManager

View File

@ -99,11 +99,13 @@ class User extends Model {
* Update User from old user model
*
* @param {oldUser} oldUser
* @param {boolean} [hooks=true] Run before / after bulk update hooks?
* @returns {Promise<boolean>}
*/
static updateFromOld(oldUser) {
static updateFromOld(oldUser, hooks = true) {
const user = this.getFromOld(oldUser)
return this.update(user, {
hooks: !!hooks,
where: {
id: user.id
}

View File

@ -48,6 +48,7 @@ class ApiRouter {
this.cronManager = Server.cronManager
this.notificationManager = Server.notificationManager
this.emailManager = Server.emailManager
this.apiCacheManager = Server.apiCacheManager
this.router = express()
this.router.disable('x-powered-by')
@ -58,6 +59,7 @@ class ApiRouter {
//
// Library Routes
//
this.router.get(/^\/libraries/, this.apiCacheManager.middleware)
this.router.post('/libraries', LibraryController.create.bind(this))
this.router.get('/libraries', LibraryController.findAll.bind(this))
this.router.get('/libraries/:id', LibraryController.middleware.bind(this), LibraryController.findOne.bind(this))

View File

@ -0,0 +1,97 @@
// Import dependencies and modules for testing
const { expect } = require('chai')
const sinon = require('sinon')
const ApiCacheManager = require('../../../server/managers/ApiCacheManager')
describe('ApiCacheManager', () => {
let cache
let req
let res
let next
let manager
beforeEach(() => {
cache = { get: sinon.stub(), set: sinon.spy() }
req = { user: { username: 'testUser' }, url: '/test-url' }
res = { send: sinon.spy(), getHeaders: sinon.stub(), statusCode: 200, status: sinon.spy(), set: sinon.spy() }
next = sinon.spy()
})
describe('middleware', () => {
it('should send cached data if available', () => {
// Arrange
const cachedData = { body: 'cached data', headers: { 'content-type': 'application/json' }, statusCode: 200 }
cache.get.returns(cachedData)
const key = JSON.stringify({ user: req.user.username, url: req.url })
manager = new ApiCacheManager(cache)
// Act
manager.middleware(req, res, next)
// Assert
expect(cache.get.calledOnce).to.be.true
expect(cache.get.calledWith(key)).to.be.true
expect(res.set.calledOnce).to.be.true
expect(res.set.calledWith(cachedData.headers)).to.be.true
expect(res.status.calledOnce).to.be.true
expect(res.status.calledWith(cachedData.statusCode)).to.be.true
expect(res.send.calledOnce).to.be.true
expect(res.send.calledWith(cachedData.body)).to.be.true
expect(res.originalSend).to.be.undefined
expect(next.called).to.be.false
expect(cache.set.called).to.be.false
})
it('should cache and send response if data is not cached', () => {
// Arrange
cache.get.returns(null)
const headers = { 'content-type': 'application/json' }
res.getHeaders.returns(headers)
const body = 'response data'
const statusCode = 200
const responseData = { body, headers, statusCode }
const key = JSON.stringify({ user: req.user.username, url: req.url })
manager = new ApiCacheManager(cache)
// Act
manager.middleware(req, res, next)
res.send(body)
// Assert
expect(cache.get.calledOnce).to.be.true
expect(cache.get.calledWith(key)).to.be.true
expect(next.calledOnce).to.be.true
expect(cache.set.calledOnce).to.be.true
expect(cache.set.calledWith(key, responseData)).to.be.true
expect(res.originalSend.calledOnce).to.be.true
expect(res.originalSend.calledWith(body)).to.be.true
})
it('should cache personalized response with 30 minutes TTL', () => {
// Arrange
cache.get.returns(null)
const headers = { 'content-type': 'application/json' }
res.getHeaders.returns(headers)
const body = 'personalized data'
const statusCode = 200
const responseData = { body, headers, statusCode }
req.url = '/libraries/id/personalized'
const key = JSON.stringify({ user: req.user.username, url: req.url })
const ttlOptions = { ttl: 30 * 60 * 1000 }
manager = new ApiCacheManager(cache, ttlOptions)
// Act
manager.middleware(req, res, next)
res.send(body)
// Assert
expect(cache.get.calledOnce).to.be.true
expect(cache.get.calledWith(key)).to.be.true
expect(next.calledOnce).to.be.true
expect(cache.set.calledOnce).to.be.true
expect(cache.set.calledWith(key, responseData, ttlOptions)).to.be.true
expect(res.originalSend.calledOnce).to.be.true
expect(res.originalSend.calledWith(body)).to.be.true
})
})
})