From bb503638123bafb42594456fa440e71b80088fb5 Mon Sep 17 00:00:00 2001 From: bobberb Date: Sun, 17 Feb 2019 00:21:55 +0000 Subject: Translated using Weblate (Hebrew) Currently translated at 97.8% (92 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/he/ --- Emby.Server.Implementations/Localization/Core/he.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json index fff1d1f0e..0ed998c4b 100644 --- a/Emby.Server.Implementations/Localization/Core/he.json +++ b/Emby.Server.Implementations/Localization/Core/he.json @@ -1,8 +1,8 @@ { - "Albums": "Albums", + "Albums": "אלבומים", "AppDeviceValues": "App: {0}, Device: {1}", - "Application": "Application", - "Artists": "Artists", + "Application": "אפליקציה", + "Artists": "אמנים", "AuthenticationSucceededWithUserName": "{0} successfully authenticated", "Books": "ספרים", "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", -- cgit v1.2.3 From 331260cf803f7d4500d2b88eabb78be994425081 Mon Sep 17 00:00:00 2001 From: TheBird956 Date: Tue, 26 Feb 2019 03:38:39 +0000 Subject: Translated using Weblate (French) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/ --- Emby.Server.Implementations/Localization/Core/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 52afb4e49..e434b7605 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -44,7 +44,7 @@ "NameInstallFailed": "{0} échec d'installation", "NameSeasonNumber": "Saison {0}", "NameSeasonUnknown": "Saison Inconnue", - "NewVersionIsAvailable": "Une nouvelle version d'Jellyfin Serveur est disponible au téléchargement.", + "NewVersionIsAvailable": "Une nouvelle version de Jellyfin Serveur est disponible au téléchargement.", "NotificationOptionApplicationUpdateAvailable": "Mise à jour de l'application disponible", "NotificationOptionApplicationUpdateInstalled": "Mise à jour de l'application installée", "NotificationOptionAudioPlayback": "Lecture audio démarrée", @@ -89,7 +89,7 @@ "UserOnlineFromDevice": "{0} s'est connecté depuis {1}", "UserPasswordChangedWithName": "Le mot de passe pour l'utilisateur {0} a été modifié", "UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}", - "UserStartedPlayingItemWithValues": "{0} est entrain de lire {1} sur {2}", + "UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}", "UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}", "ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre librairie", "ValueSpecialEpisodeName": "Spécial - {0}", -- cgit v1.2.3 From c8788d83fbd921fccf80b7f49be83db2c73a210b Mon Sep 17 00:00:00 2001 From: TheBird956 Date: Tue, 26 Feb 2019 03:23:03 +0000 Subject: Translated using Weblate (French (Canada)) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr_CA/ --- .../Localization/Core/fr-CA.json | 170 ++++++++++----------- 1 file changed, 85 insertions(+), 85 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json index 7202be9f5..4b4db39a8 100644 --- a/Emby.Server.Implementations/Localization/Core/fr-CA.json +++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json @@ -1,97 +1,97 @@ { "Albums": "Albums", - "AppDeviceValues": "App: {0}, Device: {1}", + "AppDeviceValues": "Application : {0}, Appareil : {1}", "Application": "Application", - "Artists": "Artists", - "AuthenticationSucceededWithUserName": "{0} successfully authenticated", - "Books": "Books", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", - "Channels": "Channels", - "ChapterNameValue": "Chapter {0}", + "Artists": "Artistes", + "AuthenticationSucceededWithUserName": "{0} s'est authentifié avec succès", + "Books": "Livres", + "CameraImageUploadedFrom": "Une nouvelle image de caméra a été téléchargée depuis {0}", + "Channels": "Chaînes", + "ChapterNameValue": "Chapitre {0}", "Collections": "Collections", - "DeviceOfflineWithName": "{0} has disconnected", - "DeviceOnlineWithName": "{0} is connected", - "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", - "Favorites": "Favorites", - "Folders": "Folders", + "DeviceOfflineWithName": "{0} s'est déconnecté", + "DeviceOnlineWithName": "{0} est connecté", + "FailedLoginAttemptWithUserName": "Échec d'une tentative de connexion de {0}", + "Favorites": "Favoris", + "Folders": "Dossiers", "Genres": "Genres", - "HeaderAlbumArtists": "Album Artists", - "HeaderCameraUploads": "Camera Uploads", + "HeaderAlbumArtists": "Artistes de l'album", + "HeaderCameraUploads": "Photos transférées", "HeaderContinueWatching": "Continuer à regarder", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderLiveTV": "Live TV", + "HeaderFavoriteAlbums": "Albums favoris", + "HeaderFavoriteArtists": "Artistes favoris", + "HeaderFavoriteEpisodes": "Épisodes favoris", + "HeaderFavoriteShows": "Séries favorites", + "HeaderFavoriteSongs": "Chansons favorites", + "HeaderLiveTV": "TV en direct", "HeaderNextUp": "À Suivre", - "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", - "Inherit": "Inherit", - "ItemAddedWithName": "{0} was added to the library", - "ItemRemovedWithName": "{0} was removed from the library", - "LabelIpAddressValue": "Ip address: {0}", - "LabelRunningTimeValue": "Running time: {0}", - "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", - "MessageServerConfigurationUpdated": "Server configuration has been updated", - "MixedContent": "Mixed content", - "Movies": "Movies", - "Music": "Music", - "MusicVideos": "Music videos", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", - "NotificationOptionApplicationUpdateAvailable": "Application update available", - "NotificationOptionApplicationUpdateInstalled": "Application update installed", - "NotificationOptionAudioPlayback": "Audio playback started", - "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", - "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionInstallationFailed": "Installation failure", - "NotificationOptionNewLibraryContent": "New content added", - "NotificationOptionPluginError": "Plugin failure", - "NotificationOptionPluginInstalled": "Plugin installed", - "NotificationOptionPluginUninstalled": "Plugin uninstalled", - "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Server restart required", - "NotificationOptionTaskFailed": "Scheduled task failure", - "NotificationOptionUserLockedOut": "User locked out", - "NotificationOptionVideoPlayback": "Video playback started", - "NotificationOptionVideoPlaybackStopped": "Video playback stopped", + "HeaderRecordingGroups": "Groupes d'enregistrements", + "HomeVideos": "Vidéos personnelles", + "Inherit": "Hériter", + "ItemAddedWithName": "{0} a été ajouté à la médiathèque", + "ItemRemovedWithName": "{0} a été supprimé de la médiathèque", + "LabelIpAddressValue": "Adresse IP : {0}", + "LabelRunningTimeValue": "Durée : {0}", + "Latest": "Derniers", + "MessageApplicationUpdated": "Le serveur Jellyfin a été mis à jour", + "MessageApplicationUpdatedTo": "Le serveur Jellyfin a été mis à jour vers la version {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "La configuration de la section {0} du serveur a été mise à jour", + "MessageServerConfigurationUpdated": "La configuration du serveur a été mise à jour", + "MixedContent": "Contenu mixte", + "Movies": "Films", + "Music": "Musique", + "MusicVideos": "Vidéos musicales", + "NameInstallFailed": "{0} échec d'installation", + "NameSeasonNumber": "Saison {0}", + "NameSeasonUnknown": "Saison Inconnue", + "NewVersionIsAvailable": "Une nouvelle version du serveur Jellyfin est disponible au téléchargement.", + "NotificationOptionApplicationUpdateAvailable": "Mise à jour de l'application disponible", + "NotificationOptionApplicationUpdateInstalled": "Mise à jour de l'application installée", + "NotificationOptionAudioPlayback": "Lecture audio démarrée", + "NotificationOptionAudioPlaybackStopped": "Lecture audio arrêtée", + "NotificationOptionCameraImageUploaded": "L'image de l'appareil photo a été transférée", + "NotificationOptionInstallationFailed": "Échec d'installation", + "NotificationOptionNewLibraryContent": "Nouveau contenu ajouté", + "NotificationOptionPluginError": "Erreur d'extension", + "NotificationOptionPluginInstalled": "Extension installée", + "NotificationOptionPluginUninstalled": "Extension désinstallée", + "NotificationOptionPluginUpdateInstalled": "Mise à jour d'extension installée", + "NotificationOptionServerRestartRequired": "Un redémarrage du serveur est requis", + "NotificationOptionTaskFailed": "Échec de tâche planifiée", + "NotificationOptionUserLockedOut": "Utilisateur verrouillé", + "NotificationOptionVideoPlayback": "Lecture vidéo démarrée", + "NotificationOptionVideoPlaybackStopped": "Lecture vidéo arrêtée", "Photos": "Photos", - "Playlists": "Playlists", - "Plugin": "Plugin", - "PluginInstalledWithName": "{0} was installed", - "PluginUninstalledWithName": "{0} was uninstalled", - "PluginUpdatedWithName": "{0} was updated", - "ProviderValue": "Provider: {0}", - "ScheduledTaskFailedWithName": "{0} failed", - "ScheduledTaskStartedWithName": "{0} started", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", - "Shows": "Series", - "Songs": "Songs", - "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.", + "Playlists": "Listes de lecture", + "Plugin": "Extension", + "PluginInstalledWithName": "{0} a été installé", + "PluginUninstalledWithName": "{0} a été désinstallé", + "PluginUpdatedWithName": "{0} a été mis à jour", + "ProviderValue": "Fournisseur : {0}", + "ScheduledTaskFailedWithName": "{0} a échoué", + "ScheduledTaskStartedWithName": "{0} a commencé", + "ServerNameNeedsToBeRestarted": "{0} doit être redémarré", + "Shows": "Émissions", + "Songs": "Chansons", + "StartupEmbyServerIsLoading": "Le serveur Jellyfin est en cours de chargement. Veuillez réessayer dans quelques instants.", "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", - "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}", - "Sync": "Sync", - "System": "System", - "TvShows": "TV Shows", - "User": "User", - "UserCreatedWithName": "User {0} has been created", - "UserDeletedWithName": "User {0} has been deleted", - "UserDownloadingItemWithValues": "{0} is downloading {1}", - "UserLockedOutWithName": "User {0} has been locked out", - "UserOfflineFromDevice": "{0} has disconnected from {1}", - "UserOnlineFromDevice": "{0} is online from {1}", - "UserPasswordChangedWithName": "Password has been changed for user {0}", - "UserPolicyUpdatedWithName": "User policy has been updated for {0}", - "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}", - "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "SubtitleDownloadFailureFromForItem": "Échec du téléchargement des sous-titres depuis {0} pour {1}", + "SubtitlesDownloadedForItem": "Les sous-titres de {0} ont été téléchargés", + "Sync": "Synchroniser", + "System": "Système", + "TvShows": "Séries Télé", + "User": "Utilisateur", + "UserCreatedWithName": "L'utilisateur {0} a été créé", + "UserDeletedWithName": "L'utilisateur {0} a été supprimé", + "UserDownloadingItemWithValues": "{0} est en train de télécharger {1}", + "UserLockedOutWithName": "L'utilisateur {0} a été verrouillé", + "UserOfflineFromDevice": "{0} s'est déconnecté depuis {1}", + "UserOnlineFromDevice": "{0} s'est connecté depuis {1}", + "UserPasswordChangedWithName": "Le mot de passe pour l'utilisateur {0} a été modifié", + "UserPolicyUpdatedWithName": "La politique de l'utilisateur a été mise à jour pour {0}", + "UserStartedPlayingItemWithValues": "{0} est en train de lire {1} sur {2}", + "UserStoppedPlayingItemWithValues": "{0} vient d'arrêter la lecture de {1} sur {2}", + "ValueHasBeenAddedToLibrary": "{0} a été ajouté à votre médiathèque", "ValueSpecialEpisodeName": "Spécial - {0}", "VersionNumber": "Version {0}" } -- cgit v1.2.3 From 7c13021def4432123917b6cf18c129e19ddff756 Mon Sep 17 00:00:00 2001 From: EffeF Date: Sun, 24 Feb 2019 17:44:06 +0000 Subject: Translated using Weblate (Italian) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/it/ --- Emby.Server.Implementations/Localization/Core/it.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index a5f1e8f94..357883cd3 100644 --- a/Emby.Server.Implementations/Localization/Core/it.json +++ b/Emby.Server.Implementations/Localization/Core/it.json @@ -34,17 +34,17 @@ "LabelRunningTimeValue": "Durata: {0}", "Latest": "Più recenti", "MessageApplicationUpdated": "Il Server Jellyfin è stato aggiornato", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", + "MessageApplicationUpdatedTo": "Jellyfin Server è stato aggiornato a {0}", "MessageNamedServerConfigurationUpdatedWithValue": "La sezione {0} della configurazione server è stata aggiornata", "MessageServerConfigurationUpdated": "La configurazione del server è stata aggiornata", "MixedContent": "Contenuto misto", "Movies": "Film", "Music": "Musica", "MusicVideos": "Video musicali", - "NameInstallFailed": "{0} installation failed", + "NameInstallFailed": "{0} installazione fallita", "NameSeasonNumber": "Stagione {0}", "NameSeasonUnknown": "Stagione sconosciuto", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", + "NewVersionIsAvailable": "Una nuova versione di Jellyfin Server è disponibile per il download.", "NotificationOptionApplicationUpdateAvailable": "Aggiornamento dell'applicazione disponibile", "NotificationOptionApplicationUpdateInstalled": "Aggiornamento dell'applicazione installato", "NotificationOptionAudioPlayback": "La riproduzione audio è iniziata", @@ -70,12 +70,12 @@ "ProviderValue": "Provider: {0}", "ScheduledTaskFailedWithName": "{0} fallito", "ScheduledTaskStartedWithName": "{0} avviati", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", + "ServerNameNeedsToBeRestarted": "{0} deve essere riavviato", "Shows": "Programmi", "Songs": "Canzoni", "StartupEmbyServerIsLoading": "Jellyfin server si sta avviando. Per favore riprova più tardi.", "SubtitleDownloadFailureForItem": "Impossibile scaricare i sottotitoli per {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", + "SubtitleDownloadFailureFromForItem": "Impossibile scaricare i sottotitoli da {0} per {1}", "SubtitlesDownloadedForItem": "Sottotitoli scaricati per {0}", "Sync": "Sincronizza", "System": "Sistema", @@ -91,7 +91,7 @@ "UserPolicyUpdatedWithName": "La politica dell'utente è stata aggiornata per {0}", "UserStartedPlayingItemWithValues": "{0} ha avviato la riproduzione di {1}", "UserStoppedPlayingItemWithValues": "{0} ha interrotto la riproduzione di {1}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "ValueHasBeenAddedToLibrary": "{0} è stato aggiunto alla tua libreria multimediale", "ValueSpecialEpisodeName": "Speciale - {0}", "VersionNumber": "Versione {0}" } -- cgit v1.2.3 From 311caf3fc3e45cc332e922897f963b95cb60f98a Mon Sep 17 00:00:00 2001 From: v1tin Date: Mon, 18 Feb 2019 19:02:01 +0000 Subject: Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt_BR/ --- Emby.Server.Implementations/Localization/Core/pt-BR.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json index aaedf0850..dbc9c4c4b 100644 --- a/Emby.Server.Implementations/Localization/Core/pt-BR.json +++ b/Emby.Server.Implementations/Localization/Core/pt-BR.json @@ -5,7 +5,7 @@ "Artists": "Artistas", "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso", "Books": "Livros", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", + "CameraImageUploadedFrom": "Uma nova imagem da câmera foi submetida de {0}", "Channels": "Canais", "ChapterNameValue": "Capítulo {0}", "Collections": "Coletâneas", @@ -30,21 +30,21 @@ "Inherit": "Herdar", "ItemAddedWithName": "{0} foi adicionado à biblioteca", "ItemRemovedWithName": "{0} foi removido da biblioteca", - "LabelIpAddressValue": "Endereço ip: {0}", + "LabelIpAddressValue": "Endereço IP: {0}", "LabelRunningTimeValue": "Tempo de execução: {0}", "Latest": "Recente", "MessageApplicationUpdated": "O servidor Jellyfin foi atualizado", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", + "MessageApplicationUpdatedTo": "O Servidor Jellyfin foi atualizado para {0}", "MessageNamedServerConfigurationUpdatedWithValue": "A seção {0} da configuração do servidor foi atualizada", "MessageServerConfigurationUpdated": "A configuração do servidor foi atualizada", "MixedContent": "Conteúdo misto", "Movies": "Filmes", "Music": "Música", "MusicVideos": "Vídeos musicais", - "NameInstallFailed": "{0} installation failed", + "NameInstallFailed": "A instalação de {0} falhou", "NameSeasonNumber": "Temporada {0}", "NameSeasonUnknown": "Temporada Desconhecida", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", + "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para download.", "NotificationOptionApplicationUpdateAvailable": "Atualização de aplicativo disponível", "NotificationOptionApplicationUpdateInstalled": "Atualização de aplicativo instalada", "NotificationOptionAudioPlayback": "Reprodução de áudio iniciada", @@ -70,12 +70,12 @@ "ProviderValue": "Provedor: {0}", "ScheduledTaskFailedWithName": "{0} falhou", "ScheduledTaskStartedWithName": "{0} iniciada", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", + "ServerNameNeedsToBeRestarted": "O servidor {0} precisa ser reiniciado", "Shows": "Séries", "Songs": "Músicas", "StartupEmbyServerIsLoading": "O Servidor Jellyfin está carregando. Por favor tente novamente em breve.", "SubtitleDownloadFailureForItem": "Download de legendas falhou para {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", + "SubtitleDownloadFailureFromForItem": "Houve um problema ao baixar as legendas de {0} para {1}", "SubtitlesDownloadedForItem": "Legendas baixadas para {0}", "Sync": "Sincronizar", "System": "Sistema", @@ -91,7 +91,7 @@ "UserPolicyUpdatedWithName": "A política de usuário foi atualizada para {0}", "UserStartedPlayingItemWithValues": "{0} iniciou a reprodução de {1}", "UserStoppedPlayingItemWithValues": "{0} parou de reproduzir {1}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "ValueHasBeenAddedToLibrary": "{0} foi adicionado a sua biblioteca", "ValueSpecialEpisodeName": "Especial - {0}", "VersionNumber": "Versão {0}" } -- cgit v1.2.3 From d0e4e0f6004644b58cd5f64a89f82467759e5876 Mon Sep 17 00:00:00 2001 From: SaddFox Date: Tue, 26 Feb 2019 23:05:46 +0000 Subject: Translated using Weblate (Slovenian) Currently translated at 87.2% (82 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/sl/ --- .../Localization/Core/sl-SI.json | 112 ++++++++++----------- 1 file changed, 56 insertions(+), 56 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index e850257d4..b50ff4706 100644 --- a/Emby.Server.Implementations/Localization/Core/sl-SI.json +++ b/Emby.Server.Implementations/Localization/Core/sl-SI.json @@ -1,62 +1,62 @@ { - "Albums": "Albums", - "AppDeviceValues": "App: {0}, Device: {1}", - "Application": "Application", - "Artists": "Artists", - "AuthenticationSucceededWithUserName": "{0} successfully authenticated", - "Books": "Books", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", - "Channels": "Channels", - "ChapterNameValue": "Chapter {0}", - "Collections": "Collections", + "Albums": "Albumi", + "AppDeviceValues": "Aplikacija: {0}, Naprava: {1}", + "Application": "Aplikacija", + "Artists": "Izvajalci", + "AuthenticationSucceededWithUserName": "{0} preverjanje uspešno", + "Books": "Knjige", + "CameraImageUploadedFrom": "Nova fotografija je bila naložena z {0}", + "Channels": "Kanali", + "ChapterNameValue": "Poglavje {0}", + "Collections": "Zbirke", "DeviceOfflineWithName": "{0} has disconnected", - "DeviceOnlineWithName": "{0} is connected", - "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", - "Favorites": "Favorites", - "Folders": "Folders", - "Genres": "Genres", - "HeaderAlbumArtists": "Album Artists", - "HeaderCameraUploads": "Camera Uploads", - "HeaderContinueWatching": "Continue Watching", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderLiveTV": "Live TV", - "HeaderNextUp": "Next Up", - "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", - "Inherit": "Inherit", - "ItemAddedWithName": "{0} was added to the library", - "ItemRemovedWithName": "{0} was removed from the library", - "LabelIpAddressValue": "Ip address: {0}", - "LabelRunningTimeValue": "Running time: {0}", - "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", + "DeviceOnlineWithName": "{0} je povezan", + "FailedLoginAttemptWithUserName": "Neuspešen poskus prijave z {0}", + "Favorites": "Priljubljeni", + "Folders": "Mape", + "Genres": "Zvrsti", + "HeaderAlbumArtists": "Izvajalci albuma", + "HeaderCameraUploads": "Posnetki kamere", + "HeaderContinueWatching": "Nadaljuj gledanje", + "HeaderFavoriteAlbums": "Priljubljeni albumi", + "HeaderFavoriteArtists": "Priljubljeni izvajalci", + "HeaderFavoriteEpisodes": "Priljubljene epizode", + "HeaderFavoriteShows": "Priljubljene serije", + "HeaderFavoriteSongs": "Priljubljene pesmi", + "HeaderLiveTV": "TV v živo", + "HeaderNextUp": "Sledi", + "HeaderRecordingGroups": "Zbirke posnetkov", + "HomeVideos": "Domači posnetki", + "Inherit": "Podeduj", + "ItemAddedWithName": "{0} je dodan v knjižnico", + "ItemRemovedWithName": "{0} je bil odstranjen iz knjižnice", + "LabelIpAddressValue": "IP naslov: {0}", + "LabelRunningTimeValue": "Čas trajanja: {0}", + "Latest": "Najnovejše", + "MessageApplicationUpdated": "Jellyfin strežnik je bil posodobljen", + "MessageApplicationUpdatedTo": "Jellyfin strežnik je bil posodobljen na {0}", "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", - "MessageServerConfigurationUpdated": "Server configuration has been updated", - "MixedContent": "Mixed content", - "Movies": "Movies", - "Music": "Music", - "MusicVideos": "Music videos", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", - "NotificationOptionApplicationUpdateAvailable": "Application update available", - "NotificationOptionApplicationUpdateInstalled": "Application update installed", - "NotificationOptionAudioPlayback": "Audio playback started", - "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", - "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionInstallationFailed": "Installation failure", - "NotificationOptionNewLibraryContent": "New content added", - "NotificationOptionPluginError": "Plugin failure", - "NotificationOptionPluginInstalled": "Plugin installed", - "NotificationOptionPluginUninstalled": "Plugin uninstalled", - "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Server restart required", + "MessageServerConfigurationUpdated": "Nastavitve strežnika so bile posodobljene", + "MixedContent": "Razne vsebine", + "Movies": "Filmi", + "Music": "Glasba", + "MusicVideos": "Glasbeni posnetki", + "NameInstallFailed": "{0} namestitev neuspešna", + "NameSeasonNumber": "Sezona {0}", + "NameSeasonUnknown": "Season neznana", + "NewVersionIsAvailable": "Nova razničica Jellyfin strežnika je na voljo za prenos.", + "NotificationOptionApplicationUpdateAvailable": "Posodobitev aplikacije je na voljo", + "NotificationOptionApplicationUpdateInstalled": "Posodobitev aplikacije je bila nameščena", + "NotificationOptionAudioPlayback": "Predvajanje zvoka začeto", + "NotificationOptionAudioPlaybackStopped": "Predvajanje zvoka zaustavljeno", + "NotificationOptionCameraImageUploaded": "Posnetek kamere naložen", + "NotificationOptionInstallationFailed": "Napaka pri nameščanju", + "NotificationOptionNewLibraryContent": "Nove vsebine dodane", + "NotificationOptionPluginError": "Napaka dodatka", + "NotificationOptionPluginInstalled": "Dodatek nameščen", + "NotificationOptionPluginUninstalled": "Dodatek odstranjen", + "NotificationOptionPluginUpdateInstalled": "Posodobitev dodatka nameščena", + "NotificationOptionServerRestartRequired": "Potreben je ponovni zagon strežnika", "NotificationOptionTaskFailed": "Scheduled task failure", "NotificationOptionUserLockedOut": "User locked out", "NotificationOptionVideoPlayback": "Video playback started", -- cgit v1.2.3 From 53ed6e5e6efb69572a61cb57a31b600f4ba5c02b Mon Sep 17 00:00:00 2001 From: ElFantasma Date: Fri, 22 Feb 2019 18:49:18 +0000 Subject: Translated using Weblate (Spanish (Argentina)) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/es_AR/ --- .../Localization/Core/es-AR.json | 184 ++++++++++----------- 1 file changed, 92 insertions(+), 92 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json index c01bb0c50..dc73ba6b3 100644 --- a/Emby.Server.Implementations/Localization/Core/es-AR.json +++ b/Emby.Server.Implementations/Localization/Core/es-AR.json @@ -1,97 +1,97 @@ { - "Albums": "Albums", - "AppDeviceValues": "App: {0}, Device: {1}", - "Application": "Application", - "Artists": "Artists", - "AuthenticationSucceededWithUserName": "{0} successfully authenticated", - "Books": "Books", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", - "Channels": "Channels", - "ChapterNameValue": "Chapter {0}", - "Collections": "Collections", - "DeviceOfflineWithName": "{0} has disconnected", - "DeviceOnlineWithName": "{0} is connected", - "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", - "Favorites": "Favorites", - "Folders": "Folders", - "Genres": "Genres", - "HeaderAlbumArtists": "Album Artists", - "HeaderCameraUploads": "Camera Uploads", - "HeaderContinueWatching": "Continue Watching", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderLiveTV": "Live TV", - "HeaderNextUp": "Next Up", - "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", - "Inherit": "Inherit", - "ItemAddedWithName": "{0} was added to the library", - "ItemRemovedWithName": "{0} was removed from the library", - "LabelIpAddressValue": "Ip address: {0}", - "LabelRunningTimeValue": "Running time: {0}", - "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", - "MessageServerConfigurationUpdated": "Server configuration has been updated", - "MixedContent": "Mixed content", - "Movies": "Movies", - "Music": "Music", - "MusicVideos": "Music videos", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", - "NotificationOptionApplicationUpdateAvailable": "Application update available", - "NotificationOptionApplicationUpdateInstalled": "Application update installed", - "NotificationOptionAudioPlayback": "Audio playback started", - "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", - "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionInstallationFailed": "Installation failure", - "NotificationOptionNewLibraryContent": "New content added", - "NotificationOptionPluginError": "Plugin failure", - "NotificationOptionPluginInstalled": "Plugin installed", - "NotificationOptionPluginUninstalled": "Plugin uninstalled", - "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Server restart required", - "NotificationOptionTaskFailed": "Scheduled task failure", - "NotificationOptionUserLockedOut": "User locked out", - "NotificationOptionVideoPlayback": "Video playback started", - "NotificationOptionVideoPlaybackStopped": "Video playback stopped", - "Photos": "Photos", - "Playlists": "Playlists", + "Albums": "Álbumes", + "AppDeviceValues": "Aplicación: {0}, Dispositivo: {1}", + "Application": "Aplicación", + "Artists": "Artistas", + "AuthenticationSucceededWithUserName": "{0} autenticado correctamente", + "Books": "Libros", + "CameraImageUploadedFrom": "Se ha subido una nueva imagen de cámara desde {0}", + "Channels": "Canales", + "ChapterNameValue": "Capítulo {0}", + "Collections": "Colecciones", + "DeviceOfflineWithName": "{0} se ha desconectado", + "DeviceOnlineWithName": "{0} está conectado", + "FailedLoginAttemptWithUserName": "Error al intentar iniciar sesión desde {0}", + "Favorites": "Favoritos", + "Folders": "Carpetas", + "Genres": "Géneros", + "HeaderAlbumArtists": "Artistas de álbumes", + "HeaderCameraUploads": "Subidas de cámara", + "HeaderContinueWatching": "Continuar viendo", + "HeaderFavoriteAlbums": "Álbumes favoritos", + "HeaderFavoriteArtists": "Artistas favoritos", + "HeaderFavoriteEpisodes": "Episodios favoritos", + "HeaderFavoriteShows": "Programas favoritos", + "HeaderFavoriteSongs": "Canciones favoritas", + "HeaderLiveTV": "TV en vivo", + "HeaderNextUp": "Continuar Viendo", + "HeaderRecordingGroups": "Grupos de grabación", + "HomeVideos": "Videos caseros", + "Inherit": "Heredar", + "ItemAddedWithName": "{0} se ha añadido a la biblioteca", + "ItemRemovedWithName": "{0} ha sido eliminado de la biblioteca", + "LabelIpAddressValue": "Dirección IP: {0}", + "LabelRunningTimeValue": "Tiempo de funcionamiento: {0}", + "Latest": "Últimos", + "MessageApplicationUpdated": "El servidor Jellyfin fue actualizado", + "MessageApplicationUpdatedTo": "Se ha actualizado el servidor Jellyfin a la versión {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "Fue actualizada la sección {0} de la configuración del servidor", + "MessageServerConfigurationUpdated": "Fue actualizada la configuración del servidor", + "MixedContent": "Contenido mixto", + "Movies": "Películas", + "Music": "Música", + "MusicVideos": "Videos musicales", + "NameInstallFailed": "{0} error de instalación", + "NameSeasonNumber": "Temporada {0}", + "NameSeasonUnknown": "Temporada desconocida", + "NewVersionIsAvailable": "Disponible una nueva versión de Jellyfin para descargar.", + "NotificationOptionApplicationUpdateAvailable": "Actualización de la aplicación disponible", + "NotificationOptionApplicationUpdateInstalled": "Actualización de la aplicación instalada", + "NotificationOptionAudioPlayback": "Se inició la reproducción de audio", + "NotificationOptionAudioPlaybackStopped": "Se detuvo la reproducción de audio", + "NotificationOptionCameraImageUploaded": "Imagen de la cámara cargada", + "NotificationOptionInstallationFailed": "Error de instalación", + "NotificationOptionNewLibraryContent": "Nuevo contenido añadido", + "NotificationOptionPluginError": "Error en plugin", + "NotificationOptionPluginInstalled": "Plugin instalado", + "NotificationOptionPluginUninstalled": "Plugin desinstalado", + "NotificationOptionPluginUpdateInstalled": "Actualización del complemento instalada", + "NotificationOptionServerRestartRequired": "Se requiere reinicio del servidor", + "NotificationOptionTaskFailed": "Error de tarea programada", + "NotificationOptionUserLockedOut": "Usuario bloqueado", + "NotificationOptionVideoPlayback": "Se inició la reproducción de video", + "NotificationOptionVideoPlaybackStopped": "Reproducción de video detenida", + "Photos": "Fotos", + "Playlists": "Listas de reproducción", "Plugin": "Plugin", - "PluginInstalledWithName": "{0} was installed", - "PluginUninstalledWithName": "{0} was uninstalled", - "PluginUpdatedWithName": "{0} was updated", - "ProviderValue": "Provider: {0}", - "ScheduledTaskFailedWithName": "{0} failed", - "ScheduledTaskStartedWithName": "{0} started", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", + "PluginInstalledWithName": "{0} fue instalado", + "PluginUninstalledWithName": "{0} fue desinstalado", + "PluginUpdatedWithName": "{0} fue actualizado", + "ProviderValue": "Proveedor: {0}", + "ScheduledTaskFailedWithName": "{0} falló", + "ScheduledTaskStartedWithName": "{0} iniciada", + "ServerNameNeedsToBeRestarted": "{0} necesita ser reiniciado", "Shows": "Series", - "Songs": "Songs", - "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.", + "Songs": "Canciones", + "StartupEmbyServerIsLoading": "Jellyfin Server se está cargando. Vuelve a intentarlo en breve.", "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", - "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}", - "Sync": "Sync", - "System": "System", - "TvShows": "TV Shows", - "User": "User", - "UserCreatedWithName": "User {0} has been created", - "UserDeletedWithName": "User {0} has been deleted", - "UserDownloadingItemWithValues": "{0} is downloading {1}", - "UserLockedOutWithName": "User {0} has been locked out", - "UserOfflineFromDevice": "{0} has disconnected from {1}", - "UserOnlineFromDevice": "{0} is online from {1}", - "UserPasswordChangedWithName": "Password has been changed for user {0}", - "UserPolicyUpdatedWithName": "User policy has been updated for {0}", - "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}", - "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", - "ValueSpecialEpisodeName": "Special - {0}", - "VersionNumber": "Version {0}" + "SubtitleDownloadFailureFromForItem": "Fallo de descarga de subtítulos desde {0} para {1}", + "SubtitlesDownloadedForItem": "Descargar subtítulos para {0}", + "Sync": "Sincronizar", + "System": "Sistema", + "TvShows": "Series de TV", + "User": "Usuario", + "UserCreatedWithName": "El usuario {0} ha sido creado", + "UserDeletedWithName": "El usuario {0} ha sido borrado", + "UserDownloadingItemWithValues": "{0} está descargando {1}", + "UserLockedOutWithName": "El usuario {0} ha sido bloqueado", + "UserOfflineFromDevice": "{0} se ha desconectado de {1}", + "UserOnlineFromDevice": "{0} está en línea desde {1}", + "UserPasswordChangedWithName": "Se ha cambiado la contraseña para el usuario {0}", + "UserPolicyUpdatedWithName": "Actualizada política de usuario para {0}", + "UserStartedPlayingItemWithValues": "{0} está reproduciendo {1} en {2}", + "UserStoppedPlayingItemWithValues": "{0} ha terminado de reproducir {1} en {2}", + "ValueHasBeenAddedToLibrary": "{0} ha sido añadido a tu biblioteca multimedia", + "ValueSpecialEpisodeName": "Especial - {0}", + "VersionNumber": "Versión {0}" } -- cgit v1.2.3 From 3d3d879b99776e6d156773aec5693ee7c63479ea Mon Sep 17 00:00:00 2001 From: Deniz Date: Fri, 22 Feb 2019 08:15:26 +0000 Subject: Translated using Weblate (Turkish) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/tr/ --- .../Localization/Core/tr.json | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json index 495f82db6..9e00eba62 100644 --- a/Emby.Server.Implementations/Localization/Core/tr.json +++ b/Emby.Server.Implementations/Localization/Core/tr.json @@ -1,12 +1,12 @@ { - "Albums": "Albums", - "AppDeviceValues": "App: {0}, Device: {1}", - "Application": "Application", - "Artists": "Artists", - "AuthenticationSucceededWithUserName": "{0} successfully authenticated", - "Books": "Books", + "Albums": "Albümler", + "AppDeviceValues": "Uygulama: {0}, Aygıt: {1}", + "Application": "Uygulama", + "Artists": "Sanatçılar", + "AuthenticationSucceededWithUserName": "{0} başarı ile giriş yaptı", + "Books": "Kitaplar", "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", - "Channels": "Channels", + "Channels": "Kanallar", "ChapterNameValue": "Chapter {0}", "Collections": "Collections", "DeviceOfflineWithName": "{0} has disconnected", @@ -17,8 +17,8 @@ "Genres": "Genres", "HeaderAlbumArtists": "Album Artists", "HeaderCameraUploads": "Camera Uploads", - "HeaderContinueWatching": "Continue Watching", - "HeaderFavoriteAlbums": "Favorite Albums", + "HeaderContinueWatching": "İzlemeye Devam Et", + "HeaderFavoriteAlbums": "Favori Albümler", "HeaderFavoriteArtists": "Favorite Artists", "HeaderFavoriteEpisodes": "Favorite Episodes", "HeaderFavoriteShows": "Favori Showlar", @@ -30,21 +30,21 @@ "Inherit": "Inherit", "ItemAddedWithName": "{0} was added to the library", "ItemRemovedWithName": "{0} was removed from the library", - "LabelIpAddressValue": "Ip address: {0}", - "LabelRunningTimeValue": "Running time: {0}", + "LabelIpAddressValue": "Ip adresi: {0}", + "LabelRunningTimeValue": "Çalışma süresi: {0}", "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", + "MessageApplicationUpdated": "Jellyfin Sunucusu güncellendi", "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", "MessageServerConfigurationUpdated": "Server configuration has been updated", "MixedContent": "Mixed content", "Movies": "Movies", - "Music": "Music", - "MusicVideos": "Music videos", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", + "Music": "Müzik", + "MusicVideos": "Müzik videoları", + "NameInstallFailed": "{0} kurulum başarısız", + "NameSeasonNumber": "Sezon {0}", + "NameSeasonUnknown": "Bilinmeyen Sezon", + "NewVersionIsAvailable": "Jellyfin Sunucusunun yeni bir versiyonu indirmek için hazır.", "NotificationOptionApplicationUpdateAvailable": "Application update available", "NotificationOptionApplicationUpdateInstalled": "Application update installed", "NotificationOptionAudioPlayback": "Audio playback started", -- cgit v1.2.3 From 93fe7957fb4ed4f85b14bc4560f8e595540e91bd Mon Sep 17 00:00:00 2001 From: Matsuri Date: Fri, 1 Mar 2019 05:50:39 +0000 Subject: Translated using Weblate (Chinese (Simplified)) Currently translated at 97.8% (92 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/ --- Emby.Server.Implementations/Localization/Core/zh-CN.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index 8910a6bce..6f7d362d3 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-CN.json +++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json @@ -34,14 +34,14 @@ "LabelRunningTimeValue": "运行时间:{0}", "Latest": "最新", "MessageApplicationUpdated": "Jellyfin 服务器已更新", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", + "MessageApplicationUpdatedTo": "Jellyfin Server 的版本已更新为 {0}", "MessageNamedServerConfigurationUpdatedWithValue": "服务器配置 {0} 部分已更新", "MessageServerConfigurationUpdated": "服务器配置已更新", "MixedContent": "混合内容", "Movies": "电影", "Music": "音乐", "MusicVideos": "音乐视频", - "NameInstallFailed": "{0} installation failed", + "NameInstallFailed": "{0} 安装失败", "NameSeasonNumber": "季 {0}", "NameSeasonUnknown": "未知季", "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", @@ -70,7 +70,7 @@ "ProviderValue": "提供商:{0}", "ScheduledTaskFailedWithName": "{0} 已失败", "ScheduledTaskStartedWithName": "{0} 已开始", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", + "ServerNameNeedsToBeRestarted": "{0} 需要重新启动", "Shows": "节目", "Songs": "歌曲", "StartupEmbyServerIsLoading": "Jellyfin 服务器加载中。请稍后再试。", -- cgit v1.2.3 From 16adaa64c9c94ea35ffd99df114a0b8de9249cf6 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Mon, 4 Mar 2019 12:00:32 +0000 Subject: Translated using Weblate (Kazakh) Currently translated at 100.0% (94 of 94 strings) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/kk/ --- Emby.Server.Implementations/Localization/Core/kk.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json index 658d168e9..23841f37d 100644 --- a/Emby.Server.Implementations/Localization/Core/kk.json +++ b/Emby.Server.Implementations/Localization/Core/kk.json @@ -3,15 +3,15 @@ "AppDeviceValues": "Qoldanba: {0}, Qurylǵy: {1}", "Application": "Qoldanba", "Artists": "Oryndaýshylar", - "AuthenticationSucceededWithUserName": "{0} túpnusqalyǵyn rastalýy sátti", + "AuthenticationSucceededWithUserName": "{0} túpnusqalyq rastalýy sátti aıaqtaldy", "Books": "Kitaptar", - "CameraImageUploadedFrom": "Jańa sýret {0} kamerasynan júktep alyndy", + "CameraImageUploadedFrom": "{0} kamerasynan jańa sýret júktep alyndy", "Channels": "Arnalar", "ChapterNameValue": "{0}-sahna", "Collections": "Jıyntyqtar", "DeviceOfflineWithName": "{0} ajyratylǵan", "DeviceOnlineWithName": "{0} qosylǵan", - "FailedLoginAttemptWithUserName": "{0} tarapynan kirý áreketi sátsiz", + "FailedLoginAttemptWithUserName": "{0} tarapynan kirý áreketi sátsiz aıaqtaldy", "Favorites": "Tańdaýlylar", "Folders": "Qaltalar", "Genres": "Janrlar", @@ -28,13 +28,13 @@ "HeaderRecordingGroups": "Jazba toptary", "HomeVideos": "Úılik beıneler", "Inherit": "Muraǵa ıelený", - "ItemAddedWithName": "{0} tasyǵyshhanaǵa ústelindi", + "ItemAddedWithName": "{0} tasyǵyshhanaǵa ústeldi", "ItemRemovedWithName": "{0} tasyǵyshhanadan alastaldy", "LabelIpAddressValue": "IP-mekenjaıy: {0}", "LabelRunningTimeValue": "Oınatý ýaqyty: {0}", "Latest": "Eń keıingi", "MessageApplicationUpdated": "Jellyfin Serveri jańartyldy", - "MessageApplicationUpdatedTo": "Jellyfin Serveri {0} deńgeıge jańartyldy", + "MessageApplicationUpdatedTo": "Jellyfin Serveri {0} nusqasyna jańartyldy", "MessageNamedServerConfigurationUpdatedWithValue": "Server teńsheliminiń {0} bólimi jańartyldy", "MessageServerConfigurationUpdated": "Server teńshelimi jańartyldy", "MixedContent": "Aralas mazmun", -- cgit v1.2.3 From bf43dc00bb193fb4c7aca882aadbe086ed5a1815 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Mar 2019 22:32:52 +0100 Subject: More warning fixes --- Emby.Server.Implementations/ApplicationHost.cs | 209 +++++++------- .../Diagnostics/CommonProcess.cs | 72 +++-- .../Library/LibraryManager.cs | 319 +++++++++++---------- .../Localization/LocalizationManager.cs | 37 +-- .../Session/SessionManager.cs | 244 +++++++++------- .../Sorting/AlbumArtistComparer.cs | 2 +- .../Sorting/SeriesSortNameComparer.cs | 14 +- MediaBrowser.Api/BaseApiService.cs | 35 +-- MediaBrowser.Api/UserLibrary/ArtistsService.cs | 10 - MediaBrowser.Providers/Manager/ProviderManager.cs | 39 +-- .../Music/MusicBrainzAlbumProvider.cs | 24 +- .../Music/MusicBrainzArtistProvider.cs | 18 +- 12 files changed, 534 insertions(+), 489 deletions(-) (limited to 'Emby.Server.Implementations/Localization') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 1810064e6..94eaffa47 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -34,7 +34,6 @@ using Emby.Server.Implementations.IO; using Emby.Server.Implementations.Library; using Emby.Server.Implementations.LiveTv; using Emby.Server.Implementations.Localization; -using Emby.Server.Implementations.Middleware; using Emby.Server.Implementations.Net; using Emby.Server.Implementations.Playlists; using Emby.Server.Implementations.ScheduledTasks; @@ -161,7 +160,7 @@ namespace Emby.Server.Implementations public event EventHandler> ApplicationUpdated; /// - /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart. + /// Gets a value indicating whether this instance has changes that require the entire application to restart. /// /// true if this instance has pending application restart; otherwise, false. public bool HasPendingRestart { get; private set; } @@ -175,7 +174,7 @@ namespace Emby.Server.Implementations protected ILogger Logger { get; set; } /// - /// Gets or sets the plugins. + /// Gets the plugins. /// /// The plugins. public IPlugin[] Plugins { get; protected set; } @@ -187,13 +186,13 @@ namespace Emby.Server.Implementations public ILoggerFactory LoggerFactory { get; protected set; } /// - /// Gets the application paths. + /// Gets or sets the application paths. /// /// The application paths. protected ServerApplicationPaths ApplicationPaths { get; set; } /// - /// Gets all concrete types. + /// Gets or sets all concrete types. /// /// All concrete types. public Type[] AllConcreteTypes { get; protected set; } @@ -201,7 +200,7 @@ namespace Emby.Server.Implementations /// /// The disposable parts /// - protected readonly List DisposableParts = new List(); + protected readonly List _disposableParts = new List(); /// /// Gets the configuration manager. @@ -240,27 +239,33 @@ namespace Emby.Server.Implementations /// /// The user manager. public IUserManager UserManager { get; set; } + /// /// Gets or sets the library manager. /// /// The library manager. internal ILibraryManager LibraryManager { get; set; } + /// /// Gets or sets the directory watchers. /// /// The directory watchers. private ILibraryMonitor LibraryMonitor { get; set; } + /// /// Gets or sets the provider manager. /// /// The provider manager. private IProviderManager ProviderManager { get; set; } + /// /// Gets or sets the HTTP server. /// /// The HTTP server. private IHttpServer HttpServer { get; set; } + private IDtoService DtoService { get; set; } + public IImageProcessor ImageProcessor { get; set; } /// @@ -268,6 +273,7 @@ namespace Emby.Server.Implementations /// /// The media encoder. private IMediaEncoder MediaEncoder { get; set; } + private ISubtitleEncoder SubtitleEncoder { get; set; } private ISessionManager SessionManager { get; set; } @@ -277,6 +283,7 @@ namespace Emby.Server.Implementations public LocalizationManager LocalizationManager { get; set; } private IEncodingManager EncodingManager { get; set; } + private IChannelManager ChannelManager { get; set; } /// @@ -284,20 +291,29 @@ namespace Emby.Server.Implementations /// /// The user data repository. private IUserDataManager UserDataManager { get; set; } + private IUserRepository UserRepository { get; set; } + internal SqliteItemRepository ItemRepository { get; set; } private INotificationManager NotificationManager { get; set; } + private ISubtitleManager SubtitleManager { get; set; } + private IChapterManager ChapterManager { get; set; } + private IDeviceManager DeviceManager { get; set; } internal IUserViewManager UserViewManager { get; set; } private IAuthenticationRepository AuthenticationRepository { get; set; } + private ITVSeriesManager TVSeriesManager { get; set; } + private ICollectionManager CollectionManager { get; set; } + private IMediaSourceManager MediaSourceManager { get; set; } + private IPlaylistManager PlaylistManager { get; set; } private readonly IConfiguration _configuration; @@ -313,28 +329,37 @@ namespace Emby.Server.Implementations /// /// The zip client. protected IZipClient ZipClient { get; private set; } + protected IHttpResultFactory HttpResultFactory { get; private set; } + protected IAuthService AuthService { get; private set; } - public IStartupOptions StartupOptions { get; private set; } + public IStartupOptions StartupOptions { get; } internal IImageEncoder ImageEncoder { get; private set; } protected IProcessFactory ProcessFactory { get; private set; } + protected ICryptoProvider CryptographyProvider = new CryptographyProvider(); protected readonly IXmlSerializer XmlSerializer; protected ISocketFactory SocketFactory { get; private set; } + protected ITaskManager TaskManager { get; private set; } + public IHttpClient HttpClient { get; private set; } + protected INetworkManager NetworkManager { get; set; } + public IJsonSerializer JsonSerializer { get; private set; } + protected IIsoManager IsoManager { get; private set; } /// /// Initializes a new instance of the class. /// - public ApplicationHost(ServerApplicationPaths applicationPaths, + public ApplicationHost( + ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory, IStartupOptions options, IFileSystem fileSystem, @@ -395,7 +420,7 @@ namespace Emby.Server.Implementations _validAddressResults.Clear(); } - public string ApplicationVersion => typeof(ApplicationHost).Assembly.GetName().Version.ToString(3); + public string ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3); /// /// Gets the current application user agent @@ -404,13 +429,16 @@ namespace Emby.Server.Implementations public string ApplicationUserAgent => Name.Replace(' ','-') + "/" + ApplicationVersion; private string _productName; + /// /// Gets the current application name /// /// The application name. - public string ApplicationProductName => _productName ?? (_productName = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName); + public string ApplicationProductName + => _productName ?? (_productName = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName); private DeviceId _deviceId; + public string SystemId { get @@ -441,15 +469,15 @@ namespace Emby.Server.Implementations /// /// Creates an instance of type and resolves all constructor dependencies /// - /// The type. - /// System.Object. + /// /// The type + /// T public T CreateInstance() => ActivatorUtilities.CreateInstance(_serviceProvider); /// /// Creates the instance safe. /// - /// The type information. + /// The type. /// System.Object. protected object CreateInstanceSafe(Type type) { @@ -468,14 +496,14 @@ namespace Emby.Server.Implementations /// /// Resolves this instance. /// - /// + /// The type /// ``0. public T Resolve() => _serviceProvider.GetService(); /// /// Gets the export types. /// - /// + /// The type /// IEnumerable{Type}. public IEnumerable GetExportTypes() { @@ -487,22 +515,22 @@ namespace Emby.Server.Implementations /// /// Gets the exports. /// - /// + /// The type /// if set to true [manage lifetime]. /// IEnumerable{``0}. public IEnumerable GetExports(bool manageLifetime = true) { var parts = GetExportTypes() - .Select(x => CreateInstanceSafe(x)) + .Select(CreateInstanceSafe) .Where(i => i != null) .Cast() .ToList(); // Convert to list so this isn't executed for each iteration if (manageLifetime) { - lock (DisposableParts) + lock (_disposableParts) { - DisposableParts.AddRange(parts.OfType()); + _disposableParts.AddRange(parts.OfType()); } } @@ -522,29 +550,20 @@ namespace Emby.Server.Implementations MediaEncoder.SetFFmpegPath(); - //if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath)) - //{ - // if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted) - // { - // ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false; - // ServerConfigurationManager.SaveConfiguration(); - // } - //} - Logger.LogInformation("ServerId: {0}", SystemId); - var entryPoints = GetExports(); + var entryPoints = GetExports().ToList(); var stopWatch = new Stopwatch(); stopWatch.Start(); - await Task.WhenAll(StartEntryPoints(entryPoints, true)); + await Task.WhenAll(StartEntryPoints(entryPoints, true)).ConfigureAwait(false); Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed); Logger.LogInformation("Core startup complete"); HttpServer.GlobalResponse = null; stopWatch.Restart(); - await Task.WhenAll(StartEntryPoints(entryPoints, false)); + await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false); Logger.LogInformation("Executed all post-startup entry points in {Elapsed:g}", stopWatch.Elapsed); stopWatch.Stop(); } @@ -594,7 +613,7 @@ namespace Emby.Server.Implementations SetHttpLimit(); - await RegisterResources(serviceCollection); + await RegisterResources(serviceCollection).ConfigureAwait(false); FindParts(); @@ -631,7 +650,7 @@ namespace Emby.Server.Implementations }) .Build(); - await host.StartAsync(); + await host.StartAsync().ConfigureAwait(false); } private async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func next) @@ -729,8 +748,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ServerConfigurationManager); - LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory); - await LocalizationManager.LoadAll(); + LocalizationManager = new LocalizationManager(ServerConfigurationManager, JsonSerializer, LoggerFactory); + await LocalizationManager.LoadAll().ConfigureAwait(false); serviceCollection.AddSingleton(LocalizationManager); serviceCollection.AddSingleton(new BdInfoExaminer(FileSystemManager)); @@ -769,16 +788,19 @@ namespace Emby.Server.Implementations CertificateInfo = GetCertificateInfo(true); Certificate = GetCertificate(CertificateInfo); - HttpServer = new HttpListenerHost(this, + HttpServer = new HttpListenerHost( + this, LoggerFactory, ServerConfigurationManager, _configuration, NetworkManager, JsonSerializer, XmlSerializer, - CreateHttpListener()); + CreateHttpListener()) + { + GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading") + }; - HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading"); serviceCollection.AddSingleton(HttpServer); ImageProcessor = GetImageProcessor(); @@ -933,7 +955,7 @@ namespace Emby.Server.Implementations var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password; var localCert = new X509Certificate2(certificateLocation, password); - //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA; + // localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA; if (!localCert.HasPrivateKey) { Logger.LogError("No private key included in SSL cert {CertificateLocation}.", certificateLocation); @@ -1034,13 +1056,15 @@ namespace Emby.Server.Implementations HttpServer.Init(GetExports(false), GetExports(), GetUrlPrefixes()); - LibraryManager.AddParts(GetExports(), + LibraryManager.AddParts( + GetExports(), GetExports(), GetExports(), GetExports(), GetExports()); - ProviderManager.AddParts(GetExports(), + ProviderManager.AddParts( + GetExports(), GetExports(), GetExports(), GetExports(), @@ -1121,6 +1145,7 @@ namespace Emby.Server.Implementations } private CertificateInfo CertificateInfo { get; set; } + protected X509Certificate2 Certificate { get; private set; } private IEnumerable GetUrlPrefixes() @@ -1131,7 +1156,7 @@ namespace Emby.Server.Implementations { var prefixes = new List { - "http://"+i+":" + HttpPort + "/" + "http://" + i + ":" + HttpPort + "/" }; if (CertificateInfo != null) @@ -1160,30 +1185,12 @@ namespace Emby.Server.Implementations // Generate self-signed cert var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns); var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx"); - var password = "embycert"; - - //if (generateCertificate) - //{ - // if (!File.Exists(certPath)) - // { - // FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath)); - - // try - // { - // CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger); - // } - // catch (Exception ex) - // { - // Logger.LogError(ex, "Error creating ssl cert"); - // return null; - // } - // } - //} + const string Password = "embycert"; return new CertificateInfo { Path = certPath, - Password = password + Password = Password }; } @@ -1218,9 +1225,9 @@ namespace Emby.Server.Implementations requiresRestart = true; } - var currentCertPath = CertificateInfo == null ? null : CertificateInfo.Path; + var currentCertPath = CertificateInfo?.Path; var newCertInfo = GetCertificateInfo(false); - var newCertPath = newCertInfo == null ? null : newCertInfo.Path; + var newCertPath = newCertInfo?.Path; if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase)) { @@ -1353,6 +1360,7 @@ namespace Emby.Server.Implementations /// /// Gets the system status. /// + /// The cancellation token /// SystemInfo. public async Task GetSystemInfo(CancellationToken cancellationToken) { @@ -1447,19 +1455,19 @@ namespace Emby.Server.Implementations public async Task GetWanApiUrl(CancellationToken cancellationToken) { - const string url = "http://ipv4.icanhazip.com"; + const string Url = "http://ipv4.icanhazip.com"; try { using (var response = await HttpClient.Get(new HttpRequestOptions { - Url = url, + Url = Url, LogErrorResponseBody = false, LogErrors = false, LogRequest = false, TimeoutMs = 10000, BufferContent = false, CancellationToken = cancellationToken - })) + }).ConfigureAwait(false)) { return GetLocalApiUrl(response.ReadToEnd().Trim()); } @@ -1547,10 +1555,12 @@ namespace Emby.Server.Implementations { return result; } + return null; } private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + private async Task IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken) { if (address.Equals(IpAddressInfo.Loopback) || @@ -1567,26 +1577,26 @@ namespace Emby.Server.Implementations return cachedResult; } - var logPing = false; - #if DEBUG - logPing = true; + const bool LogPing = true; +#else + const bool LogPing = false; #endif try { - using (var response = await HttpClient.SendAsync(new HttpRequestOptions - { - Url = apiUrl, - LogErrorResponseBody = false, - LogErrors = logPing, - LogRequest = logPing, - TimeoutMs = 5000, - BufferContent = false, - - CancellationToken = cancellationToken - - }, "POST").ConfigureAwait(false)) + using (var response = await HttpClient.SendAsync( + new HttpRequestOptions + { + Url = apiUrl, + LogErrorResponseBody = false, + LogErrors = LogPing, + LogRequest = LogPing, + TimeoutMs = 5000, + BufferContent = false, + + CancellationToken = cancellationToken + }, "POST").ConfigureAwait(false)) { using (var reader = new StreamReader(response.Content)) { @@ -1651,6 +1661,7 @@ namespace Emby.Server.Implementations public event EventHandler HasUpdateAvailableChanged; private bool _hasUpdateAvailable; + public bool HasUpdateAvailable { get => _hasUpdateAvailable; @@ -1711,7 +1722,7 @@ namespace Emby.Server.Implementations var process = ProcessFactory.Create(new ProcessOptions { FileName = url, - //EnableRaisingEvents = true, + EnableRaisingEvents = true, UseShellExecute = true, ErrorDialog = false }); @@ -1746,26 +1757,25 @@ namespace Emby.Server.Implementations { Logger.LogInformation("Application has been updated to version {0}", package.versionStr); - ApplicationUpdated?.Invoke(this, new GenericEventArgs - { - Argument = package - }); + ApplicationUpdated?.Invoke( + this, + new GenericEventArgs() + { + Argument = package + }); NotifyPendingRestart(); } - private bool _disposed; + private bool _disposed = false; + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - if (!_disposed) - { - _disposed = true; - - Dispose(true); - } + Dispose(true); + GC.SuppressFinalize(this); } /// @@ -1774,14 +1784,19 @@ namespace Emby.Server.Implementations /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { + if (_disposed) + { + return; + } + if (dispose) { var type = GetType(); Logger.LogInformation("Disposing {Type}", type.Name); - var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList(); - DisposableParts.Clear(); + var parts = _disposableParts.Distinct().Where(i => i.GetType() != type).ToList(); + _disposableParts.Clear(); foreach (var part in parts) { @@ -1797,6 +1812,8 @@ namespace Emby.Server.Implementations } } } + + _disposed = true; } } diff --git a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs index 2c4ef170d..175a8f3ce 100644 --- a/Emby.Server.Implementations/Diagnostics/CommonProcess.cs +++ b/Emby.Server.Implementations/Diagnostics/CommonProcess.cs @@ -9,14 +9,14 @@ namespace Emby.Server.Implementations.Diagnostics { public class CommonProcess : IProcess { - public event EventHandler Exited; - - private readonly ProcessOptions _options; private readonly Process _process; + private bool _disposed = false; + private bool _hasExited; + public CommonProcess(ProcessOptions options) { - _options = options; + StartInfo = options; var startInfo = new ProcessStartInfo { @@ -27,10 +27,10 @@ namespace Emby.Server.Implementations.Diagnostics CreateNoWindow = options.CreateNoWindow, RedirectStandardError = options.RedirectStandardError, RedirectStandardInput = options.RedirectStandardInput, - RedirectStandardOutput = options.RedirectStandardOutput + RedirectStandardOutput = options.RedirectStandardOutput, + ErrorDialog = options.ErrorDialog }; - startInfo.ErrorDialog = options.ErrorDialog; if (options.IsHidden) { @@ -45,11 +45,22 @@ namespace Emby.Server.Implementations.Diagnostics if (options.EnableRaisingEvents) { _process.EnableRaisingEvents = true; - _process.Exited += _process_Exited; + _process.Exited += OnProcessExited; } } - private bool _hasExited; + public event EventHandler Exited; + + public ProcessOptions StartInfo { get; } + + public StreamWriter StandardInput => _process.StandardInput; + + public StreamReader StandardError => _process.StandardError; + + public StreamReader StandardOutput => _process.StandardOutput; + + public int ExitCode => _process.ExitCode; + private bool HasExited { get @@ -72,25 +83,6 @@ namespace Emby.Server.Implementations.Diagnostics } } - private void _process_Exited(object sender, EventArgs e) - { - _hasExited = true; - if (Exited != null) - { - Exited(this, e); - } - } - - public ProcessOptions StartInfo => _options; - - public StreamWriter StandardInput => _process.StandardInput; - - public StreamReader StandardError => _process.StandardError; - - public StreamReader StandardOutput => _process.StandardOutput; - - public int ExitCode => _process.ExitCode; - public void Start() { _process.Start(); @@ -108,7 +100,7 @@ namespace Emby.Server.Implementations.Diagnostics public Task WaitForExitAsync(int timeMs) { - //Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true. + // Note: For this function to work correctly, the option EnableRisingEvents needs to be set to true. if (HasExited) { @@ -130,7 +122,29 @@ namespace Emby.Server.Implementations.Diagnostics public void Dispose() { - _process?.Dispose(); + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + _process?.Dispose(); + } + + _disposed = true; + } + + private void OnProcessExited(object sender, EventArgs e) + { + _hasExited = true; + Exited?.Invoke(this, e); } } } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 6591d54c5..1673e3777 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -58,22 +58,23 @@ namespace Emby.Server.Implementations.Library private ILibraryPostScanTask[] PostscanTasks { get; set; } /// - /// Gets the intro providers. + /// Gets or sets the intro providers. /// /// The intro providers. private IIntroProvider[] IntroProviders { get; set; } /// - /// Gets the list of entity resolution ignore rules + /// Gets or sets the list of entity resolution ignore rules /// /// The entity resolution ignore rules. private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; } /// - /// Gets the list of currently registered entity resolvers + /// Gets or sets the list of currently registered entity resolvers /// /// The entity resolvers enumerable. private IItemResolver[] EntityResolvers { get; set; } + private IMultiItemResolver[] MultiItemResolvers { get; set; } /// @@ -83,7 +84,7 @@ namespace Emby.Server.Implementations.Library private IBaseItemComparer[] Comparers { get; set; } /// - /// Gets the active item repository + /// Gets or sets the active item repository /// /// The item repository. public IItemRepository ItemRepository { get; set; } @@ -133,12 +134,14 @@ namespace Emby.Server.Implementations.Library private readonly Func _providerManagerFactory; private readonly Func _userviewManager; public bool IsScanRunning { get; private set; } + private IServerApplicationHost _appHost; /// /// The _library items cache /// private readonly ConcurrentDictionary _libraryItemsCache; + /// /// Gets the library items cache. /// @@ -150,7 +153,8 @@ namespace Emby.Server.Implementations.Library /// /// Initializes a new instance of the class. /// - /// The logger. + /// The application host + /// The logger factory. /// The task manager. /// The user manager. /// The configuration manager. @@ -167,6 +171,7 @@ namespace Emby.Server.Implementations.Library Func providerManagerFactory, Func userviewManager) { + _appHost = appHost; _logger = loggerFactory.CreateLogger(nameof(LibraryManager)); _taskManager = taskManager; _userManager = userManager; @@ -176,7 +181,7 @@ namespace Emby.Server.Implementations.Library _fileSystem = fileSystem; _providerManagerFactory = providerManagerFactory; _userviewManager = userviewManager; - _appHost = appHost; + _libraryItemsCache = new ConcurrentDictionary(); ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -191,8 +196,9 @@ namespace Emby.Server.Implementations.Library /// The resolvers. /// The intro providers. /// The item comparers. - /// The postscan tasks. - public void AddParts(IEnumerable rules, + /// The post scan tasks. + public void AddParts( + IEnumerable rules, IEnumerable resolvers, IEnumerable introProviders, IEnumerable itemComparers, @@ -203,24 +209,19 @@ namespace Emby.Server.Implementations.Library MultiItemResolvers = EntityResolvers.OfType().ToArray(); IntroProviders = introProviders.ToArray(); Comparers = itemComparers.ToArray(); - - PostscanTasks = postscanTasks.OrderBy(i => - { - var hasOrder = i as IHasOrder; - - return hasOrder == null ? 0 : hasOrder.Order; - - }).ToArray(); + PostscanTasks = postscanTasks.ToArray(); } /// /// The _root folder /// private volatile AggregateFolder _rootFolder; + /// /// The _root folder sync lock /// private readonly object _rootFolderSyncLock = new object(); + /// /// Gets the root folder. /// @@ -239,11 +240,13 @@ namespace Emby.Server.Implementations.Library } } } + return _rootFolder; } } private bool _wizardCompleted; + /// /// Records the configuration values. /// @@ -258,7 +261,7 @@ namespace Emby.Server.Implementations.Library /// /// The sender. /// The instance containing the event data. - void ConfigurationUpdated(object sender, EventArgs e) + private void ConfigurationUpdated(object sender, EventArgs e) { var config = ConfigurationManager.Configuration; @@ -335,12 +338,14 @@ namespace Emby.Server.Implementations.Library // channel no longer installed } } + options.DeleteFileLocation = false; } if (item is LiveTvProgram) { - _logger.LogDebug("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + _logger.LogDebug( + "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", item.GetType().Name, item.Name ?? "Unknown name", item.Path ?? string.Empty, @@ -348,7 +353,8 @@ namespace Emby.Server.Implementations.Library } else { - _logger.LogInformation("Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", + _logger.LogInformation( + "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}", item.GetType().Name, item.Name ?? "Unknown name", item.Path ?? string.Empty, @@ -488,12 +494,13 @@ namespace Emby.Server.Implementations.Library { throw new ArgumentNullException(nameof(key)); } + if (type == null) { throw new ArgumentNullException(nameof(type)); } - if (key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath)) + if (key.StartsWith(ConfigurationManager.ApplicationPaths.ProgramDataPath, StringComparison.Ordinal)) { // Try to normalize paths located underneath program-data in an attempt to make them more portable key = key.Substring(ConfigurationManager.ApplicationPaths.ProgramDataPath.Length) @@ -511,13 +518,11 @@ namespace Emby.Server.Implementations.Library return key.GetMD5(); } - public BaseItem ResolvePath(FileSystemMetadata fileInfo, - Folder parent = null) - { - return ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent); - } + public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null) + => ResolvePath(fileInfo, new DirectoryService(_logger, _fileSystem), null, parent); - private BaseItem ResolvePath(FileSystemMetadata fileInfo, + private BaseItem ResolvePath( + FileSystemMetadata fileInfo, IDirectoryService directoryService, IItemResolver[] resolvers, Folder parent = null, @@ -572,7 +577,7 @@ namespace Emby.Server.Implementations.Library { _logger.LogError(ex, "Error in GetFilteredFileSystemEntries isPhysicalRoot: {0} IsVf: {1}", isPhysicalRoot, isVf); - files = new FileSystemMetadata[] { }; + files = Array.Empty(); } else { @@ -600,13 +605,7 @@ namespace Emby.Server.Implementations.Library } public bool IgnoreFile(FileSystemMetadata file, BaseItem parent) - { - if (EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent))) - { - return true; - } - return false; - } + => EntityResolutionIgnoreRules.Any(r => r.ShouldIgnore(file, parent)); public List NormalizeRootPathList(IEnumerable paths) { @@ -646,7 +645,8 @@ namespace Emby.Server.Implementations.Library return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers); } - public IEnumerable ResolvePaths(IEnumerable files, + public IEnumerable ResolvePaths( + IEnumerable files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, @@ -672,6 +672,7 @@ namespace Emby.Server.Implementations.Library { ResolverHelper.SetInitialItemValues(item, parent, _fileSystem, this, directoryService); } + items.AddRange(ResolveFileList(result.ExtraFiles, directoryService, parent, collectionType, resolvers, libraryOptions)); return items; } @@ -681,7 +682,8 @@ namespace Emby.Server.Implementations.Library return ResolveFileList(fileList, directoryService, parent, collectionType, resolvers, libraryOptions); } - private IEnumerable ResolveFileList(IEnumerable fileList, + private IEnumerable ResolveFileList( + IEnumerable fileList, IDirectoryService directoryService, Folder parent, string collectionType, @@ -766,6 +768,7 @@ namespace Emby.Server.Implementations.Library private volatile UserRootFolder _userRootFolder; private readonly object _syncLock = new object(); + public Folder GetUserRootFolder() { if (_userRootFolder == null) @@ -810,8 +813,6 @@ namespace Emby.Server.Implementations.Library throw new ArgumentNullException(nameof(path)); } - //_logger.LogInformation("FindByPath {0}", path); - var query = new InternalItemsQuery { Path = path, @@ -885,7 +886,6 @@ namespace Emby.Server.Implementations.Library /// /// The value. /// Task{Year}. - /// public Year GetYear(int value) { if (value <= 0) @@ -1027,20 +1027,25 @@ namespace Emby.Server.Implementations.Library private async Task ValidateTopLibraryFolders(CancellationToken cancellationToken) { - var rootChildren = RootFolder.Children.ToList(); - rootChildren = GetUserRootFolder().Children.ToList(); - await RootFolder.RefreshMetadata(cancellationToken).ConfigureAwait(false); // Start by just validating the children of the root, but go no further - await RootFolder.ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), recursive: false); + await RootFolder.ValidateChildren( + new SimpleProgress(), + cancellationToken, + new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), + recursive: false).ConfigureAwait(false); await GetUserRootFolder().RefreshMetadata(cancellationToken).ConfigureAwait(false); - await GetUserRootFolder().ValidateChildren(new SimpleProgress(), cancellationToken, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), recursive: false).ConfigureAwait(false); + await GetUserRootFolder().ValidateChildren( + new SimpleProgress(), + cancellationToken, + new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)), + recursive: false).ConfigureAwait(false); // Quickly scan CollectionFolders for changes - foreach (var folder in GetUserRootFolder().Children.OfType().ToList()) + foreach (var folder in GetUserRootFolder().Children.OfType()) { await folder.RefreshMetadata(cancellationToken).ConfigureAwait(false); } @@ -1204,7 +1209,7 @@ namespace Emby.Server.Implementations.Library private string GetCollectionType(string path) { return _fileSystem.GetFilePaths(path, new[] { ".collection" }, true, false) - .Select(i => Path.GetFileNameWithoutExtension(i)) + .Select(Path.GetFileNameWithoutExtension) .FirstOrDefault(i => !string.IsNullOrEmpty(i)); } @@ -1218,7 +1223,7 @@ namespace Emby.Server.Implementations.Library { if (id == Guid.Empty) { - throw new ArgumentException(nameof(id), "Guid can't be empty"); + throw new ArgumentException("Guid can't be empty", nameof(id)); } if (LibraryItemsCache.TryGetValue(id, out BaseItem item)) @@ -1386,17 +1391,7 @@ namespace Emby.Server.Implementations.Library var parents = query.AncestorIds.Select(i => GetItemById(i)).ToList(); - if (parents.All(i => - { - if (i is ICollectionFolder || i is UserView) - { - return true; - } - - //_logger.LogDebug("Query requires ancestor query due to type: " + i.GetType().Name); - return false; - - })) + if (parents.All(i => i is ICollectionFolder || i is UserView)) { // Optimize by querying against top level views query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray(); @@ -1452,17 +1447,7 @@ namespace Emby.Server.Implementations.Library private void SetTopParentIdsOrAncestors(InternalItemsQuery query, List parents) { - if (parents.All(i => - { - if (i is ICollectionFolder || i is UserView) - { - return true; - } - - //_logger.LogDebug("Query requires ancestor query due to type: " + i.GetType().Name); - return false; - - })) + if (parents.All(i => i is ICollectionFolder || i is UserView)) { // Optimize by querying against top level views query.TopParentIds = parents.SelectMany(i => GetTopParentIdsForQuery(i, query.User)).ToArray(); @@ -1511,11 +1496,9 @@ namespace Emby.Server.Implementations.Library private IEnumerable GetTopParentIdsForQuery(BaseItem item, User user) { - var view = item as UserView; - - if (view != null) + if (item is UserView view) { - if (string.Equals(view.ViewType, CollectionType.LiveTv)) + if (string.Equals(view.ViewType, CollectionType.LiveTv, StringComparison.Ordinal)) { return new[] { view.Id }; } @@ -1528,8 +1511,10 @@ namespace Emby.Server.Implementations.Library { return GetTopParentIdsForQuery(displayParent, user); } + return Array.Empty(); } + if (!view.ParentId.Equals(Guid.Empty)) { var displayParent = GetItemById(view.ParentId); @@ -1537,6 +1522,7 @@ namespace Emby.Server.Implementations.Library { return GetTopParentIdsForQuery(displayParent, user); } + return Array.Empty(); } @@ -1550,11 +1536,11 @@ namespace Emby.Server.Implementations.Library .Where(i => user.IsFolderGrouped(i.Id)) .SelectMany(i => GetTopParentIdsForQuery(i, user)); } + return Array.Empty(); } - var collectionFolder = item as CollectionFolder; - if (collectionFolder != null) + if (item is CollectionFolder collectionFolder) { return collectionFolder.PhysicalFolderIds; } @@ -1564,6 +1550,7 @@ namespace Emby.Server.Implementations.Library { return new[] { topParent.Id }; } + return Array.Empty(); } @@ -1760,19 +1747,16 @@ namespace Emby.Server.Implementations.Library { var comparer = Comparers.FirstOrDefault(c => string.Equals(name, c.Name, StringComparison.OrdinalIgnoreCase)); - if (comparer != null) + // If it requires a user, create a new one, and assign the user + if (comparer is IUserBaseItemComparer) { - // If it requires a user, create a new one, and assign the user - if (comparer is IUserBaseItemComparer) - { - var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType()); + var userComparer = (IUserBaseItemComparer)Activator.CreateInstance(comparer.GetType()); - userComparer.User = user; - userComparer.UserManager = _userManager; - userComparer.UserDataRepository = _userDataRepository; + userComparer.User = user; + userComparer.UserManager = _userManager; + userComparer.UserDataRepository = _userDataRepository; - return userComparer; - } + return userComparer; } return comparer; @@ -1783,7 +1767,6 @@ namespace Emby.Server.Implementations.Library /// /// The item. /// The parent item. - /// Task. public void CreateItem(BaseItem item, BaseItem parent) { CreateItems(new[] { item }, parent, CancellationToken.None); @@ -1793,20 +1776,23 @@ namespace Emby.Server.Implementations.Library /// Creates the items. /// /// The items. + /// The parent item /// The cancellation token. - /// Task. public void CreateItems(IEnumerable items, BaseItem parent, CancellationToken cancellationToken) { - ItemRepository.SaveItems(items, cancellationToken); + // Don't iterate multiple times + var itemsList = items.ToList(); + + ItemRepository.SaveItems(itemsList, cancellationToken); - foreach (var item in items) + foreach (var item in itemsList) { RegisterItem(item); } if (ItemAdded != null) { - foreach (var item in items) + foreach (var item in itemsList) { // With the live tv guide this just creates too much noise if (item.SourceType != SourceType.Library) @@ -1816,11 +1802,13 @@ namespace Emby.Server.Implementations.Library try { - ItemAdded(this, new ItemChangeEventArgs - { - Item = item, - Parent = parent ?? item.GetParent() - }); + ItemAdded( + this, + new ItemChangeEventArgs + { + Item = item, + Parent = parent ?? item.GetParent() + }); } catch (Exception ex) { @@ -1842,7 +1830,10 @@ namespace Emby.Server.Implementations.Library /// public void UpdateItems(IEnumerable items, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { - foreach (var item in items) + // Don't iterate multiple times + var itemsList = items.ToList(); + + foreach (var item in itemsList) { if (item.IsFileProtocol) { @@ -1854,14 +1845,11 @@ namespace Emby.Server.Implementations.Library RegisterItem(item); } - //var logName = item.LocationType == LocationType.Remote ? item.Name ?? item.Path : item.Path ?? item.Name; - //_logger.LogDebug("Saving {0} to database.", logName); - - ItemRepository.SaveItems(items, cancellationToken); + ItemRepository.SaveItems(itemsList, cancellationToken); if (ItemUpdated != null) { - foreach (var item in items) + foreach (var item in itemsList) { // With the live tv guide this just creates too much noise if (item.SourceType != SourceType.Library) @@ -1871,12 +1859,14 @@ namespace Emby.Server.Implementations.Library try { - ItemUpdated(this, new ItemChangeEventArgs - { - Item = item, - Parent = parent, - UpdateReason = updateReason - }); + ItemUpdated( + this, + new ItemChangeEventArgs + { + Item = item, + Parent = parent, + UpdateReason = updateReason + }); } catch (Exception ex) { @@ -1890,9 +1880,9 @@ namespace Emby.Server.Implementations.Library /// Updates the item. /// /// The item. + /// The parent item. /// The update reason. /// The cancellation token. - /// Task. public void UpdateItem(BaseItem item, BaseItem parent, ItemUpdateType updateReason, CancellationToken cancellationToken) { UpdateItems(new [] { item }, parent, updateReason, cancellationToken); @@ -1902,17 +1892,20 @@ namespace Emby.Server.Implementations.Library /// Reports the item removed. /// /// The item. + /// The parent item. public void ReportItemRemoved(BaseItem item, BaseItem parent) { if (ItemRemoved != null) { try { - ItemRemoved(this, new ItemChangeEventArgs - { - Item = item, - Parent = parent - }); + ItemRemoved( + this, + new ItemChangeEventArgs + { + Item = item, + Parent = parent + }); } catch (Exception ex) { @@ -2038,8 +2031,7 @@ namespace Emby.Server.Implementations.Library public string GetConfiguredContentType(BaseItem item, bool inheritConfiguredPath) { - var collectionFolder = item as ICollectionFolder; - if (collectionFolder != null) + if (item is ICollectionFolder collectionFolder) { return collectionFolder.CollectionType; } @@ -2049,13 +2041,11 @@ namespace Emby.Server.Implementations.Library private string GetContentTypeOverride(string path, bool inherit) { - var nameValuePair = ConfigurationManager.Configuration.ContentTypes.FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path) || (inherit && !string.IsNullOrEmpty(i.Name) && _fileSystem.ContainsSubPath(i.Name, path))); - if (nameValuePair != null) - { - return nameValuePair.Value; - } - - return null; + var nameValuePair = ConfigurationManager.Configuration.ContentTypes + .FirstOrDefault(i => _fileSystem.AreEqual(i.Name, path) + || (inherit && !string.IsNullOrEmpty(i.Name) + && _fileSystem.ContainsSubPath(i.Name, path))); + return nameValuePair?.Value; } private string GetTopFolderContentType(BaseItem item) @@ -2072,6 +2062,7 @@ namespace Emby.Server.Implementations.Library { break; } + item = parent; } @@ -2083,9 +2074,9 @@ namespace Emby.Server.Implementations.Library } private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24); - //private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromMinutes(1); - public UserView GetNamedView(User user, + public UserView GetNamedView( + User user, string name, string viewType, string sortName) @@ -2093,13 +2084,15 @@ namespace Emby.Server.Implementations.Library return GetNamedView(user, name, Guid.Empty, viewType, sortName); } - public UserView GetNamedView(string name, + public UserView GetNamedView( + string name, string viewType, string sortName) { - var path = Path.Combine(ConfigurationManager.ApplicationPaths.InternalMetadataPath, - "views", - _fileSystem.GetValidFilename(viewType)); + var path = Path.Combine( + ConfigurationManager.ApplicationPaths.InternalMetadataPath, + "views", + _fileSystem.GetValidFilename(viewType)); var id = GetNewItemId(path + "_namedview_" + name, typeof(UserView)); @@ -2135,7 +2128,8 @@ namespace Emby.Server.Implementations.Library return item; } - public UserView GetNamedView(User user, + public UserView GetNamedView( + User user, string name, Guid parentId, string viewType, @@ -2164,10 +2158,10 @@ namespace Emby.Server.Implementations.Library Name = name, ViewType = viewType, ForcedSortName = sortName, - UserId = user.Id + UserId = user.Id, + DisplayParentId = parentId }; - item.DisplayParentId = parentId; CreateItem(item, null); @@ -2184,20 +2178,24 @@ namespace Emby.Server.Implementations.Library if (refresh) { - _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) - { - // Need to force save to increment DateLastSaved - ForceSave = true + _providerManagerFactory().QueueRefresh( + item.Id, + new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) + { + // Need to force save to increment DateLastSaved + ForceSave = true - }, RefreshPriority.Normal); + }, + RefreshPriority.Normal); } return item; } - public UserView GetShadowView(BaseItem parent, - string viewType, - string sortName) + public UserView GetShadowView( + BaseItem parent, + string viewType, + string sortName) { if (parent == null) { @@ -2248,18 +2246,21 @@ namespace Emby.Server.Implementations.Library if (refresh) { - _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) - { - // Need to force save to increment DateLastSaved - ForceSave = true - - }, RefreshPriority.Normal); + _providerManagerFactory().QueueRefresh( + item.Id, + new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) + { + // Need to force save to increment DateLastSaved + ForceSave = true + }, + RefreshPriority.Normal); } return item; } - public UserView GetNamedView(string name, + public UserView GetNamedView( + string name, Guid parentId, string viewType, string sortName, @@ -2322,17 +2323,21 @@ namespace Emby.Server.Implementations.Library if (refresh) { - _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) - { - // Need to force save to increment DateLastSaved - ForceSave = true - }, RefreshPriority.Normal); + _providerManagerFactory().QueueRefresh( + item.Id, + new MetadataRefreshOptions(new DirectoryService(_logger, _fileSystem)) + { + // Need to force save to increment DateLastSaved + ForceSave = true + }, + RefreshPriority.Normal); } return item; } - public void AddExternalSubtitleStreams(List streams, + public void AddExternalSubtitleStreams( + List streams, string videoPath, string[] files) { @@ -2436,6 +2441,7 @@ namespace Emby.Server.Implementations.Library { changed = true; } + episode.IndexNumber = episodeInfo.EpisodeNumber; } @@ -2445,6 +2451,7 @@ namespace Emby.Server.Implementations.Library { changed = true; } + episode.IndexNumberEnd = episodeInfo.EndingEpsiodeNumber; } @@ -2454,6 +2461,7 @@ namespace Emby.Server.Implementations.Library { changed = true; } + episode.ParentIndexNumber = episodeInfo.SeasonNumber; } } @@ -2483,6 +2491,7 @@ namespace Emby.Server.Implementations.Library private NamingOptions _namingOptions; private string[] _videoFileExtensions; + private NamingOptions GetNamingOptionsInternal() { if (_namingOptions == null) @@ -2679,7 +2688,7 @@ namespace Emby.Server.Implementations.Library var newPath = path.Replace(from, to, StringComparison.OrdinalIgnoreCase); var changed = false; - if (!string.Equals(newPath, path)) + if (!string.Equals(newPath, path, StringComparison.Ordinal)) { if (to.IndexOf('/') != -1) { @@ -2803,6 +2812,7 @@ namespace Emby.Server.Implementations.Library { continue; } + throw; } } @@ -2907,6 +2917,7 @@ namespace Emby.Server.Implementations.Library } private const string ShortcutFileExtension = ".mblink"; + public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo) { AddMediaPathInternal(virtualFolderName, pathInfo, true); @@ -2923,7 +2934,7 @@ namespace Emby.Server.Implementations.Library if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentNullException(nameof(path)); + throw new ArgumentException(nameof(path)); } if (!Directory.Exists(path)) diff --git a/Emby.Server.Implementations/Localization/LocalizationManager.cs b/Emby.Server.Implementations/Localization/LocalizationManager.cs index 762649b71..8c49b6405 100644 --- a/Emby.Server.Implementations/Localization/LocalizationManager.cs +++ b/Emby.Server.Implementations/Localization/LocalizationManager.cs @@ -11,7 +11,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; @@ -35,7 +34,6 @@ namespace Emby.Server.Implementations.Localization private readonly Dictionary> _allParentalRatings = new Dictionary>(StringComparer.OrdinalIgnoreCase); - private readonly IFileSystem _fileSystem; private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; private static readonly Assembly _assembly = typeof(LocalizationManager).Assembly; @@ -44,40 +42,38 @@ namespace Emby.Server.Implementations.Localization /// Initializes a new instance of the class. /// /// The configuration manager. - /// The file system. /// The json serializer. + /// The logger factory public LocalizationManager( IServerConfigurationManager configurationManager, - IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILoggerFactory loggerFactory) { _configurationManager = configurationManager; - _fileSystem = fileSystem; _jsonSerializer = jsonSerializer; _logger = loggerFactory.CreateLogger(nameof(LocalizationManager)); } public async Task LoadAll() { - const string ratingsResource = "Emby.Server.Implementations.Localization.Ratings."; + const string RatingsResource = "Emby.Server.Implementations.Localization.Ratings."; // Extract from the assembly foreach (var resource in _assembly.GetManifestResourceNames()) { - if (!resource.StartsWith(ratingsResource)) + if (!resource.StartsWith(RatingsResource, StringComparison.Ordinal)) { continue; } - string countryCode = resource.Substring(ratingsResource.Length, 2); + string countryCode = resource.Substring(RatingsResource.Length, 2); var dict = new Dictionary(StringComparer.OrdinalIgnoreCase); using (var str = _assembly.GetManifestResourceStream(resource)) using (var reader = new StreamReader(str)) { string line; - while ((line = await reader.ReadLineAsync()) != null) + while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null) { if (string.IsNullOrWhiteSpace(line)) { @@ -102,7 +98,7 @@ namespace Emby.Server.Implementations.Localization _allParentalRatings[countryCode] = dict; } - await LoadCultures(); + await LoadCultures().ConfigureAwait(false); } public string NormalizeFormKD(string text) @@ -121,14 +117,14 @@ namespace Emby.Server.Implementations.Localization { List list = new List(); - const string path = "Emby.Server.Implementations.Localization.iso6392.txt"; + const string ResourcePath = "Emby.Server.Implementations.Localization.iso6392.txt"; - using (var stream = _assembly.GetManifestResourceStream(path)) + using (var stream = _assembly.GetManifestResourceStream(ResourcePath)) using (var reader = new StreamReader(stream)) { while (!reader.EndOfStream) { - var line = await reader.ReadLineAsync(); + var line = await reader.ReadLineAsync().ConfigureAwait(false); if (string.IsNullOrWhiteSpace(line)) { @@ -154,11 +150,11 @@ namespace Emby.Server.Implementations.Localization string[] threeletterNames; if (string.IsNullOrWhiteSpace(parts[1])) { - threeletterNames = new [] { parts[0] }; + threeletterNames = new[] { parts[0] }; } else { - threeletterNames = new [] { parts[0], parts[1] }; + threeletterNames = new[] { parts[0], parts[1] }; } list.Add(new CultureDto @@ -218,6 +214,7 @@ namespace Emby.Server.Implementations.Localization /// Gets the ratings. /// /// The country code. + /// The ratings private Dictionary GetRatings(string countryCode) { _allParentalRatings.TryGetValue(countryCode, out var value); @@ -227,9 +224,12 @@ namespace Emby.Server.Implementations.Localization private static readonly string[] _unratedValues = { "n/a", "unrated", "not rated" }; + /// /// /// Gets the rating level. /// + /// Rating field + /// The rating level> public int? GetRatingLevel(string rating) { if (string.IsNullOrEmpty(rating)) @@ -301,6 +301,7 @@ namespace Emby.Server.Implementations.Localization { culture = _configurationManager.Configuration.UICulture; } + if (string.IsNullOrEmpty(culture)) { culture = DefaultCulture; @@ -346,8 +347,8 @@ namespace Emby.Server.Implementations.Localization var namespaceName = GetType().Namespace + "." + prefix; - await CopyInto(dictionary, namespaceName + "." + baseFilename); - await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)); + await CopyInto(dictionary, namespaceName + "." + baseFilename).ConfigureAwait(false); + await CopyInto(dictionary, namespaceName + "." + GetResourceFilename(culture)).ConfigureAwait(false); return dictionary; } @@ -359,7 +360,7 @@ namespace Emby.Server.Implementations.Localization // If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain if (stream != null) { - var dict = await _jsonSerializer.DeserializeFromStreamAsync>(stream); + var dict = await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); foreach (var key in dict.Keys) { diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs index 03e7b2654..985748caf 100644 --- a/Emby.Server.Implementations/Session/SessionManager.cs +++ b/Emby.Server.Implementations/Session/SessionManager.cs @@ -116,14 +116,14 @@ namespace Emby.Server.Implementations.Session _authRepo = authRepo; _deviceManager = deviceManager; _mediaSourceManager = mediaSourceManager; - _deviceManager.DeviceOptionsUpdated += _deviceManager_DeviceOptionsUpdated; + _deviceManager.DeviceOptionsUpdated += OnDeviceManagerDeviceOptionsUpdated; } - private void _deviceManager_DeviceOptionsUpdated(object sender, GenericEventArgs> e) + private void OnDeviceManagerDeviceOptionsUpdated(object sender, GenericEventArgs> e) { foreach (var session in Sessions) { - if (string.Equals(session.DeviceId, e.Argument.Item1)) + if (string.Equals(session.DeviceId, e.Argument.Item1, StringComparison.Ordinal)) { if (!string.IsNullOrWhiteSpace(e.Argument.Item2.CustomName)) { @@ -138,11 +138,29 @@ namespace Emby.Server.Implementations.Session } } - private bool _disposed; + private bool _disposed = false; + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + // TODO: dispose stuff + } + + _deviceManager.DeviceOptionsUpdated -= OnDeviceManagerDeviceOptionsUpdated; + _disposed = true; - _deviceManager.DeviceOptionsUpdated -= _deviceManager_DeviceOptionsUpdated; } public void CheckDisposed() @@ -157,7 +175,7 @@ namespace Emby.Server.Implementations.Session /// Gets all connections. /// /// All connections. - public IEnumerable Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate).ToList(); + public IEnumerable Sessions => _activeConnections.Values.OrderByDescending(c => c.LastActivityDate); private void OnSessionStarted(SessionInfo info) { @@ -171,20 +189,27 @@ namespace Emby.Server.Implementations.Session } } - EventHelper.QueueEventIfNotNull(SessionStarted, this, new SessionEventArgs - { - SessionInfo = info - - }, _logger); + EventHelper.QueueEventIfNotNull( + SessionStarted, + this, + new SessionEventArgs + { + SessionInfo = info + }, + _logger); } private void OnSessionEnded(SessionInfo info) { - EventHelper.QueueEventIfNotNull(SessionEnded, this, new SessionEventArgs - { - SessionInfo = info + EventHelper.QueueEventIfNotNull( + SessionEnded, + this, + new SessionEventArgs + { + SessionInfo = info - }, _logger); + }, + _logger); info.Dispose(); } @@ -192,9 +217,6 @@ namespace Emby.Server.Implementations.Session public void UpdateDeviceName(string sessionId, string deviceName) { var session = GetSession(sessionId); - - var key = GetSessionKey(session.Client, session.DeviceId); - if (session != null) { session.DeviceName = deviceName; @@ -210,10 +232,10 @@ namespace Emby.Server.Implementations.Session /// Name of the device. /// The remote end point. /// The user. - /// Task. + /// SessionInfo. /// user - /// - public SessionInfo LogSessionActivity(string appName, + public SessionInfo LogSessionActivity( + string appName, string appVersion, string deviceId, string deviceName, @@ -226,10 +248,12 @@ namespace Emby.Server.Implementations.Session { throw new ArgumentNullException(nameof(appName)); } + if (string.IsNullOrEmpty(appVersion)) { throw new ArgumentNullException(nameof(appVersion)); } + if (string.IsNullOrEmpty(deviceId)) { throw new ArgumentNullException(nameof(deviceId)); @@ -260,10 +284,12 @@ namespace Emby.Server.Implementations.Session if ((activityDate - lastActivityDate).TotalSeconds > 10) { - SessionActivity?.Invoke(this, new SessionEventArgs - { - SessionInfo = session - }); + SessionActivity?.Invoke( + this, + new SessionEventArgs + { + SessionInfo = session + }); } return session; @@ -304,6 +330,7 @@ namespace Emby.Server.Implementations.Session /// /// Updates the now playing item id. /// + /// Task. private async Task UpdateNowPlayingItem(SessionInfo session, PlaybackProgressInfo info, BaseItem libraryItem, bool updateLastCheckInTime) { if (string.IsNullOrEmpty(info.MediaSourceId)) @@ -418,7 +445,7 @@ namespace Emby.Server.Implementations.Session }); sessionInfo.UserId = user == null ? Guid.Empty : user.Id; - sessionInfo.UserName = user == null ? null : user.Name; + sessionInfo.UserName = user?.Name; sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary); sessionInfo.RemoteEndPoint = remoteEndPoint; sessionInfo.Client = appName; @@ -432,7 +459,7 @@ namespace Emby.Server.Implementations.Session if (user == null) { - sessionInfo.AdditionalUsers = new SessionUserInfo[] { }; + sessionInfo.AdditionalUsers = Array.Empty(); } return sessionInfo; @@ -449,9 +476,9 @@ namespace Emby.Server.Implementations.Session ServerId = _appHost.SystemId }; - var username = user == null ? null : user.Name; + var username = user?.Name; - sessionInfo.UserId = user == null ? Guid.Empty : user.Id; + sessionInfo.UserId = user?.Id ?? Guid.Empty; sessionInfo.UserName = username; sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary); sessionInfo.RemoteEndPoint = remoteEndPoint; @@ -508,6 +535,7 @@ namespace Emby.Server.Implementations.Session _idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); } } + private void StopIdleCheckTimer() { if (_idleTimer != null) @@ -539,9 +567,9 @@ namespace Emby.Server.Implementations.Session Item = session.NowPlayingItem, ItemId = session.NowPlayingItem == null ? Guid.Empty : session.NowPlayingItem.Id, SessionId = session.Id, - MediaSourceId = session.PlayState == null ? null : session.PlayState.MediaSourceId, - PositionTicks = session.PlayState == null ? null : session.PlayState.PositionTicks - }); + MediaSourceId = session.PlayState?.MediaSourceId, + PositionTicks = session.PlayState?.PositionTicks + }).ConfigureAwait(false); } catch (Exception ex) { @@ -616,18 +644,22 @@ namespace Emby.Server.Implementations.Session // Nothing to save here // Fire events to inform plugins - EventHelper.QueueEventIfNotNull(PlaybackStart, this, new PlaybackProgressEventArgs - { - Item = libraryItem, - Users = users, - MediaSourceId = info.MediaSourceId, - MediaInfo = info.Item, - DeviceName = session.DeviceName, - ClientName = session.Client, - DeviceId = session.DeviceId, - Session = session - - }, _logger); + EventHelper.QueueEventIfNotNull( + PlaybackStart, + this, + new PlaybackProgressEventArgs + { + Item = libraryItem, + Users = users, + MediaSourceId = info.MediaSourceId, + MediaInfo = info.Item, + DeviceName = session.DeviceName, + ClientName = session.Client, + DeviceId = session.DeviceId, + Session = session + + }, + _logger); StartIdleCheckTimer(); } @@ -667,6 +699,7 @@ namespace Emby.Server.Implementations.Session /// /// Used to report playback progress for an item /// + /// Task. public async Task OnPlaybackProgress(PlaybackProgressInfo info, bool isAutomated) { CheckDisposed(); @@ -695,21 +728,23 @@ namespace Emby.Server.Implementations.Session } } - PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs - { - Item = libraryItem, - Users = users, - PlaybackPositionTicks = session.PlayState.PositionTicks, - MediaSourceId = session.PlayState.MediaSourceId, - MediaInfo = info.Item, - DeviceName = session.DeviceName, - ClientName = session.Client, - DeviceId = session.DeviceId, - IsPaused = info.IsPaused, - PlaySessionId = info.PlaySessionId, - IsAutomated = isAutomated, - Session = session - }); + PlaybackProgress?.Invoke( + this, + new PlaybackProgressEventArgs + { + Item = libraryItem, + Users = users, + PlaybackPositionTicks = session.PlayState.PositionTicks, + MediaSourceId = session.PlayState.MediaSourceId, + MediaInfo = info.Item, + DeviceName = session.DeviceName, + ClientName = session.Client, + DeviceId = session.DeviceId, + IsPaused = info.IsPaused, + PlaySessionId = info.PlaySessionId, + IsAutomated = isAutomated, + Session = session + }); if (!isAutomated) { @@ -830,8 +865,7 @@ namespace Emby.Server.Implementations.Session { MediaSourceInfo mediaSource = null; - var hasMediaSources = libraryItem as IHasMediaSources; - if (hasMediaSources != null) + if (libraryItem is IHasMediaSources hasMediaSources) { mediaSource = await GetMediaSource(libraryItem, info.MediaSourceId, info.LiveStreamId).ConfigureAwait(false); } @@ -848,7 +882,8 @@ namespace Emby.Server.Implementations.Session { var msString = info.PositionTicks.HasValue ? (info.PositionTicks.Value / 10000).ToString(CultureInfo.InvariantCulture) : "unknown"; - _logger.LogInformation("Playback stopped reported by app {0} {1} playing {2}. Stopped at {3} ms", + _logger.LogInformation( + "Playback stopped reported by app {0} {1} playing {2}. Stopped at {3} ms", session.Client, session.ApplicationVersion, info.Item.Name, @@ -887,20 +922,24 @@ namespace Emby.Server.Implementations.Session } } - EventHelper.QueueEventIfNotNull(PlaybackStopped, this, new PlaybackStopEventArgs - { - Item = libraryItem, - Users = users, - PlaybackPositionTicks = info.PositionTicks, - PlayedToCompletion = playedToCompletion, - MediaSourceId = info.MediaSourceId, - MediaInfo = info.Item, - DeviceName = session.DeviceName, - ClientName = session.Client, - DeviceId = session.DeviceId, - Session = session + EventHelper.QueueEventIfNotNull( + PlaybackStopped, + this, + new PlaybackStopEventArgs + { + Item = libraryItem, + Users = users, + PlaybackPositionTicks = info.PositionTicks, + PlayedToCompletion = playedToCompletion, + MediaSourceId = info.MediaSourceId, + MediaInfo = info.Item, + DeviceName = session.DeviceName, + ClientName = session.Client, + DeviceId = session.DeviceId, + Session = session - }, _logger); + }, + _logger); } private bool OnPlaybackStopped(User user, BaseItem item, long? positionTicks, bool playbackFailed) @@ -936,11 +975,10 @@ namespace Emby.Server.Implementations.Session /// The session identifier. /// if set to true [throw on missing]. /// SessionInfo. - /// + /// sessionId private SessionInfo GetSession(string sessionId, bool throwOnMissing = true) { - var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId)); - + var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal)); if (session == null && throwOnMissing) { throw new ResourceNotFoundException(string.Format("Session {0} not found.", sessionId)); @@ -952,7 +990,7 @@ namespace Emby.Server.Implementations.Session private SessionInfo GetSessionToRemoteControl(string sessionId) { // Accept either device id or session id - var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId)); + var session = Sessions.FirstOrDefault(i => string.Equals(i.Id, sessionId, StringComparison.Ordinal)); if (session == null) { @@ -1061,10 +1099,12 @@ namespace Emby.Server.Implementations.Session var series = episode.Series; if (series != null) { - var episodes = series.GetEpisodes(user, new DtoOptions(false) - { - EnableImages = false - }) + var episodes = series.GetEpisodes( + user, + new DtoOptions(false) + { + EnableImages = false + }) .Where(i => !i.IsVirtualItem) .SkipWhile(i => i.Id != episode.Id) .ToList(); @@ -1100,9 +1140,7 @@ namespace Emby.Server.Implementations.Session return new List(); } - var byName = item as IItemByName; - - if (byName != null) + if (item is IItemByName byName) { return byName.GetTaggedItems(new InternalItemsQuery(user) { @@ -1152,7 +1190,7 @@ namespace Emby.Server.Implementations.Session if (item == null) { - _logger.LogError("A non-existant item Id {0} was passed into TranslateItemForInstantMix", id); + _logger.LogError("A non-existent item Id {0} was passed into TranslateItemForInstantMix", id); return new List(); } @@ -1163,13 +1201,15 @@ namespace Emby.Server.Implementations.Session { var generalCommand = new GeneralCommand { - Name = GeneralCommandType.DisplayContent.ToString() + Name = GeneralCommandType.DisplayContent.ToString(), + Arguments = + { + ["ItemId"] = command.ItemId, + ["ItemName"] = command.ItemName, + ["ItemType"] = command.ItemType + } }; - generalCommand.Arguments["ItemId"] = command.ItemId; - generalCommand.Arguments["ItemName"] = command.ItemName; - generalCommand.Arguments["ItemType"] = command.ItemType; - return SendGeneralCommand(controllingSessionId, sessionId, generalCommand, cancellationToken); } @@ -1410,7 +1450,8 @@ namespace Emby.Server.Implementations.Session var token = GetAuthorizationToken(user, request.DeviceId, request.App, request.AppVersion, request.DeviceName); - var session = LogSessionActivity(request.App, + var session = LogSessionActivity( + request.App, request.AppVersion, request.DeviceId, request.DeviceName, @@ -1454,9 +1495,9 @@ namespace Emby.Server.Implementations.Session { Logout(auth); } - catch + catch (Exception ex) { - + _logger.LogError(ex, "Error while logging out."); } } } @@ -1572,7 +1613,8 @@ namespace Emby.Server.Implementations.Session ReportCapabilities(session, capabilities, true); } - private void ReportCapabilities(SessionInfo session, + private void ReportCapabilities( + SessionInfo session, ClientCapabilities capabilities, bool saveCapabilities) { @@ -1580,10 +1622,12 @@ namespace Emby.Server.Implementations.Session if (saveCapabilities) { - CapabilitiesChanged?.Invoke(this, new SessionEventArgs - { - SessionInfo = session - }); + CapabilitiesChanged?.Invoke( + this, + new SessionEventArgs + { + SessionInfo = session + }); try { diff --git a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs index 535f123f9..0804b01fc 100644 --- a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs +++ b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs @@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Sorting { var audio = x as IHasAlbumArtist; - return audio != null ? audio.AlbumArtists.FirstOrDefault() : null; + return audio?.AlbumArtists.FirstOrDefault(); } /// diff --git a/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs b/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs index 46e0dd918..504b6d283 100644 --- a/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs +++ b/Emby.Server.Implementations/Sorting/SeriesSortNameComparer.cs @@ -18,17 +18,17 @@ namespace Emby.Server.Implementations.Sorting return string.Compare(GetValue(x), GetValue(y), StringComparison.CurrentCultureIgnoreCase); } - private static string GetValue(BaseItem item) - { - var hasSeries = item as IHasSeries; - - return hasSeries != null ? hasSeries.FindSeriesSortName() : null; - } - /// /// Gets the name. /// /// The name. public string Name => ItemSortBy.SeriesSortName; + + private static string GetValue(BaseItem item) + { + var hasSeries = item as IHasSeries; + + return hasSeries?.FindSeriesSortName(); + } } } diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 69673a49c..49f8c6ace 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -165,6 +165,7 @@ namespace MediaBrowser.Api { options.ImageTypeLimit = hasDtoOptions.ImageTypeLimit.Value; } + if (hasDtoOptions.EnableUserData.HasValue) { options.EnableUserData = hasDtoOptions.EnableUserData.Value; @@ -307,7 +308,7 @@ namespace MediaBrowser.Api return pathInfo[index]; } - private string[] Parse(string pathUri) + private static string[] Parse(string pathUri) { var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None); @@ -329,38 +330,32 @@ namespace MediaBrowser.Api /// protected BaseItem GetItemByName(string name, string type, ILibraryManager libraryManager, DtoOptions dtoOptions) { - BaseItem item; - - if (type.IndexOf("Person", StringComparison.OrdinalIgnoreCase) == 0) - { - item = GetPerson(name, libraryManager, dtoOptions); - } - else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0) + if (type.Equals("Person", StringComparison.OrdinalIgnoreCase)) { - item = GetArtist(name, libraryManager, dtoOptions); + return GetPerson(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Artist", StringComparison.OrdinalIgnoreCase)) { - item = GetGenre(name, libraryManager, dtoOptions); + return GetArtist(name, libraryManager, dtoOptions); } - else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Genre", StringComparison.OrdinalIgnoreCase)) { - item = GetMusicGenre(name, libraryManager, dtoOptions); + return GetGenre(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("MusicGenre", StringComparison.OrdinalIgnoreCase)) { - item = GetStudio(name, libraryManager, dtoOptions); + return GetMusicGenre(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Studio", StringComparison.OrdinalIgnoreCase)) { - item = libraryManager.GetYear(int.Parse(name)); + return GetStudio(name, libraryManager, dtoOptions); } - else + else if (type.Equals("Year", StringComparison.OrdinalIgnoreCase)) { - throw new ArgumentException(); + return libraryManager.GetYear(int.Parse(name)); } - return item; + throw new ArgumentException("Invalid type", nameof(type)); } } } diff --git a/MediaBrowser.Api/UserLibrary/ArtistsService.cs b/MediaBrowser.Api/UserLibrary/ArtistsService.cs index 7a8455ff2..a30f8adfe 100644 --- a/MediaBrowser.Api/UserLibrary/ArtistsService.cs +++ b/MediaBrowser.Api/UserLibrary/ArtistsService.cs @@ -87,11 +87,6 @@ namespace MediaBrowser.Api.UserLibrary /// System.Object. public object Get(GetArtists request) { - if (string.IsNullOrWhiteSpace(request.IncludeItemTypes)) - { - //request.IncludeItemTypes = "Audio,MusicVideo"; - } - return GetResultSlim(request); } @@ -102,11 +97,6 @@ namespace MediaBrowser.Api.UserLibrary /// System.Object. public object Get(GetAlbumArtists request) { - if (string.IsNullOrWhiteSpace(request.IncludeItemTypes)) - { - //request.IncludeItemTypes = "Audio,MusicVideo"; - } - var result = GetResultSlim(request); return ToOptimizedResult(result); diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index f26087fda..860ea13cf 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -942,10 +942,7 @@ namespace MediaBrowser.Providers.Manager _activeRefreshes[id] = 0; } - if (RefreshStarted != null) - { - RefreshStarted(this, new GenericEventArgs(item)); - } + RefreshStarted?.Invoke(this, new GenericEventArgs(item)); } public void OnRefreshComplete(BaseItem item) @@ -956,10 +953,7 @@ namespace MediaBrowser.Providers.Manager _activeRefreshes.Remove(item.Id); } - if (RefreshCompleted != null) - { - RefreshCompleted(this, new GenericEventArgs(item)); - } + RefreshCompleted?.Invoke(this, new GenericEventArgs(item)); } public double? GetRefreshProgress(Guid id) @@ -986,10 +980,7 @@ namespace MediaBrowser.Providers.Manager { _activeRefreshes[id] = progress; - if (RefreshProgress != null) - { - RefreshProgress(this, new GenericEventArgs>(new Tuple(item, progress))); - } + RefreshProgress?.Invoke(this, new GenericEventArgs>(new Tuple(item, progress))); } else { @@ -1079,17 +1070,14 @@ namespace MediaBrowser.Providers.Manager await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); // Collection folders don't validate their children so we'll have to simulate that here - var collectionFolder = item as CollectionFolder; - if (collectionFolder != null) + if (item is CollectionFolder collectionFolder) { await RefreshCollectionFolderChildren(options, collectionFolder, cancellationToken).ConfigureAwait(false); } else { - var folder = item as Folder; - - if (folder != null) + if (item is Folder folder) { await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options).ConfigureAwait(false); } @@ -1098,16 +1086,11 @@ namespace MediaBrowser.Providers.Manager private async Task RefreshCollectionFolderChildren(MetadataRefreshOptions options, CollectionFolder collectionFolder, CancellationToken cancellationToken) { - foreach (var child in collectionFolder.GetPhysicalFolders().ToList()) + foreach (var child in collectionFolder.GetPhysicalFolders()) { await child.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); - if (child.IsFolder) - { - var folder = (Folder)child; - - await folder.ValidateChildren(new SimpleProgress(), cancellationToken, options, true).ConfigureAwait(false); - } + await child.ValidateChildren(new SimpleProgress(), cancellationToken, options, true).ConfigureAwait(false); } } @@ -1116,20 +1099,18 @@ namespace MediaBrowser.Providers.Manager var albums = _libraryManagerFactory() .GetItemList(new InternalItemsQuery { - IncludeItemTypes = new[] { typeof(MusicAlbum).Name }, + IncludeItemTypes = new[] { nameof(MusicAlbum) }, ArtistIds = new[] { item.Id }, DtoOptions = new DtoOptions(false) { EnableImages = false } }) - .OfType() - .ToList(); + .OfType(); var musicArtists = albums .Select(i => i.MusicArtist) - .Where(i => i != null) - .ToList(); + .Where(i => i != null); var musicArtistRefreshTasks = musicArtists.Select(i => i.ValidateChildren(new SimpleProgress(), cancellationToken, options, true)); diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index aee992103..f86cdeab9 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -53,7 +53,7 @@ namespace MediaBrowser.Providers.Music var releaseId = searchInfo.GetReleaseId(); var releaseGroupId = searchInfo.GetReleaseGroupId(); - string url = null; + string url; var isNameSearch = false; bool forceMusicBrainzProper = false; @@ -100,10 +100,10 @@ namespace MediaBrowser.Providers.Music } } - return new List(); + return Enumerable.Empty(); } - private List GetResultsFromResponse(Stream stream) + private IEnumerable GetResultsFromResponse(Stream stream) { using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -149,7 +149,7 @@ namespace MediaBrowser.Providers.Music return result; - }).ToList(); + }); } } } @@ -301,7 +301,7 @@ namespace MediaBrowser.Providers.Music public List> Artists = new List>(); - public static List Parse(XmlReader reader) + public static IEnumerable Parse(XmlReader reader) { reader.MoveToContent(); reader.Read(); @@ -338,13 +338,11 @@ namespace MediaBrowser.Providers.Music } } - return new List(); + return Enumerable.Empty(); } - private static List ParseReleaseList(XmlReader reader) + private static IEnumerable ParseReleaseList(XmlReader reader) { - var list = new List(); - reader.MoveToContent(); reader.Read(); @@ -369,7 +367,7 @@ namespace MediaBrowser.Providers.Music var release = ParseRelease(subReader, releaseId); if (release != null) { - list.Add(release); + yield return release; } } break; @@ -386,8 +384,6 @@ namespace MediaBrowser.Providers.Music reader.Read(); } } - - return list; } private static ReleaseResult ParseRelease(XmlReader reader, string releaseId) @@ -552,7 +548,7 @@ namespace MediaBrowser.Providers.Music return (null, null); } - private static ValueTuple ParseArtistArtistCredit(XmlReader reader, string artistId) + private static (string name, string id) ParseArtistArtistCredit(XmlReader reader, string artistId) { reader.MoveToContent(); reader.Read(); @@ -586,7 +582,7 @@ namespace MediaBrowser.Providers.Music } } - return new ValueTuple(name, artistId); + return (name, artistId); } private async Task GetReleaseIdFromReleaseGroupId(string releaseGroupId, CancellationToken cancellationToken) diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index 924b71250..55aab7778 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Music { using (var stream = response.Content) { - var results = GetResultsFromResponse(stream); + var results = GetResultsFromResponse(stream).ToList(); if (results.Count > 0) { @@ -74,10 +74,10 @@ namespace MediaBrowser.Providers.Music } } - return new List(); + return Enumerable.Empty(); } - private List GetResultsFromResponse(Stream stream) + private IEnumerable GetResultsFromResponse(Stream stream) { using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -126,15 +126,13 @@ namespace MediaBrowser.Providers.Music } } - return new List(); + return Enumerable.Empty(); } } } - private List ParseArtistList(XmlReader reader) + private IEnumerable ParseArtistList(XmlReader reader) { - var list = new List(); - reader.MoveToContent(); reader.Read(); @@ -159,7 +157,7 @@ namespace MediaBrowser.Providers.Music var artist = ParseArtist(subReader, mbzId); if (artist != null) { - list.Add(artist); + yield return artist; } } break; @@ -176,8 +174,6 @@ namespace MediaBrowser.Providers.Music reader.Read(); } } - - return list; } private RemoteSearchResult ParseArtist(XmlReader reader, string artistId) @@ -277,7 +273,7 @@ namespace MediaBrowser.Providers.Music /// /// The name. /// System.String. - private string UrlEncode(string name) + private static string UrlEncode(string name) { return WebUtility.UrlEncode(name); } -- cgit v1.2.3