From bb503638123bafb42594456fa440e71b80088fb5 Mon Sep 17 00:00:00 2001 From: bobberb Date: Sun, 17 Feb 2019 00:21:55 +0000 Subject: [PATCH 01/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json index fff1d1f0ec..0ed998c4bd 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}", From 331260cf803f7d4500d2b88eabb78be994425081 Mon Sep 17 00:00:00 2001 From: TheBird956 Date: Tue, 26 Feb 2019 03:38:39 +0000 Subject: [PATCH 02/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 52afb4e492..e434b7605b 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}", From c8788d83fbd921fccf80b7f49be83db2c73a210b Mon Sep 17 00:00:00 2001 From: TheBird956 Date: Tue, 26 Feb 2019 03:23:03 +0000 Subject: [PATCH 03/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json index 7202be9f56..4b4db39a8b 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}" } From 7c13021def4432123917b6cf18c129e19ddff756 Mon Sep 17 00:00:00 2001 From: EffeF Date: Sun, 24 Feb 2019 17:44:06 +0000 Subject: [PATCH 04/48] 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/ --- .../Localization/Core/it.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/it.json b/Emby.Server.Implementations/Localization/Core/it.json index a5f1e8f94d..357883cd37 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}" } From 311caf3fc3e45cc332e922897f963b95cb60f98a Mon Sep 17 00:00:00 2001 From: v1tin Date: Mon, 18 Feb 2019 19:02:01 +0000 Subject: [PATCH 05/48] 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/ --- .../Localization/Core/pt-BR.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/pt-BR.json b/Emby.Server.Implementations/Localization/Core/pt-BR.json index aaedf08505..dbc9c4c4b8 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}" } From d0e4e0f6004644b58cd5f64a89f82467759e5876 Mon Sep 17 00:00:00 2001 From: SaddFox Date: Tue, 26 Feb 2019 23:05:46 +0000 Subject: [PATCH 06/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/sl-SI.json b/Emby.Server.Implementations/Localization/Core/sl-SI.json index e850257d4a..b50ff4706e 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", From 53ed6e5e6efb69572a61cb57a31b600f4ba5c02b Mon Sep 17 00:00:00 2001 From: ElFantasma Date: Fri, 22 Feb 2019 18:49:18 +0000 Subject: [PATCH 07/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json index c01bb0c501..dc73ba6b34 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}" } From 3d3d879b99776e6d156773aec5693ee7c63479ea Mon Sep 17 00:00:00 2001 From: Deniz Date: Fri, 22 Feb 2019 08:15:26 +0000 Subject: [PATCH 08/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/tr.json b/Emby.Server.Implementations/Localization/Core/tr.json index 495f82db6d..9e00eba62f 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", From a9302b8b53e8393fbedeefb3be75ae6eba8ae815 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 1 Feb 2019 17:43:31 +0100 Subject: [PATCH 09/48] Remove useless abstraction around XmlReaderSettings This removes the amount of stuff that needs to be passed around Also removes some unneeded `ManagedFileSystem` usage --- .../ConnectionManager/ConnectionManager.cs | 7 +- Emby.Dlna/ConnectionManager/ControlHandler.cs | 4 +- .../ContentDirectory/ContentDirectory.cs | 11 +- Emby.Dlna/ContentDirectory/ControlHandler.cs | 19 +- Emby.Dlna/Main/DlnaEntryPoint.cs | 15 +- .../MediaReceiverRegistrar/ControlHandler.cs | 5 +- .../MediaReceiverRegistrar.cs | 7 +- Emby.Dlna/Service/BaseControlHandler.cs | 17 +- .../ApplicationHost.cs | 4 - .../Xml/XmlReaderSettingsFactory.cs | 20 - .../Parsers/BaseItemXmlParser.cs | 20 +- .../Parsers/BoxSetXmlParser.cs | 5 +- .../Parsers/PlaylistXmlParser.cs | 5 +- .../Providers/BoxSetXmlProvider.cs | 7 +- .../Providers/PlaylistXmlProvider.cs | 7 +- .../Savers/BaseXmlSaver.cs | 7 +- .../Savers/BoxSetXmlSaver.cs | 4 +- .../Savers/PlaylistXmlSaver.cs | 4 +- .../Xml/IXmlReaderSettingsFactory.cs | 9 - .../Music/MusicBrainzAlbumProvider.cs | 175 ++++---- .../Music/MusicBrainzArtistProvider.cs | 19 +- .../TV/MissingEpisodeProvider.cs | 3 - .../TV/SeriesMetadataService.cs | 4 - .../TV/TheTVDB/TvdbPrescanTask.cs | 396 ++++++++++++++++++ .../TV/TheTVDB/TvdbSeriesProvider.cs | 1 - .../Parsers/BaseNfoParser.cs | 34 +- .../Parsers/EpisodeNfoParser.cs | 5 +- .../Parsers/MovieNfoParser.cs | 19 +- .../Parsers/SeasonNfoParser.cs | 5 +- .../Parsers/SeriesNfoParser.cs | 5 +- .../Providers/AlbumNfoProvider.cs | 7 +- .../Providers/ArtistNfoProvider.cs | 7 +- .../Providers/BaseVideoNfoProvider.cs | 7 +- .../Providers/EpisodeNfoProvider.cs | 7 +- .../Providers/MovieNfoProvider.cs | 10 +- .../Providers/SeasonNfoProvider.cs | 11 +- .../Providers/SeriesNfoProvider.cs | 13 +- .../Savers/AlbumNfoSaver.cs | 4 +- .../Savers/ArtistNfoSaver.cs | 4 +- .../Savers/BaseNfoSaver.cs | 87 ++-- .../Savers/EpisodeNfoSaver.cs | 4 +- .../Savers/MovieNfoSaver.cs | 4 +- .../Savers/SeasonNfoSaver.cs | 6 +- .../Savers/SeriesNfoSaver.cs | 4 +- 44 files changed, 654 insertions(+), 364 deletions(-) delete mode 100644 Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs delete mode 100644 MediaBrowser.Model/Xml/IXmlReaderSettingsFactory.cs create mode 100644 MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs diff --git a/Emby.Dlna/ConnectionManager/ConnectionManager.cs b/Emby.Dlna/ConnectionManager/ConnectionManager.cs index cc427f2a15..679eecc891 100644 --- a/Emby.Dlna/ConnectionManager/ConnectionManager.cs +++ b/Emby.Dlna/ConnectionManager/ConnectionManager.cs @@ -3,7 +3,6 @@ using Emby.Dlna.Service; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.ConnectionManager @@ -13,15 +12,13 @@ namespace Emby.Dlna.ConnectionManager private readonly IDlnaManager _dlna; private readonly ILogger _logger; private readonly IServerConfigurationManager _config; - protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; - public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient) : base(logger, httpClient) { _dlna = dlna; _config = config; _logger = logger; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } public string GetServiceXml(IDictionary headers) @@ -34,7 +31,7 @@ namespace Emby.Dlna.ConnectionManager var profile = _dlna.GetProfile(request.Headers) ?? _dlna.GetDefaultProfile(); - return new ControlHandler(_config, _logger, XmlReaderSettingsFactory, profile).ProcessControlRequest(request); + return new ControlHandler(_config, _logger, profile).ProcessControlRequest(request); } } } diff --git a/Emby.Dlna/ConnectionManager/ControlHandler.cs b/Emby.Dlna/ConnectionManager/ControlHandler.cs index 16211c61f4..2e11047487 100644 --- a/Emby.Dlna/ConnectionManager/ControlHandler.cs +++ b/Emby.Dlna/ConnectionManager/ControlHandler.cs @@ -4,7 +4,6 @@ using Emby.Dlna.Service; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Dlna; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.ConnectionManager @@ -32,7 +31,8 @@ namespace Emby.Dlna.ConnectionManager }; } - public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory, DeviceProfile profile) : base(config, logger, xmlReaderSettingsFactory) + public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile) + : base(config, logger) { _profile = profile; } diff --git a/Emby.Dlna/ContentDirectory/ContentDirectory.cs b/Emby.Dlna/ContentDirectory/ContentDirectory.cs index b0fec90e69..3e2927845e 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectory.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectory.cs @@ -11,7 +11,6 @@ using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.ContentDirectory @@ -28,7 +27,6 @@ namespace Emby.Dlna.ContentDirectory private readonly IMediaSourceManager _mediaSourceManager; private readonly IUserViewManager _userViewManager; private readonly IMediaEncoder _mediaEncoder; - protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; private readonly ITVSeriesManager _tvSeriesManager; public ContentDirectory(IDlnaManager dlna, @@ -38,7 +36,12 @@ namespace Emby.Dlna.ContentDirectory IServerConfigurationManager config, IUserManager userManager, ILogger logger, - IHttpClient httpClient, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager) + IHttpClient httpClient, + ILocalizationManager localization, + IMediaSourceManager mediaSourceManager, + IUserViewManager userViewManager, + IMediaEncoder mediaEncoder, + ITVSeriesManager tvSeriesManager) : base(logger, httpClient) { _dlna = dlna; @@ -51,7 +54,6 @@ namespace Emby.Dlna.ContentDirectory _mediaSourceManager = mediaSourceManager; _userViewManager = userViewManager; _mediaEncoder = mediaEncoder; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; _tvSeriesManager = tvSeriesManager; } @@ -94,7 +96,6 @@ namespace Emby.Dlna.ContentDirectory _mediaSourceManager, _userViewManager, _mediaEncoder, - XmlReaderSettingsFactory, _tvSeriesManager) .ProcessControlRequest(request); } diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 84f38ff769..4f8c89e485 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -25,7 +25,6 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.ContentDirectory @@ -51,8 +50,22 @@ namespace Emby.Dlna.ContentDirectory private readonly DeviceProfile _profile; - public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, string accessToken, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IUserViewManager userViewManager, IMediaEncoder mediaEncoder, IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager) - : base(config, logger, xmlReaderSettingsFactory) + public ControlHandler( + ILogger logger, + ILibraryManager libraryManager, + DeviceProfile profile, + string serverAddress, + string accessToken, + IImageProcessor imageProcessor, + IUserDataManager userDataManager, + User user, int systemUpdateId, + IServerConfigurationManager config, + ILocalizationManager localization, + IMediaSourceManager mediaSourceManager, + IUserViewManager userViewManager, + IMediaEncoder mediaEncoder, + ITVSeriesManager tvSeriesManager) + : base(config, logger) { _libraryManager = libraryManager; _userDataManager = userDataManager; diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 57ed0097a0..1339ba9e4c 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Emby.Dlna.PlayTo; @@ -20,7 +19,6 @@ using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Net; using MediaBrowser.Model.System; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; using Rssdp; using Rssdp.Infrastructure; @@ -48,7 +46,7 @@ namespace Emby.Dlna.Main private readonly IDeviceDiscovery _deviceDiscovery; private SsdpDevicePublisher _Publisher; - + private readonly ISocketFactory _socketFactory; private readonly IEnvironmentInfo _environmentInfo; private readonly INetworkManager _networkManager; @@ -79,7 +77,6 @@ namespace Emby.Dlna.Main IEnvironmentInfo environmentInfo, INetworkManager networkManager, IUserViewManager userViewManager, - IXmlReaderSettingsFactory xmlReaderSettingsFactory, ITVSeriesManager tvSeriesManager) { _config = config; @@ -100,7 +97,8 @@ namespace Emby.Dlna.Main _networkManager = networkManager; _logger = loggerFactory.CreateLogger("Dlna"); - ContentDirectory = new ContentDirectory.ContentDirectory(dlnaManager, + ContentDirectory = new ContentDirectory.ContentDirectory( + dlnaManager, userDataManager, imageProcessor, libraryManager, @@ -112,12 +110,11 @@ namespace Emby.Dlna.Main mediaSourceManager, userViewManager, mediaEncoder, - xmlReaderSettingsFactory, tvSeriesManager); - ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient, xmlReaderSettingsFactory); + ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient); - MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config, xmlReaderSettingsFactory); + MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config); Current = this; } @@ -260,7 +257,7 @@ namespace Emby.Dlna.Main var fullService = "urn:schemas-upnp-org:device:MediaServer:1"; - _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address); + _logger.LogInformation("Registering publisher for {0} on {1}", fullService, address.ToString()); var descriptorUri = "/dlna/" + udn + "/description.xml"; var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri); diff --git a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs index ae8175f4a2..7381e52582 100644 --- a/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs +++ b/Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using Emby.Dlna.Service; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.MediaReceiverRegistrar @@ -36,8 +35,8 @@ namespace Emby.Dlna.MediaReceiverRegistrar }; } - public ControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) - : base(config, logger, xmlReaderSettingsFactory) + public ControlHandler(IServerConfigurationManager config, ILogger logger) + : base(config, logger) { } } diff --git a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs index 2b84528eab..eeae3acb6f 100644 --- a/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs +++ b/Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using Emby.Dlna.Service; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.MediaReceiverRegistrar @@ -10,13 +9,11 @@ namespace Emby.Dlna.MediaReceiverRegistrar public class MediaReceiverRegistrar : BaseService, IMediaReceiverRegistrar { private readonly IServerConfigurationManager _config; - protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; - public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config) : base(logger, httpClient) { _config = config; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } public string GetServiceXml(IDictionary headers) @@ -28,7 +25,7 @@ namespace Emby.Dlna.MediaReceiverRegistrar { return new ControlHandler( _config, - Logger, XmlReaderSettingsFactory) + Logger) .ProcessControlRequest(request); } } diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 5f78674b88..067d5fa43f 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -7,7 +7,6 @@ using System.Xml; using Emby.Dlna.Didl; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Extensions; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace Emby.Dlna.Service @@ -18,13 +17,11 @@ namespace Emby.Dlna.Service protected readonly IServerConfigurationManager Config; protected readonly ILogger _logger; - protected readonly IXmlReaderSettingsFactory XmlReaderSettingsFactory; - protected BaseControlHandler(IServerConfigurationManager config, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + protected BaseControlHandler(IServerConfigurationManager config, ILogger logger) { Config = config; _logger = logger; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } public ControlResponse ProcessControlRequest(ControlRequest request) @@ -61,11 +58,13 @@ namespace Emby.Dlna.Service using (var streamReader = new StreamReader(request.InputXml)) { - var readerSettings = XmlReaderSettingsFactory.Create(false); - - readerSettings.CheckCharacters = false; - readerSettings.IgnoreProcessingInstructions = true; - readerSettings.IgnoreComments = true; + var readerSettings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; using (var reader = XmlReader.Create(streamReader, readerSettings)) { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index b3bb4f740e..ec1ad6dbdf 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -44,7 +44,6 @@ using Emby.Server.Implementations.Serialization; using Emby.Server.Implementations.Session; using Emby.Server.Implementations.TV; using Emby.Server.Implementations.Updates; -using Emby.Server.Implementations.Xml; using MediaBrowser.Api; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; @@ -98,7 +97,6 @@ using MediaBrowser.Model.Services; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Updates; -using MediaBrowser.Model.Xml; using MediaBrowser.Providers.Chapters; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Subtitles; @@ -691,8 +689,6 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(new BdInfoExaminer(FileSystemManager)); - serviceCollection.AddSingleton(new XmlReaderSettingsFactory()); - UserDataManager = new UserDataManager(LoggerFactory, ServerConfigurationManager, () => UserManager); serviceCollection.AddSingleton(UserDataManager); diff --git a/Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs b/Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs deleted file mode 100644 index 308922e6d1..0000000000 --- a/Emby.Server.Implementations/Xml/XmlReaderSettingsFactory.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Xml; -using MediaBrowser.Model.Xml; - -namespace Emby.Server.Implementations.Xml -{ - public class XmlReaderSettingsFactory : IXmlReaderSettingsFactory - { - public XmlReaderSettings Create(bool enableValidation) - { - var settings = new XmlReaderSettings(); - - if (!enableValidation) - { - settings.ValidationType = ValidationType.None; - } - - return settings; - } - } -} diff --git a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs index 38458e34c8..23b9745769 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BaseItemXmlParser.cs @@ -10,7 +10,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Parsers @@ -30,19 +29,14 @@ namespace MediaBrowser.LocalMetadata.Parsers private Dictionary _validProviderIds; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - protected IFileSystem FileSystem { get; private set; } - /// /// Initializes a new instance of the class. /// /// The logger. - public BaseItemXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) + public BaseItemXmlParser(ILogger logger, IProviderManager providerManager) { Logger = logger; ProviderManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; - FileSystem = fileSystem; } /// @@ -64,11 +58,13 @@ namespace MediaBrowser.LocalMetadata.Parsers throw new ArgumentException("The metadata file was empty or null.", nameof(metadataFile)); } - var settings = XmlReaderSettingsFactory.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; _validProviderIds = _validProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); diff --git a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs index e595e9d068..127334625d 100644 --- a/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/BoxSetXmlParser.cs @@ -3,8 +3,6 @@ using System.Xml; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Parsers @@ -87,7 +85,8 @@ namespace MediaBrowser.LocalMetadata.Parsers item.Item.LinkedChildren = list.ToArray(); } - public BoxSetXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + public BoxSetXmlParser(ILogger logger, IProviderManager providerManager) + : base(logger, providerManager) { } } diff --git a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs index ff69cb0237..5608a0be90 100644 --- a/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs +++ b/MediaBrowser.LocalMetadata/Parsers/PlaylistXmlParser.cs @@ -3,8 +3,6 @@ using System.Xml; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Parsers @@ -95,7 +93,8 @@ namespace MediaBrowser.LocalMetadata.Parsers item.LinkedChildren = list.ToArray(); } - public PlaylistXmlParser(ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, IFileSystem fileSystem) : base(logger, providerManager, xmlReaderSettingsFactory, fileSystem) + public PlaylistXmlParser(ILogger logger, IProviderManager providerManager) + : base(logger, providerManager) { } } diff --git a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs index 539f818c65..2e303efab6 100644 --- a/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/BoxSetXmlProvider.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Providers @@ -16,19 +15,17 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public BoxSetXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) { - new BoxSetXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); + new BoxSetXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs index 442a18cb98..d111ae9ba8 100644 --- a/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs +++ b/MediaBrowser.LocalMetadata/Providers/PlaylistXmlProvider.cs @@ -4,7 +4,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.LocalMetadata.Parsers; using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Providers @@ -13,19 +12,17 @@ namespace MediaBrowser.LocalMetadata.Providers { private readonly ILogger _logger; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public PlaylistXmlProvider(IFileSystem fileSystem, ILogger logger, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) { - new PlaylistXmlParser(_logger, _providerManager, XmlReaderSettingsFactory, FileSystem).Fetch(result, path, cancellationToken); + new PlaylistXmlParser(_logger, _providerManager).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs index 438b842525..30a33b729a 100644 --- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs @@ -14,7 +14,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Savers @@ -23,7 +22,7 @@ namespace MediaBrowser.LocalMetadata.Savers { private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) { FileSystem = fileSystem; ConfigurationManager = configurationManager; @@ -31,7 +30,6 @@ namespace MediaBrowser.LocalMetadata.Savers UserManager = userManager; UserDataManager = userDataManager; Logger = logger; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected IFileSystem FileSystem { get; private set; } @@ -40,9 +38,6 @@ namespace MediaBrowser.LocalMetadata.Savers protected IUserManager UserManager { get; private set; } protected IUserDataManager UserDataManager { get; private set; } protected ILogger Logger { get; private set; } - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - - protected ItemUpdateType MinimumUpdateType => ItemUpdateType.MetadataDownload; public string Name => XmlProviderUtils.Name; diff --git a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs index b4d5440a52..ea939e33b1 100644 --- a/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/BoxSetXmlSaver.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Savers @@ -31,7 +30,8 @@ namespace MediaBrowser.LocalMetadata.Savers return Path.Combine(item.Path, "collection.xml"); } - public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) + : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) { } } diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs index 09bb6d8f72..35a431fa48 100644 --- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs +++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs @@ -5,7 +5,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.LocalMetadata.Savers @@ -49,7 +48,8 @@ namespace MediaBrowser.LocalMetadata.Savers return Path.Combine(path, "playlist.xml"); } - public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger, xmlReaderSettingsFactory) + public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger) + : base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger) { } } diff --git a/MediaBrowser.Model/Xml/IXmlReaderSettingsFactory.cs b/MediaBrowser.Model/Xml/IXmlReaderSettingsFactory.cs deleted file mode 100644 index b39325958b..0000000000 --- a/MediaBrowser.Model/Xml/IXmlReaderSettingsFactory.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Xml; - -namespace MediaBrowser.Model.Xml -{ - public interface IXmlReaderSettingsFactory - { - XmlReaderSettings Create(bool enableValidation); - } -} diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index e4bb52217c..335f2c5395 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -15,7 +15,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Music @@ -28,17 +27,15 @@ namespace MediaBrowser.Providers.Music private readonly IApplicationHost _appHost; private readonly ILogger _logger; private readonly IJsonSerializer _json; - private readonly IXmlReaderSettingsFactory _xmlSettings; public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org"; - public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json, IXmlReaderSettingsFactory xmlSettings) + public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json) { _httpClient = httpClient; _appHost = appHost; _logger = logger; _json = json; - _xmlSettings = xmlSettings; Current = this; } @@ -101,11 +98,13 @@ namespace MediaBrowser.Providers.Music { using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; using (var reader = XmlReader.Create(oReader, settings)) { @@ -240,22 +239,20 @@ namespace MediaBrowser.Providers.Music artistId); using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = response.Content) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - using (var stream = response.Content) + var settings = new XmlReaderSettings() { - using (var oReader = new StreamReader(stream, Encoding.UTF8)) - { - var settings = _xmlSettings.Create(false); + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - using (var reader = XmlReader.Create(oReader, settings)) - { - return ReleaseResult.Parse(reader).FirstOrDefault(); - } - } + using (var reader = XmlReader.Create(oReader, settings)) + { + return ReleaseResult.Parse(reader).FirstOrDefault(); } } } @@ -267,22 +264,20 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(artistName)); using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var stream = response.Content) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - using (var stream = response.Content) + var settings = new XmlReaderSettings() { - using (var oReader = new StreamReader(stream, Encoding.UTF8)) - { - var settings = _xmlSettings.Create(false); + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - using (var reader = XmlReader.Create(oReader, settings)) - { - return ReleaseResult.Parse(reader).FirstOrDefault(); - } - } + using (var reader = XmlReader.Create(oReader, settings)) + { + return ReleaseResult.Parse(reader).FirstOrDefault(); } } } @@ -590,26 +585,24 @@ namespace MediaBrowser.Providers.Music var url = string.Format("/ws/2/release?release-group={0}", releaseGroupId); using (var response = await GetMusicBrainzResponse(url, true, true, cancellationToken).ConfigureAwait(false)) + using (var stream = response.Content) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - using (var stream = response.Content) + var settings = new XmlReaderSettings() { - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; + + using (var reader = XmlReader.Create(oReader, settings)) + { + var result = ReleaseResult.Parse(reader).FirstOrDefault(); + + if (result != null) { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - using (var reader = XmlReader.Create(oReader, settings)) - { - var result = ReleaseResult.Parse(reader).FirstOrDefault(); - - if (result != null) - { - return result.ReleaseId; - } - } + return result.ReleaseId; } } } @@ -628,56 +621,54 @@ namespace MediaBrowser.Providers.Music var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId); using (var response = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false)) + using (var stream = response.Content) + using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - using (var stream = response.Content) + var settings = new XmlReaderSettings() { - using (var oReader = new StreamReader(stream, Encoding.UTF8)) + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; + + using (var reader = XmlReader.Create(oReader, settings)) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - - using (var reader = XmlReader.Create(oReader, settings)) + if (reader.NodeType == XmlNodeType.Element) { - reader.MoveToContent(); - reader.Read(); - - // Loop through each element - while (!reader.EOF && reader.ReadState == ReadState.Interactive) + switch (reader.Name) { - if (reader.NodeType == XmlNodeType.Element) - { - switch (reader.Name) + case "release-group-list": { - case "release-group-list": - { - if (reader.IsEmptyElement) - { - reader.Read(); - continue; - } - using (var subReader = reader.ReadSubtree()) - { - return GetFirstReleaseGroupId(subReader); - } - } - default: - { - reader.Skip(); - break; - } + if (reader.IsEmptyElement) + { + reader.Read(); + continue; + } + using (var subReader = reader.ReadSubtree()) + { + return GetFirstReleaseGroupId(subReader); + } + } + default: + { + reader.Skip(); + break; } - } - else - { - reader.Read(); - } } - return null; + } + else + { + reader.Read(); } } + return null; } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index 8d10834c32..924b712507 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -13,17 +13,14 @@ using MediaBrowser.Controller.Extensions; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Xml; namespace MediaBrowser.Providers.Music { public class MusicBrainzArtistProvider : IRemoteMetadataProvider { - private readonly IXmlReaderSettingsFactory _xmlSettings; - - public MusicBrainzArtistProvider(IXmlReaderSettingsFactory xmlSettings) + public MusicBrainzArtistProvider() { - _xmlSettings = xmlSettings; + } public async Task> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken) @@ -84,11 +81,13 @@ namespace MediaBrowser.Providers.Music { using (var oReader = new StreamReader(stream, Encoding.UTF8)) { - var settings = _xmlSettings.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; using (var reader = XmlReader.Create(oReader, settings)) { diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 0a2975e0f9..752c0941d0 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; -using System.Xml; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index afbd838e4b..d5b0b6fd89 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -8,7 +8,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.TV.TheTVDB; using Microsoft.Extensions.Logging; @@ -18,7 +17,6 @@ namespace MediaBrowser.Providers.TV public class SeriesMetadataService : MetadataService { private readonly ILocalizationManager _localization; - private readonly IXmlReaderSettingsFactory _xmlSettings; private readonly TvDbClientManager _tvDbClientManager; public SeriesMetadataService( @@ -29,13 +27,11 @@ namespace MediaBrowser.Providers.TV IUserDataManager userDataManager, ILibraryManager libraryManager, ILocalizationManager localization, - IXmlReaderSettingsFactory xmlSettings, TvDbClientManager tvDbClientManager ) : base(serverConfigurationManager, logger, providerManager, fileSystem, userDataManager, libraryManager) { _localization = localization; - _xmlSettings = xmlSettings; _tvDbClientManager = tvDbClientManager; } diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs new file mode 100644 index 0000000000..c8ae585740 --- /dev/null +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbPrescanTask.cs @@ -0,0 +1,396 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; +using MediaBrowser.Providers.TV.TheTVDB; +using Microsoft.Extensions.Logging; + +namespace MediaBrowser.Providers.TV +{ + /// + /// Class TvdbPrescanTask + /// + public class TvdbPrescanTask : ILibraryPostScanTask + { + public const string TvdbBaseUrl = "https://thetvdb.com/"; + + /// + /// The server time URL + /// + private const string ServerTimeUrl = TvdbBaseUrl + "api/Updates.php?type=none"; + + /// + /// The updates URL + /// + private const string UpdatesUrl = TvdbBaseUrl + "api/Updates.php?type=all&time={0}"; + + /// + /// The _HTTP client + /// + private readonly IHttpClient _httpClient; + /// + /// The _logger + /// + private readonly ILogger _logger; + /// + /// The _config + /// + private readonly IServerConfigurationManager _config; + private readonly IFileSystem _fileSystem; + private readonly ILibraryManager _libraryManager; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The HTTP client. + /// The config. + public TvdbPrescanTask(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config, IFileSystem fileSystem, ILibraryManager libraryManager) + { + _logger = logger; + _httpClient = httpClient; + _config = config; + _fileSystem = fileSystem; + _libraryManager = libraryManager; + } + + protected readonly CultureInfo UsCulture = new CultureInfo("en-US"); + + /// + /// Runs the specified progress. + /// + /// The progress. + /// The cancellation token. + /// Task. + public async Task Run(IProgress progress, CancellationToken cancellationToken) + { + var path = TvdbSeriesProvider.GetSeriesDataPath(_config.CommonApplicationPaths); + + Directory.CreateDirectory(path); + + var timestampFile = Path.Combine(path, "time.txt"); + + var timestampFileInfo = _fileSystem.GetFileInfo(timestampFile); + + // Don't check for tvdb updates anymore frequently than 24 hours + if (timestampFileInfo.Exists && (DateTime.UtcNow - _fileSystem.GetLastWriteTimeUtc(timestampFileInfo)).TotalDays < 1) + { + return; + } + + // Find out the last time we queried tvdb for updates + var lastUpdateTime = timestampFileInfo.Exists ? File.ReadAllText(timestampFile, Encoding.UTF8) : string.Empty; + + string newUpdateTime; + + var existingDirectories = _fileSystem.GetDirectoryPaths(path) + .Select(Path.GetFileName) + .ToList(); + + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true, + GroupByPresentationUniqueKey = false, + DtoOptions = new DtoOptions(false) + { + EnableImages = false + } + + }).Cast() + .ToList(); + + var seriesIdsInLibrary = seriesList + .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb))) + .Select(i => i.GetProviderId(MetadataProviders.Tvdb)) + .ToList(); + + var missingSeries = seriesIdsInLibrary.Except(existingDirectories, StringComparer.OrdinalIgnoreCase) + .ToList(); + + var enableInternetProviders = seriesList.Count == 0 ? false : seriesList[0].IsMetadataFetcherEnabled(_libraryManager.GetLibraryOptions(seriesList[0]), TvdbSeriesProvider.Current.Name); + if (!enableInternetProviders) + { + progress.Report(100); + return; + } + + // If this is our first time, update all series + if (string.IsNullOrEmpty(lastUpdateTime)) + { + // First get tvdb server time + using (var response = await _httpClient.SendAsync(new HttpRequestOptions + { + Url = ServerTimeUrl, + CancellationToken = cancellationToken, + EnableHttpCompression = true, + BufferContent = false + + }, "GET").ConfigureAwait(false)) + { + // First get tvdb server time + using (var stream = response.Content) + { + newUpdateTime = GetUpdateTime(stream); + } + } + + existingDirectories.AddRange(missingSeries); + + await UpdateSeries(existingDirectories, path, null, progress, cancellationToken).ConfigureAwait(false); + } + else + { + var seriesToUpdate = await GetSeriesIdsToUpdate(existingDirectories, lastUpdateTime, cancellationToken).ConfigureAwait(false); + + newUpdateTime = seriesToUpdate.Item2; + + long.TryParse(lastUpdateTime, NumberStyles.Any, UsCulture, out var lastUpdateValue); + + var nullableUpdateValue = lastUpdateValue == 0 ? (long?)null : lastUpdateValue; + + var listToUpdate = seriesToUpdate.Item1.ToList(); + listToUpdate.AddRange(missingSeries); + + await UpdateSeries(listToUpdate, path, nullableUpdateValue, progress, cancellationToken).ConfigureAwait(false); + } + + File.WriteAllText(timestampFile, newUpdateTime, Encoding.UTF8); + progress.Report(100); + } + + /// + /// Gets the update time. + /// + /// The response. + /// System.String. + private string GetUpdateTime(Stream response) + { + // Use XmlReader for best performance + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; + + using (var streamReader = new StreamReader(response, Encoding.UTF8)) + using (var reader = XmlReader.Create(streamReader, settings)) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Time": + { + return (reader.ReadElementContentAsString() ?? string.Empty).Trim(); + } + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + return null; + } + + /// + /// Gets the series ids to update. + /// + /// The existing series ids. + /// The last update time. + /// The cancellation token. + /// Task{IEnumerable{System.String}}. + private async Task, string>> GetSeriesIdsToUpdate(IEnumerable existingSeriesIds, string lastUpdateTime, CancellationToken cancellationToken) + { + // First get last time + using (var response = await _httpClient.SendAsync(new HttpRequestOptions + { + Url = string.Format(UpdatesUrl, lastUpdateTime), + CancellationToken = cancellationToken, + EnableHttpCompression = true, + BufferContent = false + + }, "GET").ConfigureAwait(false)) + { + using (var stream = response.Content) + { + var data = GetUpdatedSeriesIdList(stream); + + var existingDictionary = existingSeriesIds.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + + var seriesList = data.ids + .Where(i => !string.IsNullOrWhiteSpace(i) && existingDictionary.ContainsKey(i)); + + return new Tuple, string>(seriesList, data.updateTime); + } + } + } + + private (List ids, string updateTime) GetUpdatedSeriesIdList(Stream stream) + { + string updateTime = null; + var idList = new List(); + + // Use XmlReader for best performance + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; + + using (var streamReader = new StreamReader(stream, Encoding.UTF8)) + using (var reader = XmlReader.Create(streamReader, settings)) + { + reader.MoveToContent(); + reader.Read(); + + // Loop through each element + while (!reader.EOF && reader.ReadState == ReadState.Interactive) + { + if (reader.NodeType == XmlNodeType.Element) + { + switch (reader.Name) + { + case "Time": + { + updateTime = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); + break; + } + case "Series": + { + var id = (reader.ReadElementContentAsString() ?? string.Empty).Trim(); + idList.Add(id); + break; + } + default: + reader.Skip(); + break; + } + } + else + { + reader.Read(); + } + } + } + + return (idList, updateTime); + } + + /// + /// Updates the series. + /// + /// The series ids. + /// The series data path. + /// The last tv db update time. + /// The progress. + /// The cancellation token. + /// Task. + private async Task UpdateSeries(List seriesIds, string seriesDataPath, long? lastTvDbUpdateTime, IProgress progress, CancellationToken cancellationToken) + { + var numComplete = 0; + + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true, + GroupByPresentationUniqueKey = false, + DtoOptions = new DtoOptions(false) + { + EnableImages = false + } + + }).Cast(); + + // Gather all series into a lookup by tvdb id + var allSeries = seriesList + .Where(i => !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb))) + .ToLookup(i => i.GetProviderId(MetadataProviders.Tvdb)); + + foreach (var seriesId in seriesIds) + { + // Find the preferred language(s) for the movie in the library + var languages = allSeries[seriesId] + .Select(i => i.GetPreferredMetadataLanguage()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var language in languages) + { + try + { + await UpdateSeries(seriesId, seriesDataPath, lastTvDbUpdateTime, language, cancellationToken).ConfigureAwait(false); + } + catch (HttpException ex) + { + _logger.LogError(ex, "Error updating tvdb series id {ID}, language {Language}", seriesId, language); + + // Already logged at lower levels, but don't fail the whole operation, unless timed out + // We have to fail this to make it run again otherwise new episode data could potentially be missing + if (ex.IsTimedOut) + { + throw; + } + } + } + + numComplete++; + double percent = numComplete; + percent /= seriesIds.Count; + percent *= 100; + + progress.Report(percent); + } + } + + /// + /// Updates the series. + /// + /// The id. + /// The series data path. + /// The last tv db update time. + /// The preferred metadata language. + /// The cancellation token. + /// Task. + private Task UpdateSeries(string id, string seriesDataPath, long? lastTvDbUpdateTime, string preferredMetadataLanguage, CancellationToken cancellationToken) + { + _logger.LogInformation("Updating series from tvdb " + id + ", language " + preferredMetadataLanguage); + + seriesDataPath = Path.Combine(seriesDataPath, id); + + Directory.CreateDirectory(seriesDataPath); + + return TvdbSeriesProvider.Current.DownloadSeriesZip(id, MetadataProviders.Tvdb.ToString(), null, null, seriesDataPath, lastTvDbUpdateTime, preferredMetadataLanguage, cancellationToken); + } + } +} diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs index 9c24e4c987..09b056c0cb 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbSeriesProvider.cs @@ -23,7 +23,6 @@ namespace MediaBrowser.Providers.TV.TheTVDB { internal static TvdbSeriesProvider Current { get; private set; } private readonly IHttpClient _httpClient; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localizationManager; diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs index f20dbbb6ea..aa5313eb72 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs @@ -13,8 +13,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Extensions; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.XbmcMetadata.Configuration; using MediaBrowser.XbmcMetadata.Savers; using Microsoft.Extensions.Logging; @@ -28,9 +26,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers /// The logger /// protected ILogger Logger { get; private set; } - protected IFileSystem FileSystem { get; private set; } protected IProviderManager ProviderManager { get; private set; } - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } private readonly CultureInfo _usCulture = new CultureInfo("en-US"); private readonly IConfigurationManager _config; @@ -39,13 +35,11 @@ namespace MediaBrowser.XbmcMetadata.Parsers /// /// Initializes a new instance of the class. /// - public BaseNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public BaseNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) { Logger = logger; _config = config; ProviderManager = providerManager; - FileSystem = fileSystem; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } /// @@ -68,11 +62,13 @@ namespace MediaBrowser.XbmcMetadata.Parsers throw new ArgumentException("The metadata file was empty or null.", nameof(metadataFile)); } - var settings = XmlReaderSettingsFactory.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; _validProviderIds = _validProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -935,19 +931,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers value = value.Trim().Trim(separator); - return string.IsNullOrWhiteSpace(value) ? Array.Empty() : Split(value, separator, StringSplitOptions.RemoveEmptyEntries); - } - - /// - /// Provides an additional overload for string.split - /// - /// The val. - /// The separators. - /// The options. - /// System.String[][]. - private string[] Split(string val, char[] separators, StringSplitOptions options) - { - return val.Split(separators, options); + return string.IsNullOrWhiteSpace(value) ? Array.Empty() : value.Split(separator, StringSplitOptions.RemoveEmptyEntries); } } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs index a8cb6ac40d..7f68ba256e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs @@ -8,8 +8,6 @@ using System.Xml; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Parsers @@ -220,7 +218,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers } } - public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(logger, config, providerManager, fileSystem, xmlReaderSettingsFactory) + public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(logger, config, providerManager) { } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs index a3e48d30d9..526cc62b0e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs @@ -7,8 +7,6 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Parsers @@ -124,14 +122,16 @@ namespace MediaBrowser.XbmcMetadata.Parsers using (var stringReader = new StringReader("" + xml + "")) { // These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions + var settings = new XmlReaderSettings() + { + ValidationType = ValidationType.None, + CheckCharacters = false, + IgnoreProcessingInstructions = true, + IgnoreComments = true + }; + try { - var settings = XmlReaderSettingsFactory.Create(false); - - settings.CheckCharacters = false; - settings.IgnoreProcessingInstructions = true; - settings.IgnoreComments = true; - // Use XmlReader for best performance using (var reader = XmlReader.Create(stringReader, settings)) { @@ -167,7 +167,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers } } - public MovieNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(logger, config, providerManager, fileSystem, xmlReaderSettingsFactory) + public MovieNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(logger, config, providerManager) { } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs index 17f36d82d7..882f3a9d3a 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs @@ -3,8 +3,6 @@ using System.Xml; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Parsers @@ -42,7 +40,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers } } - public SeasonNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(logger, config, providerManager, fileSystem, xmlReaderSettingsFactory) + public SeasonNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(logger, config, providerManager) { } } diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs index 700656b652..b0f25ae64e 100644 --- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs +++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs @@ -5,8 +5,6 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Parsers @@ -94,7 +92,8 @@ namespace MediaBrowser.XbmcMetadata.Parsers } } - public SeriesNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager, IFileSystem fileSystem, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(logger, config, providerManager, fileSystem, xmlReaderSettingsFactory) + public SeriesNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(logger, config, providerManager) { } } diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs index 1e22bf3582..6e6a22794d 100644 --- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs @@ -4,7 +4,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.XbmcMetadata.Parsers; using Microsoft.Extensions.Logging; @@ -15,20 +14,18 @@ namespace MediaBrowser.XbmcMetadata.Providers private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public AlbumNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public AlbumNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _config = config; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) { - new BaseNfoParser(_logger, _config, _providerManager, FileSystem, XmlReaderSettingsFactory).Fetch(result, path, cancellationToken); + new BaseNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs index ad811b4754..20abfc7f3a 100644 --- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs @@ -4,7 +4,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.XbmcMetadata.Parsers; using Microsoft.Extensions.Logging; @@ -15,20 +14,18 @@ namespace MediaBrowser.XbmcMetadata.Providers private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public ArtistNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public ArtistNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _config = config; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) { - new BaseNfoParser(_logger, _config, _providerManager, FileSystem, XmlReaderSettingsFactory).Fetch(result, path, cancellationToken); + new BaseNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken); } protected override FileSystemMetadata GetXmlFile(ItemInfo info, IDirectoryService directoryService) diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs index 94f104f61b..28a0514d57 100644 --- a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs @@ -4,7 +4,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.XbmcMetadata.Parsers; using MediaBrowser.XbmcMetadata.Savers; using Microsoft.Extensions.Logging; @@ -17,15 +16,13 @@ namespace MediaBrowser.XbmcMetadata.Providers private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public BaseVideoNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public BaseVideoNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _config = config; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) @@ -34,7 +31,7 @@ namespace MediaBrowser.XbmcMetadata.Providers { Item = result.Item }; - new MovieNfoParser(_logger, _config, _providerManager, FileSystem, XmlReaderSettingsFactory).Fetch(tmpItem, path, cancellationToken); + new MovieNfoParser(_logger, _config, _providerManager).Fetch(tmpItem, path, cancellationToken); result.Item = (T)tmpItem.Item; result.People = tmpItem.People; diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs index bf05f0f38b..f90f283cf3 100644 --- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs @@ -5,7 +5,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using MediaBrowser.XbmcMetadata.Parsers; using Microsoft.Extensions.Logging; @@ -16,22 +15,20 @@ namespace MediaBrowser.XbmcMetadata.Providers private readonly ILogger _logger; private readonly IConfigurationManager _config; private readonly IProviderManager _providerManager; - protected IXmlReaderSettingsFactory XmlReaderSettingsFactory { get; private set; } - public EpisodeNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) + public EpisodeNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) : base(fileSystem) { _logger = logger; _config = config; _providerManager = providerManager; - XmlReaderSettingsFactory = xmlReaderSettingsFactory; } protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken) { var images = new List(); - new EpisodeNfoParser(_logger, _config, _providerManager, FileSystem, XmlReaderSettingsFactory).Fetch(result, images, path, cancellationToken); + new EpisodeNfoParser(_logger, _config, _providerManager).Fetch(result, images, path, cancellationToken); result.Images = images; } diff --git a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs index 77b3b3781b..d21164c022 100644 --- a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs +++ b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs @@ -3,28 +3,30 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; namespace MediaBrowser.XbmcMetadata.Providers { public class MovieNfoProvider : BaseVideoNfoProvider { - public MovieNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, logger, config, providerManager, xmlReaderSettingsFactory) + public MovieNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(fileSystem, logger, config, providerManager) { } } public class MusicVideoNfoProvider : BaseVideoNfoProvider { - public MusicVideoNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory) : base(fileSystem, logger, config, providerManager, xmlReaderSettingsFactory) + public MusicVideoNfoProvider(IFileSystem fileSystem, ILogger logger, IConfigurationManager config, IProviderManager providerManager) + : base(fileSystem, logger, config, providerManager) { } } public class VideoNfoProvider : BaseVideoNfoProvider public class TypeMapper { - private readonly IAssemblyInfo _assemblyInfo; - /// /// This holds all the types in the running assemblies so that we can de-serialize properly when we don't have strong types /// private readonly ConcurrentDictionary _typeMap = new ConcurrentDictionary(); - public TypeMapper(IAssemblyInfo assemblyInfo) + public TypeMapper() { - _assemblyInfo = assemblyInfo; } /// @@ -45,8 +41,7 @@ namespace Emby.Server.Implementations.Data /// Type. private Type LookupType(string typeName) { - return _assemblyInfo - .GetCurrentAssemblies() + return AppDomain.CurrentDomain.GetAssemblies() .Select(a => a.GetType(typeName)) .FirstOrDefault(t => t != null); } diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs index fceb82ba19..f4eddb08ba 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs @@ -33,7 +33,6 @@ using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Querying; -using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; @@ -58,7 +57,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV private readonly IProviderManager _providerManager; private readonly IMediaEncoder _mediaEncoder; private readonly IProcessFactory _processFactory; - private readonly IAssemblyInfo _assemblyInfo; private IMediaSourceManager _mediaSourceManager; public static EmbyTV Current; @@ -74,7 +72,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV public EmbyTV(IServerApplicationHost appHost, IStreamHelper streamHelper, IMediaSourceManager mediaSourceManager, - IAssemblyInfo assemblyInfo, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, @@ -101,7 +98,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _processFactory = processFactory; _liveTvManager = (LiveTvManager)liveTvManager; _jsonSerializer = jsonSerializer; - _assemblyInfo = assemblyInfo; _mediaSourceManager = mediaSourceManager; _streamHelper = streamHelper; diff --git a/Emby.Server.Implementations/Reflection/AssemblyInfo.cs b/Emby.Server.Implementations/Reflection/AssemblyInfo.cs deleted file mode 100644 index 9d16fe43f6..0000000000 --- a/Emby.Server.Implementations/Reflection/AssemblyInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.IO; -using System.Reflection; -using MediaBrowser.Model.Reflection; - -namespace Emby.Server.Implementations.Reflection -{ - public class AssemblyInfo : IAssemblyInfo - { - public Stream GetManifestResourceStream(Type type, string resource) - { - return type.Assembly.GetManifestResourceStream(resource); - } - - public string[] GetManifestResourceNames(Type type) - { - return type.Assembly.GetManifestResourceNames(); - } - - public Assembly[] GetCurrentAssemblies() - { - return AppDomain.CurrentDomain.GetAssemblies(); - } - } -} diff --git a/MediaBrowser.Model/Reflection/IAssemblyInfo.cs b/MediaBrowser.Model/Reflection/IAssemblyInfo.cs deleted file mode 100644 index 5c4536c1c1..0000000000 --- a/MediaBrowser.Model/Reflection/IAssemblyInfo.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace MediaBrowser.Model.Reflection -{ - public interface IAssemblyInfo - { - Stream GetManifestResourceStream(Type type, string resource); - string[] GetManifestResourceNames(Type type); - - Assembly[] GetCurrentAssemblies(); - } -} diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 531978e1dd..aa0208495b 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -13,7 +13,6 @@ using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Plugins; -using MediaBrowser.Model.Reflection; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; @@ -117,20 +116,26 @@ namespace MediaBrowser.WebDashboard.Api private readonly IFileSystem _fileSystem; private readonly ILocalizationManager _localization; private readonly IJsonSerializer _jsonSerializer; - private readonly IAssemblyInfo _assemblyInfo; private IResourceFileManager _resourceFileManager; /// /// Initializes a new instance of the class. /// - public DashboardService(IServerApplicationHost appHost, IResourceFileManager resourceFileManager, IServerConfigurationManager serverConfigurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, IAssemblyInfo assemblyInfo, ILogger logger, IHttpResultFactory resultFactory) + public DashboardService( + IServerApplicationHost appHost, + IResourceFileManager resourceFileManager, + IServerConfigurationManager serverConfigurationManager, + IFileSystem fileSystem, + ILocalizationManager localization, + IJsonSerializer jsonSerializer, + ILogger logger, + IHttpResultFactory resultFactory) { _appHost = appHost; _serverConfigurationManager = serverConfigurationManager; _fileSystem = fileSystem; _localization = localization; _jsonSerializer = jsonSerializer; - _assemblyInfo = assemblyInfo; _logger = logger; _resultFactory = resultFactory; _resourceFileManager = resourceFileManager; @@ -187,7 +192,7 @@ namespace MediaBrowser.WebDashboard.Api if (altPage != null) { plugin = altPage.Item2; - stream = _assemblyInfo.GetManifestResourceStream(plugin.GetType(), altPage.Item1.EmbeddedResourcePath); + stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath); isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase); isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html"); From 620d7b560d0b72f532d96a5b459f14fd4ad3044a Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Thu, 28 Feb 2019 22:33:20 +0100 Subject: [PATCH 12/48] Fail on warnings for Jellyfin.Server --- .../Activity/ActivityLogEntryPoint.cs | 181 +++++++----------- .../Emby.Server.Implementations.csproj | 15 ++ .../SocketSharp/HttpPostedFile.cs | 44 ++--- Jellyfin.Server/Jellyfin.Server.csproj | 7 +- jellyfin.ruleset | 5 + 5 files changed, 118 insertions(+), 134 deletions(-) diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs index 739f687678..98cd97c318 100644 --- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs +++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs @@ -30,13 +30,10 @@ namespace Emby.Server.Implementations.Activity public class ActivityLogEntryPoint : IServerEntryPoint { private readonly IInstallationManager _installationManager; - - //private readonly ILogger _logger; private readonly ISessionManager _sessionManager; private readonly ITaskManager _taskManager; private readonly IActivityManager _activityManager; private readonly ILocalizationManager _localization; - private readonly ILibraryManager _libraryManager; private readonly ISubtitleManager _subManager; private readonly IUserManager _userManager; @@ -61,41 +58,37 @@ namespace Emby.Server.Implementations.Activity public Task RunAsync() { - _taskManager.TaskCompleted += _taskManager_TaskCompleted; + _taskManager.TaskCompleted += OnTaskCompleted; - _installationManager.PluginInstalled += _installationManager_PluginInstalled; - _installationManager.PluginUninstalled += _installationManager_PluginUninstalled; - _installationManager.PluginUpdated += _installationManager_PluginUpdated; - _installationManager.PackageInstallationFailed += _installationManager_PackageInstallationFailed; + _installationManager.PluginInstalled += OnPluginInstalled; + _installationManager.PluginUninstalled += OnPluginUninstalled; + _installationManager.PluginUpdated += OnPluginUpdated; + _installationManager.PackageInstallationFailed += OnPackageInstallationFailed; - _sessionManager.SessionStarted += _sessionManager_SessionStarted; - _sessionManager.AuthenticationFailed += _sessionManager_AuthenticationFailed; - _sessionManager.AuthenticationSucceeded += _sessionManager_AuthenticationSucceeded; - _sessionManager.SessionEnded += _sessionManager_SessionEnded; + _sessionManager.SessionStarted += OnSessionStarted; + _sessionManager.AuthenticationFailed += OnAuthenticationFailed; + _sessionManager.AuthenticationSucceeded += OnAuthenticationSucceeded; + _sessionManager.SessionEnded += OnSessionEnded; - _sessionManager.PlaybackStart += _sessionManager_PlaybackStart; - _sessionManager.PlaybackStopped += _sessionManager_PlaybackStopped; + _sessionManager.PlaybackStart += OnPlaybackStart; + _sessionManager.PlaybackStopped += OnPlaybackStopped; - //_subManager.SubtitlesDownloaded += _subManager_SubtitlesDownloaded; - _subManager.SubtitleDownloadFailure += _subManager_SubtitleDownloadFailure; + _subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure; - _userManager.UserCreated += _userManager_UserCreated; - _userManager.UserPasswordChanged += _userManager_UserPasswordChanged; - _userManager.UserDeleted += _userManager_UserDeleted; - _userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated; - _userManager.UserLockedOut += _userManager_UserLockedOut; + _userManager.UserCreated += OnUserCreated; + _userManager.UserPasswordChanged += OnUserPasswordChanged; + _userManager.UserDeleted += OnUserDeleted; + _userManager.UserPolicyUpdated += OnUserPolicyUpdated; + _userManager.UserLockedOut += OnUserLockedOut; - //_config.ConfigurationUpdated += _config_ConfigurationUpdated; - //_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated; + _deviceManager.CameraImageUploaded += OnCameraImageUploaded; - _deviceManager.CameraImageUploaded += _deviceManager_CameraImageUploaded; - - _appHost.ApplicationUpdated += _appHost_ApplicationUpdated; + _appHost.ApplicationUpdated += OnApplicationUpdated; return Task.CompletedTask; } - void _deviceManager_CameraImageUploaded(object sender, GenericEventArgs e) + private void OnCameraImageUploaded(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -104,7 +97,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _userManager_UserLockedOut(object sender, GenericEventArgs e) + private void OnUserLockedOut(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -114,7 +107,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _subManager_SubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e) + private void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -125,7 +118,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _sessionManager_PlaybackStopped(object sender, PlaybackStopEventArgs e) + private void OnPlaybackStopped(object sender, PlaybackStopEventArgs e) { var item = e.MediaInfo; @@ -146,7 +139,7 @@ namespace Emby.Server.Implementations.Activity return; } - var user = e.Users.First(); + var user = e.Users[0]; CreateLogEntry(new ActivityLogEntry { @@ -156,7 +149,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _sessionManager_PlaybackStart(object sender, PlaybackProgressEventArgs e) + private void OnPlaybackStart(object sender, PlaybackProgressEventArgs e) { var item = e.MediaInfo; @@ -232,7 +225,7 @@ namespace Emby.Server.Implementations.Activity return null; } - void _sessionManager_SessionEnded(object sender, SessionEventArgs e) + private void OnSessionEnded(object sender, SessionEventArgs e) { string name; var session = e.SessionInfo; @@ -258,7 +251,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _sessionManager_AuthenticationSucceeded(object sender, GenericEventArgs e) + private void OnAuthenticationSucceeded(object sender, GenericEventArgs e) { var user = e.Argument.User; @@ -271,7 +264,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _sessionManager_AuthenticationFailed(object sender, GenericEventArgs e) + private void OnAuthenticationFailed(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -282,7 +275,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _appHost_ApplicationUpdated(object sender, GenericEventArgs e) + private void OnApplicationUpdated(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -292,25 +285,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e) - { - CreateLogEntry(new ActivityLogEntry - { - Name = string.Format(_localization.GetLocalizedString("MessageNamedServerConfigurationUpdatedWithValue"), e.Key), - Type = "NamedConfigurationUpdated" - }); - } - - void _config_ConfigurationUpdated(object sender, EventArgs e) - { - CreateLogEntry(new ActivityLogEntry - { - Name = _localization.GetLocalizedString("MessageServerConfigurationUpdated"), - Type = "ServerConfigurationUpdated" - }); - } - - void _userManager_UserPolicyUpdated(object sender, GenericEventArgs e) + private void OnUserPolicyUpdated(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -320,7 +295,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _userManager_UserDeleted(object sender, GenericEventArgs e) + private void OnUserDeleted(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -329,7 +304,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _userManager_UserPasswordChanged(object sender, GenericEventArgs e) + private void OnUserPasswordChanged(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -339,7 +314,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _userManager_UserCreated(object sender, GenericEventArgs e) + private void OnUserCreated(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -349,18 +324,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _subManager_SubtitlesDownloaded(object sender, SubtitleDownloadEventArgs e) - { - CreateLogEntry(new ActivityLogEntry - { - Name = string.Format(_localization.GetLocalizedString("SubtitlesDownloadedForItem"), Notifications.Notifications.GetItemName(e.Item)), - Type = "SubtitlesDownloaded", - ItemId = e.Item.Id.ToString("N"), - ShortOverview = string.Format(_localization.GetLocalizedString("ProviderValue"), e.Provider) - }); - } - - void _sessionManager_SessionStarted(object sender, SessionEventArgs e) + private void OnSessionStarted(object sender, SessionEventArgs e) { string name; var session = e.SessionInfo; @@ -386,7 +350,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _installationManager_PluginUpdated(object sender, GenericEventArgs> e) + private void OnPluginUpdated(object sender, GenericEventArgs> e) { CreateLogEntry(new ActivityLogEntry { @@ -397,7 +361,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _installationManager_PluginUninstalled(object sender, GenericEventArgs e) + private void OnPluginUninstalled(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -406,7 +370,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _installationManager_PluginInstalled(object sender, GenericEventArgs e) + private void OnPluginInstalled(object sender, GenericEventArgs e) { CreateLogEntry(new ActivityLogEntry { @@ -416,7 +380,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _installationManager_PackageInstallationFailed(object sender, InstallationFailedEventArgs e) + private void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e) { var installationInfo = e.InstallationInfo; @@ -429,7 +393,7 @@ namespace Emby.Server.Implementations.Activity }); } - void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e) + private void OnTaskCompleted(object sender, TaskCompletionEventArgs e) { var result = e.Result; var task = e.Task; @@ -468,48 +432,36 @@ namespace Emby.Server.Implementations.Activity } private void CreateLogEntry(ActivityLogEntry entry) - { - try - { - _activityManager.Create(entry); - } - catch - { - // Logged at lower levels - } - } + => _activityManager.Create(entry); public void Dispose() { - _taskManager.TaskCompleted -= _taskManager_TaskCompleted; + _taskManager.TaskCompleted -= OnTaskCompleted; - _installationManager.PluginInstalled -= _installationManager_PluginInstalled; - _installationManager.PluginUninstalled -= _installationManager_PluginUninstalled; - _installationManager.PluginUpdated -= _installationManager_PluginUpdated; - _installationManager.PackageInstallationFailed -= _installationManager_PackageInstallationFailed; + _installationManager.PluginInstalled -= OnPluginInstalled; + _installationManager.PluginUninstalled -= OnPluginUninstalled; + _installationManager.PluginUpdated -= OnPluginUpdated; + _installationManager.PackageInstallationFailed -= OnPackageInstallationFailed; - _sessionManager.SessionStarted -= _sessionManager_SessionStarted; - _sessionManager.AuthenticationFailed -= _sessionManager_AuthenticationFailed; - _sessionManager.AuthenticationSucceeded -= _sessionManager_AuthenticationSucceeded; - _sessionManager.SessionEnded -= _sessionManager_SessionEnded; + _sessionManager.SessionStarted -= OnSessionStarted; + _sessionManager.AuthenticationFailed -= OnAuthenticationFailed; + _sessionManager.AuthenticationSucceeded -= OnAuthenticationSucceeded; + _sessionManager.SessionEnded -= OnSessionEnded; - _sessionManager.PlaybackStart -= _sessionManager_PlaybackStart; - _sessionManager.PlaybackStopped -= _sessionManager_PlaybackStopped; + _sessionManager.PlaybackStart -= OnPlaybackStart; + _sessionManager.PlaybackStopped -= OnPlaybackStopped; - _subManager.SubtitleDownloadFailure -= _subManager_SubtitleDownloadFailure; + _subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure; - _userManager.UserCreated -= _userManager_UserCreated; - _userManager.UserPasswordChanged -= _userManager_UserPasswordChanged; - _userManager.UserDeleted -= _userManager_UserDeleted; - _userManager.UserPolicyUpdated -= _userManager_UserPolicyUpdated; - _userManager.UserLockedOut -= _userManager_UserLockedOut; + _userManager.UserCreated -= OnUserCreated; + _userManager.UserPasswordChanged -= OnUserPasswordChanged; + _userManager.UserDeleted -= OnUserDeleted; + _userManager.UserPolicyUpdated -= OnUserPolicyUpdated; + _userManager.UserLockedOut -= OnUserLockedOut; - _config.ConfigurationUpdated -= _config_ConfigurationUpdated; - _config.NamedConfigurationUpdated -= _config_NamedConfigurationUpdated; + _deviceManager.CameraImageUploaded -= OnCameraImageUploaded; - _deviceManager.CameraImageUploaded -= _deviceManager_CameraImageUploaded; - - _appHost.ApplicationUpdated -= _appHost_ApplicationUpdated; + _appHost.ApplicationUpdated -= OnApplicationUpdated; } /// @@ -531,6 +483,7 @@ namespace Emby.Server.Implementations.Activity values.Add(CreateValueString(years, "year")); days = days % DaysInYear; } + // Number of months if (days >= DaysInMonth) { @@ -538,25 +491,39 @@ namespace Emby.Server.Implementations.Activity values.Add(CreateValueString(months, "month")); days = days % DaysInMonth; } + // Number of days if (days >= 1) + { values.Add(CreateValueString(days, "day")); + } + // Number of hours if (span.Hours >= 1) + { values.Add(CreateValueString(span.Hours, "hour")); + } // Number of minutes if (span.Minutes >= 1) + { values.Add(CreateValueString(span.Minutes, "minute")); + } + // Number of seconds (include when 0 if no other components included) if (span.Seconds >= 1 || values.Count == 0) + { values.Add(CreateValueString(span.Seconds, "second")); + } // Combine values into string var builder = new StringBuilder(); for (int i = 0; i < values.Count; i++) { if (builder.Length > 0) + { builder.Append(i == values.Count - 1 ? " and " : ", "); + } + builder.Append(values[i]); } // Return result diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 39e9ed3756..3cbd2792d9 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -47,6 +47,21 @@ false + + true + + + + + + + + + + + ../jellyfin.ruleset + + diff --git a/Emby.Server.Implementations/SocketSharp/HttpPostedFile.cs b/Emby.Server.Implementations/SocketSharp/HttpPostedFile.cs index f38ed848ee..95b7912fbb 100644 --- a/Emby.Server.Implementations/SocketSharp/HttpPostedFile.cs +++ b/Emby.Server.Implementations/SocketSharp/HttpPostedFile.cs @@ -63,6 +63,28 @@ public sealed class HttpPostedFile : IDisposable _position = offset; } + public override bool CanRead => true; + + public override bool CanSeek => true; + + public override bool CanWrite => false; + + public override long Length => _end - _offset; + + public override long Position + { + get => _position - _offset; + set + { + if (value > Length) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + _position = Seek(value, SeekOrigin.Begin); + } + } + public override void Flush() { } @@ -178,27 +200,5 @@ public sealed class HttpPostedFile : IDisposable { throw new NotSupportedException(); } - - public override bool CanRead => true; - - public override bool CanSeek => true; - - public override bool CanWrite => false; - - public override long Length => _end - _offset; - - public override long Position - { - get => _position - _offset; - set - { - if (value > Length) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } - - _position = Seek(value, SeekOrigin.Begin); - } - } } } diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index bd670df527..9346a2d254 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -12,7 +12,8 @@ latest - SA1600;CS1591 + SA1600;SA1601;CS1591 + true @@ -23,10 +24,6 @@ - - true - - diff --git a/jellyfin.ruleset b/jellyfin.ruleset index 4381349ca6..0a04b4c557 100644 --- a/jellyfin.ruleset +++ b/jellyfin.ruleset @@ -1,6 +1,11 @@ + + + + + From decaffed86cbc5db99c3f79d266fdfcdd262c12d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Thu, 7 Mar 2019 17:39:40 +0100 Subject: [PATCH 13/48] Remove EnvironmentInfo This moved the last bit of usefulness of EnvironmentInfo into a static class. --- Emby.Dlna/Main/DlnaEntryPoint.cs | 13 ++-- .../IsoMounter/LinuxIsoManager.cs | 10 ++- .../ApplicationHost.cs | 47 ++++-------- .../EnvironmentInfo/EnvironmentInfo.cs | 36 ---------- .../IO/LibraryMonitor.cs | 15 +--- .../IO/ManagedFileSystem.cs | 16 ++--- .../Networking/NetworkManager.cs | 8 +-- Jellyfin.Server/CoreAppHost.cs | 3 - Jellyfin.Server/Program.cs | 51 ++----------- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 +-- .../LiveTv/ProgressiveFileCopier.cs | 8 +-- .../Playback/Progressive/AudioService.cs | 8 +-- .../BaseProgressiveStreamingService.cs | 15 ++-- .../Progressive/ProgressiveStreamWriter.cs | 10 ++- .../Playback/Progressive/VideoService.cs | 8 +-- .../Playback/UniversalAudioService.cs | 7 +- MediaBrowser.Common/IApplicationHost.cs | 3 +- MediaBrowser.Common/System/OperatingSystem.cs | 72 +++++++++++++++++++ MediaBrowser.Model/System/IEnvironmentInfo.cs | 21 ------ .../System/OperatingSystemId.cs | 10 +++ 20 files changed, 144 insertions(+), 225 deletions(-) delete mode 100644 Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs create mode 100644 MediaBrowser.Common/System/OperatingSystem.cs delete mode 100644 MediaBrowser.Model/System/IEnvironmentInfo.cs create mode 100644 MediaBrowser.Model/System/OperatingSystemId.cs diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 57ed0097a0..919a8f46f8 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using Emby.Dlna.PlayTo; @@ -24,6 +23,7 @@ using MediaBrowser.Model.Xml; using Microsoft.Extensions.Logging; using Rssdp; using Rssdp.Infrastructure; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Dlna.Main { @@ -48,9 +48,8 @@ namespace Emby.Dlna.Main private readonly IDeviceDiscovery _deviceDiscovery; private SsdpDevicePublisher _Publisher; - + private readonly ISocketFactory _socketFactory; - private readonly IEnvironmentInfo _environmentInfo; private readonly INetworkManager _networkManager; private ISsdpCommunicationsServer _communicationsServer; @@ -76,7 +75,6 @@ namespace Emby.Dlna.Main IDeviceDiscovery deviceDiscovery, IMediaEncoder mediaEncoder, ISocketFactory socketFactory, - IEnvironmentInfo environmentInfo, INetworkManager networkManager, IUserViewManager userViewManager, IXmlReaderSettingsFactory xmlReaderSettingsFactory, @@ -96,7 +94,6 @@ namespace Emby.Dlna.Main _deviceDiscovery = deviceDiscovery; _mediaEncoder = mediaEncoder; _socketFactory = socketFactory; - _environmentInfo = environmentInfo; _networkManager = networkManager; _logger = loggerFactory.CreateLogger("Dlna"); @@ -169,8 +166,8 @@ namespace Emby.Dlna.Main { if (_communicationsServer == null) { - var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows || - _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux; + var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows || + OperatingSystem.Id == OperatingSystemId.Linux; _communicationsServer = new SsdpCommunicationsServer(_config, _socketFactory, _networkManager, _logger, enableMultiSocketBinding) { @@ -230,7 +227,7 @@ namespace Emby.Dlna.Main try { - _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion, _config.GetDlnaConfiguration().SendOnlyMatchedHost); + _Publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost); _Publisher.LogFunction = LogMessage; _Publisher.SupportPnpRootDevice = false; diff --git a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs index 943caa3e62..2f0003be88 100644 --- a/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs +++ b/Emby.IsoMounting/IsoMounter/LinuxIsoManager.cs @@ -7,6 +7,7 @@ using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace IsoMounter { @@ -17,7 +18,6 @@ namespace IsoMounter #region Private Fields - private readonly IEnvironmentInfo EnvironmentInfo; private readonly bool ExecutablesAvailable; private readonly ILogger _logger; private readonly string MountCommand; @@ -30,10 +30,8 @@ namespace IsoMounter #region Constructor(s) - public LinuxIsoManager(ILogger logger, IEnvironmentInfo environment, IProcessFactory processFactory) + public LinuxIsoManager(ILogger logger, IProcessFactory processFactory) { - - EnvironmentInfo = environment; _logger = logger; ProcessFactory = processFactory; @@ -109,7 +107,7 @@ namespace IsoMounter public bool CanMount(string path) { - if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Linux) + if (OperatingSystem.Id != OperatingSystemId.Linux) { return false; } @@ -118,7 +116,7 @@ namespace IsoMounter Name, path, Path.GetExtension(path), - EnvironmentInfo.OperatingSystem, + OperatingSystem.Name, ExecutablesAvailable ); diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index a581214c71..964d173421 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -115,6 +115,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using ServiceStack; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations { @@ -143,12 +144,8 @@ namespace Emby.Server.Implementations return false; } - if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows) - { - return true; - } - - if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX) + if (OperatingSystem.Id == OperatingSystemId.Windows + || OperatingSystem.Id == OperatingSystemId.Darwin) { return true; } @@ -218,8 +215,6 @@ namespace Emby.Server.Implementations public IFileSystem FileSystemManager { get; set; } - protected IEnvironmentInfo EnvironmentInfo { get; set; } - public PackageVersionClass SystemUpdateLevel { get @@ -239,15 +234,6 @@ namespace Emby.Server.Implementations /// The server configuration manager. public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager; - /// - /// Gets the configuration manager. - /// - /// IConfigurationManager. - protected IConfigurationManager GetConfigurationManager() - { - return new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager); - } - protected virtual IResourceFileManager CreateResourceFileManager() { return new ResourceFileManager(HttpResultFactory, LoggerFactory, FileSystemManager); @@ -356,7 +342,6 @@ namespace Emby.Server.Implementations ILoggerFactory loggerFactory, IStartupOptions options, IFileSystem fileSystem, - IEnvironmentInfo environmentInfo, IImageEncoder imageEncoder, INetworkManager networkManager, IConfiguration configuration) @@ -370,13 +355,12 @@ namespace Emby.Server.Implementations NetworkManager = networkManager; networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets; - EnvironmentInfo = environmentInfo; ApplicationPaths = applicationPaths; LoggerFactory = loggerFactory; FileSystemManager = fileSystem; - ConfigurationManager = GetConfigurationManager(); + ConfigurationManager = new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager); Logger = LoggerFactory.CreateLogger("App"); @@ -532,7 +516,7 @@ namespace Emby.Server.Implementations /// /// Runs the startup tasks. /// - public async Task RunStartupTasks() + public async Task RunStartupTasksAsync() { Logger.LogInformation("Running startup tasks"); @@ -584,7 +568,7 @@ namespace Emby.Server.Implementations } } - public async Task Init(IServiceCollection serviceCollection) + public async Task InitAsync(IServiceCollection serviceCollection) { HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber; @@ -706,8 +690,6 @@ namespace Emby.Server.Implementations serviceCollection.AddLogging(); serviceCollection.AddSingleton(Logger); - serviceCollection.AddSingleton(EnvironmentInfo); - serviceCollection.AddSingleton(FileSystemManager); serviceCollection.AddSingleton(); @@ -786,7 +768,7 @@ namespace Emby.Server.Implementations var musicManager = new MusicManager(LibraryManager); serviceCollection.AddSingleton(new MusicManager(LibraryManager)); - LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager, EnvironmentInfo); + LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager); serviceCollection.AddSingleton(LibraryMonitor); serviceCollection.AddSingleton(new SearchEngine(LoggerFactory, LibraryManager, UserManager)); @@ -907,7 +889,7 @@ namespace Emby.Server.Implementations public virtual string PackageRuntime => "netcore"; - public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, EnvironmentInfo.EnvironmentInfo environmentInfo) + public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths) { // Distinct these to prevent users from reporting problems that aren't actually problems var commandLineArgs = Environment @@ -915,8 +897,9 @@ namespace Emby.Server.Implementations .Distinct(); logger.LogInformation("Arguments: {Args}", commandLineArgs); - logger.LogInformation("Operating system: {OS} {OSVersion}", environmentInfo.OperatingSystemName, environmentInfo.OperatingSystemVersion); - logger.LogInformation("Architecture: {Architecture}", environmentInfo.SystemArchitecture); + // FIXME: @bond this logs the kernel version, not the OS version + logger.LogInformation("Operating system: {OS} {OSVersion}", OperatingSystem.Name, Environment.OSVersion.Version); + logger.LogInformation("Architecture: {Architecture}", RuntimeInformation.OSArchitecture); logger.LogInformation("64-Bit Process: {Is64Bit}", Environment.Is64BitProcess); logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive); logger.LogInformation("Processor count: {ProcessorCount}", Environment.ProcessorCount); @@ -1400,8 +1383,8 @@ namespace Emby.Server.Implementations HttpServerPortNumber = HttpPort, SupportsHttps = SupportsHttps, HttpsPortNumber = HttpsPort, - OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(), - OperatingSystemDisplayName = EnvironmentInfo.OperatingSystemName, + OperatingSystem = OperatingSystem.Id.ToString(), + OperatingSystemDisplayName = OperatingSystem.Name, CanSelfRestart = CanSelfRestart, CanLaunchWebBrowser = CanLaunchWebBrowser, WanAddress = wanAddress, @@ -1411,7 +1394,7 @@ namespace Emby.Server.Implementations LocalAddress = localAddress, SupportsLibraryMonitor = true, EncoderLocation = MediaEncoder.EncoderLocation, - SystemArchitecture = EnvironmentInfo.SystemArchitecture, + SystemArchitecture = RuntimeInformation.OSArchitecture, SystemUpdateLevel = SystemUpdateLevel, PackageName = StartupOptions.PackageName }; @@ -1435,7 +1418,7 @@ namespace Emby.Server.Implementations { Version = ApplicationVersion, Id = SystemId, - OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(), + OperatingSystem = OperatingSystem.Id.ToString(), WanAddress = wanAddress, ServerName = FriendlyName, LocalAddress = localAddress diff --git a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs b/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs deleted file mode 100644 index c8104150d6..0000000000 --- a/Emby.Server.Implementations/EnvironmentInfo/EnvironmentInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using MediaBrowser.Model.System; - -namespace Emby.Server.Implementations.EnvironmentInfo -{ - public class EnvironmentInfo : IEnvironmentInfo - { - public EnvironmentInfo(MediaBrowser.Model.System.OperatingSystem operatingSystem) - { - OperatingSystem = operatingSystem; - } - - public MediaBrowser.Model.System.OperatingSystem OperatingSystem { get; private set; } - - public string OperatingSystemName - { - get - { - switch (OperatingSystem) - { - case MediaBrowser.Model.System.OperatingSystem.Android: return "Android"; - case MediaBrowser.Model.System.OperatingSystem.BSD: return "BSD"; - case MediaBrowser.Model.System.OperatingSystem.Linux: return "Linux"; - case MediaBrowser.Model.System.OperatingSystem.OSX: return "macOS"; - case MediaBrowser.Model.System.OperatingSystem.Windows: return "Windows"; - default: throw new Exception($"Unknown OS {OperatingSystem}"); - } - } - } - - public string OperatingSystemVersion => Environment.OSVersion.Version.ToString() + " " + Environment.OSVersion.ServicePack.ToString(); - - public Architecture SystemArchitecture => RuntimeInformation.OSArchitecture; - } -} diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs index d473425115..df4dc41b99 100644 --- a/Emby.Server.Implementations/IO/LibraryMonitor.cs +++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs @@ -10,8 +10,8 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; -using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations.IO { @@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.IO private IServerConfigurationManager ConfigurationManager { get; set; } private readonly IFileSystem _fileSystem; - private readonly IEnvironmentInfo _environmentInfo; /// /// Initializes a new instance of the class. @@ -136,14 +135,12 @@ namespace Emby.Server.Implementations.IO ILoggerFactory loggerFactory, ILibraryManager libraryManager, IServerConfigurationManager configurationManager, - IFileSystem fileSystem, - IEnvironmentInfo environmentInfo) + IFileSystem fileSystem) { LibraryManager = libraryManager; Logger = loggerFactory.CreateLogger(GetType().Name); ConfigurationManager = configurationManager; _fileSystem = fileSystem; - _environmentInfo = environmentInfo; } private bool IsLibraryMonitorEnabled(BaseItem item) @@ -267,7 +264,7 @@ namespace Emby.Server.Implementations.IO return; } - if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + if (OperatingSystem.Id != OperatingSystemId.Windows) { if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase) || path.StartsWith("smb://", StringComparison.OrdinalIgnoreCase)) { @@ -276,12 +273,6 @@ namespace Emby.Server.Implementations.IO } } - if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Android) - { - // causing crashing - return; - } - // Already being watched if (_fileSystemWatchers.ContainsKey(path)) { diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 421592fada..47cea7269d 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -8,6 +8,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations.IO { @@ -24,22 +25,19 @@ namespace Emby.Server.Implementations.IO private readonly string _tempPath; - private readonly IEnvironmentInfo _environmentInfo; private readonly bool _isEnvironmentCaseInsensitive; public ManagedFileSystem( ILoggerFactory loggerFactory, - IEnvironmentInfo environmentInfo, IApplicationPaths applicationPaths) { Logger = loggerFactory.CreateLogger("FileSystem"); _supportsAsyncFileStreams = true; _tempPath = applicationPaths.TempDirectory; - _environmentInfo = environmentInfo; - SetInvalidFileNameChars(environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows); + SetInvalidFileNameChars(OperatingSystem.Id == OperatingSystemId.Windows); - _isEnvironmentCaseInsensitive = environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows; + _isEnvironmentCaseInsensitive = OperatingSystem.Id == OperatingSystemId.Windows; } public virtual void AddShortcutHandler(IShortcutHandler handler) @@ -468,7 +466,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetHidden(string path, bool isHidden) { - if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows) { return; } @@ -492,7 +490,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetReadOnly(string path, bool isReadOnly) { - if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows) { return; } @@ -516,7 +514,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetAttributes(string path, bool isHidden, bool isReadOnly) { - if (_environmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows) + if (OperatingSystem.Id != MediaBrowser.Model.System.OperatingSystemId.Windows) { return; } @@ -801,7 +799,7 @@ namespace Emby.Server.Implementations.IO public virtual void SetExecutable(string path) { - if (_environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX) + if (OperatingSystem.Id == MediaBrowser.Model.System.OperatingSystemId.Darwin) { RunProcess("chmod", "+x \"" + path + "\"", Path.GetDirectoryName(path)); } diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index ace93ebdee..c102f9eb55 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -7,11 +7,11 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Threading.Tasks; using MediaBrowser.Common.Net; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations.Networking { @@ -22,14 +22,12 @@ namespace Emby.Server.Implementations.Networking public event EventHandler NetworkChanged; public Func LocalSubnetsFn { get; set; } - public NetworkManager( - ILoggerFactory loggerFactory, - IEnvironmentInfo environment) + public NetworkManager(ILoggerFactory loggerFactory) { Logger = loggerFactory.CreateLogger(nameof(NetworkManager)); // In FreeBSD these events cause a crash - if (environment.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.BSD) + if (OperatingSystem.Id != OperatingSystemId.BSD) { try { diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs index 17259c7370..8e6ed7a7e5 100644 --- a/Jellyfin.Server/CoreAppHost.cs +++ b/Jellyfin.Server/CoreAppHost.cs @@ -3,7 +3,6 @@ using System.Reflection; using Emby.Server.Implementations; using Emby.Server.Implementations.HttpServer; using MediaBrowser.Model.IO; -using MediaBrowser.Model.System; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -16,7 +15,6 @@ namespace Jellyfin.Server ILoggerFactory loggerFactory, StartupOptions options, IFileSystem fileSystem, - IEnvironmentInfo environmentInfo, MediaBrowser.Controller.Drawing.IImageEncoder imageEncoder, MediaBrowser.Common.Net.INetworkManager networkManager, IConfiguration configuration) @@ -25,7 +23,6 @@ namespace Jellyfin.Server loggerFactory, options, fileSystem, - environmentInfo, imageEncoder, networkManager, configuration) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 0ef1711d4c..a60f2a4f61 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using CommandLine; using Emby.Drawing; using Emby.Server.Implementations; -using Emby.Server.Implementations.EnvironmentInfo; using Emby.Server.Implementations.IO; using Emby.Server.Implementations.Networking; using Jellyfin.Drawing.Skia; @@ -46,7 +45,6 @@ namespace Jellyfin.Server const string pattern = @"^(-[^-\s]{2})"; // Match -xx, not -x, not --xx, not xx const string substitution = @"-$1"; // Prepend with additional single-hyphen var regex = new Regex(pattern); - for (var i = 0; i < args.Length; i++) { args[i] = regex.Replace(args[i], substitution); @@ -54,9 +52,7 @@ namespace Jellyfin.Server // Parse the command line arguments and either start the app or exit indicating error await Parser.Default.ParseArguments(args) - .MapResult( - options => StartApp(options), - errs => Task.FromResult(0)).ConfigureAwait(false); + .MapResult(StartApp, _ => Task.CompletedTask).ConfigureAwait(false); } public static void Shutdown() @@ -119,31 +115,29 @@ namespace Jellyfin.Server _logger.LogInformation("Jellyfin version: {Version}", Assembly.GetEntryAssembly().GetName().Version); - EnvironmentInfo environmentInfo = new EnvironmentInfo(GetOperatingSystem()); - ApplicationHost.LogEnvironmentInfo(_logger, appPaths, environmentInfo); + ApplicationHost.LogEnvironmentInfo(_logger, appPaths); SQLitePCL.Batteries_V2.Init(); // Allow all https requests ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); - var fileSystem = new ManagedFileSystem(_loggerFactory, environmentInfo, appPaths); + var fileSystem = new ManagedFileSystem(_loggerFactory, appPaths); using (var appHost = new CoreAppHost( appPaths, _loggerFactory, options, fileSystem, - environmentInfo, new NullImageEncoder(), - new NetworkManager(_loggerFactory, environmentInfo), + new NetworkManager(_loggerFactory), appConfig)) { - await appHost.Init(new ServiceCollection()).ConfigureAwait(false); + await appHost.InitAsync(new ServiceCollection()).ConfigureAwait(false); appHost.ImageProcessor.ImageEncoder = GetImageEncoder(fileSystem, appPaths, appHost.LocalizationManager); - await appHost.RunStartupTasks().ConfigureAwait(false); + await appHost.RunStartupTasksAsync().ConfigureAwait(false); try { @@ -179,7 +173,6 @@ namespace Jellyfin.Server // ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin // ELSE use $HOME/.local/share/jellyfin var dataDir = options.DataDir; - if (string.IsNullOrEmpty(dataDir)) { dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH"); @@ -236,7 +229,6 @@ namespace Jellyfin.Server // ELSE IF XDG_CACHE_HOME, use $XDG_CACHE_HOME/jellyfin // ELSE HOME/.cache/jellyfin var cacheDir = options.CacheDir; - if (string.IsNullOrEmpty(cacheDir)) { cacheDir = Environment.GetEnvironmentVariable("JELLYFIN_CACHE_DIR"); @@ -270,7 +262,6 @@ namespace Jellyfin.Server // ELSE IF --datadir, use /log (assume portable run) // ELSE /log var logDir = options.LogDir; - if (string.IsNullOrEmpty(logDir)) { logDir = Environment.GetEnvironmentVariable("JELLYFIN_LOG_DIR"); @@ -364,36 +355,6 @@ namespace Jellyfin.Server return new NullImageEncoder(); } - private static MediaBrowser.Model.System.OperatingSystem GetOperatingSystem() - { - switch (Environment.OSVersion.Platform) - { - case PlatformID.MacOSX: - return MediaBrowser.Model.System.OperatingSystem.OSX; - case PlatformID.Win32NT: - return MediaBrowser.Model.System.OperatingSystem.Windows; - case PlatformID.Unix: - default: - { - string osDescription = RuntimeInformation.OSDescription; - if (osDescription.Contains("linux", StringComparison.OrdinalIgnoreCase)) - { - return MediaBrowser.Model.System.OperatingSystem.Linux; - } - else if (osDescription.Contains("darwin", StringComparison.OrdinalIgnoreCase)) - { - return MediaBrowser.Model.System.OperatingSystem.OSX; - } - else if (osDescription.Contains("bsd", StringComparison.OrdinalIgnoreCase)) - { - return MediaBrowser.Model.System.OperatingSystem.BSD; - } - - throw new Exception($"Can't resolve OS with description: '{osDescription}'"); - } - } - } - private static void StartNewInstance(StartupOptions options) { _logger.LogInformation("Starting new instance"); diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 88ed734569..486d5e8a71 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -698,12 +698,11 @@ namespace MediaBrowser.Api.LiveTv private readonly IFileSystem _fileSystem; private readonly IAuthorizationContext _authContext; private readonly ISessionContext _sessionContext; - private readonly IEnvironmentInfo _environment; private ICryptoProvider _cryptographyProvider; private IStreamHelper _streamHelper; private IMediaSourceManager _mediaSourceManager; - public LiveTvService(ICryptoProvider crypto, IMediaSourceManager mediaSourceManager, IStreamHelper streamHelper, ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext, IEnvironmentInfo environment) + public LiveTvService(ICryptoProvider crypto, IMediaSourceManager mediaSourceManager, IStreamHelper streamHelper, ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext) { _liveTvManager = liveTvManager; _userManager = userManager; @@ -714,7 +713,6 @@ namespace MediaBrowser.Api.LiveTv _fileSystem = fileSystem; _authContext = authContext; _sessionContext = sessionContext; - _environment = environment; _cryptographyProvider = crypto; _streamHelper = streamHelper; _mediaSourceManager = mediaSourceManager; @@ -756,7 +754,7 @@ namespace MediaBrowser.Api.LiveTv [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType(path) }; - return new ProgressiveFileCopier(_fileSystem, _streamHelper, path, outputHeaders, Logger, _environment) + return new ProgressiveFileCopier(_fileSystem, _streamHelper, path, outputHeaders, Logger) { AllowEndOfFile = false }; @@ -779,7 +777,7 @@ namespace MediaBrowser.Api.LiveTv [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType("file." + request.Container) }; - return new ProgressiveFileCopier(directStreamProvider, _streamHelper, outputHeaders, Logger, _environment) + return new ProgressiveFileCopier(directStreamProvider, _streamHelper, outputHeaders, Logger) { AllowEndOfFile = false }; diff --git a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs index 8412bf66b9..51552d928b 100644 --- a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs +++ b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.LiveTv @@ -23,25 +22,22 @@ namespace MediaBrowser.Api.LiveTv public bool AllowEndOfFile = true; private readonly IDirectStreamProvider _directStreamProvider; - private readonly IEnvironmentInfo _environment; private IStreamHelper _streamHelper; - public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary outputHeaders, ILogger logger, IEnvironmentInfo environment) + public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary outputHeaders, ILogger logger) { _fileSystem = fileSystem; _path = path; _outputHeaders = outputHeaders; _logger = logger; - _environment = environment; _streamHelper = streamHelper; } - public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary outputHeaders, ILogger logger, IEnvironmentInfo environment) + public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, IStreamHelper streamHelper, Dictionary outputHeaders, ILogger logger) { _directStreamProvider = directStreamProvider; _outputHeaders = outputHeaders; _logger = logger; - _environment = environment; _streamHelper = streamHelper; } diff --git a/MediaBrowser.Api/Playback/Progressive/AudioService.cs b/MediaBrowser.Api/Playback/Progressive/AudioService.cs index 48b4e2f24e..dfe4b2b8e9 100644 --- a/MediaBrowser.Api/Playback/Progressive/AudioService.cs +++ b/MediaBrowser.Api/Playback/Progressive/AudioService.cs @@ -3,7 +3,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; -using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; @@ -11,7 +10,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; namespace MediaBrowser.Api.Playback.Progressive { @@ -46,8 +44,7 @@ namespace MediaBrowser.Api.Playback.Progressive IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IJsonSerializer jsonSerializer, - IAuthorizationContext authorizationContext, - IEnvironmentInfo environmentInfo) + IAuthorizationContext authorizationContext) : base(httpClient, serverConfig, userManager, @@ -60,8 +57,7 @@ namespace MediaBrowser.Api.Playback.Progressive deviceManager, mediaSourceManager, jsonSerializer, - authorizationContext, - environmentInfo) + authorizationContext) { } diff --git a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs index f43f26b2f3..a2c20e38fd 100644 --- a/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs +++ b/MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -8,15 +7,12 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; -using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; using Microsoft.Net.Http.Headers; namespace MediaBrowser.Api.Playback.Progressive @@ -26,7 +22,6 @@ namespace MediaBrowser.Api.Playback.Progressive /// public abstract class BaseProgressiveStreamingService : BaseStreamingService { - protected readonly IEnvironmentInfo EnvironmentInfo; protected IHttpClient HttpClient { get; private set; } public BaseProgressiveStreamingService( @@ -42,8 +37,7 @@ namespace MediaBrowser.Api.Playback.Progressive IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IJsonSerializer jsonSerializer, - IAuthorizationContext authorizationContext, - IEnvironmentInfo environmentInfo) + IAuthorizationContext authorizationContext) : base(serverConfig, userManager, libraryManager, @@ -57,7 +51,6 @@ namespace MediaBrowser.Api.Playback.Progressive jsonSerializer, authorizationContext) { - EnvironmentInfo = environmentInfo; HttpClient = httpClient; } @@ -157,7 +150,7 @@ namespace MediaBrowser.Api.Playback.Progressive // TODO: Don't hardcode this outputHeaders[HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType("file.ts"); - return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None) + return new ProgressiveFileCopier(state.DirectStreamProvider, outputHeaders, null, Logger, CancellationToken.None) { AllowEndOfFile = false }; @@ -203,7 +196,7 @@ namespace MediaBrowser.Api.Playback.Progressive }; - return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, EnvironmentInfo, CancellationToken.None) + return new ProgressiveFileCopier(FileSystem, state.MediaPath, outputHeaders, null, Logger, CancellationToken.None) { AllowEndOfFile = false }; @@ -397,7 +390,7 @@ namespace MediaBrowser.Api.Playback.Progressive outputHeaders[item.Key] = item.Value; } - return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, EnvironmentInfo, CancellationToken.None); + return new ProgressiveFileCopier(FileSystem, outputPath, outputHeaders, job, Logger, CancellationToken.None); } finally { diff --git a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs index 3dd9de2a1b..6609120655 100644 --- a/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs +++ b/MediaBrowser.Api/Playback/Progressive/ProgressiveStreamWriter.cs @@ -8,6 +8,7 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.Services; using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; +using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace MediaBrowser.Api.Playback.Progressive { @@ -27,9 +28,8 @@ namespace MediaBrowser.Api.Playback.Progressive public bool AllowEndOfFile = true; private readonly IDirectStreamProvider _directStreamProvider; - private readonly IEnvironmentInfo _environment; - public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) + public ProgressiveFileCopier(IFileSystem fileSystem, string path, Dictionary outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) { _fileSystem = fileSystem; _path = path; @@ -37,17 +37,15 @@ namespace MediaBrowser.Api.Playback.Progressive _job = job; _logger = logger; _cancellationToken = cancellationToken; - _environment = environment; } - public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary outputHeaders, TranscodingJob job, ILogger logger, IEnvironmentInfo environment, CancellationToken cancellationToken) + public ProgressiveFileCopier(IDirectStreamProvider directStreamProvider, Dictionary outputHeaders, TranscodingJob job, ILogger logger, CancellationToken cancellationToken) { _directStreamProvider = directStreamProvider; _outputHeaders = outputHeaders; _job = job; _logger = logger; _cancellationToken = cancellationToken; - _environment = environment; } public IDictionary Headers => _outputHeaders; @@ -79,7 +77,7 @@ namespace MediaBrowser.Api.Playback.Progressive var eofCount = 0; // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsyncFileRead = _environment.OperatingSystem != Model.System.OperatingSystem.Windows; + var allowAsyncFileRead = OperatingSystem.Id != OperatingSystemId.Windows; using (var inputStream = GetInputStream(allowAsyncFileRead)) { diff --git a/MediaBrowser.Api/Playback/Progressive/VideoService.cs b/MediaBrowser.Api/Playback/Progressive/VideoService.cs index bf15cc756c..ab19fdc261 100644 --- a/MediaBrowser.Api/Playback/Progressive/VideoService.cs +++ b/MediaBrowser.Api/Playback/Progressive/VideoService.cs @@ -3,7 +3,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; -using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; @@ -11,7 +10,6 @@ using MediaBrowser.Model.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; namespace MediaBrowser.Api.Playback.Progressive { @@ -83,8 +81,7 @@ namespace MediaBrowser.Api.Playback.Progressive IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IJsonSerializer jsonSerializer, - IAuthorizationContext authorizationContext, - IEnvironmentInfo environmentInfo) + IAuthorizationContext authorizationContext) : base(httpClient, serverConfig, userManager, @@ -97,8 +94,7 @@ namespace MediaBrowser.Api.Playback.Progressive deviceManager, mediaSourceManager, jsonSerializer, - authorizationContext, - environmentInfo) + authorizationContext) { } diff --git a/MediaBrowser.Api/Playback/UniversalAudioService.cs b/MediaBrowser.Api/Playback/UniversalAudioService.cs index f97e88e986..b3d8bfe59f 100644 --- a/MediaBrowser.Api/Playback/UniversalAudioService.cs +++ b/MediaBrowser.Api/Playback/UniversalAudioService.cs @@ -18,7 +18,6 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; namespace MediaBrowser.Api.Playback @@ -93,7 +92,6 @@ namespace MediaBrowser.Api.Playback IAuthorizationContext authorizationContext, IImageProcessor imageProcessor, INetworkManager networkManager, - IEnvironmentInfo environmentInfo, ILoggerFactory loggerFactory) { HttpClient = httpClient; @@ -112,7 +110,6 @@ namespace MediaBrowser.Api.Playback AuthorizationContext = authorizationContext; ImageProcessor = imageProcessor; NetworkManager = networkManager; - EnvironmentInfo = environmentInfo; _loggerFactory = loggerFactory; _logger = loggerFactory.CreateLogger(nameof(UniversalAudioService)); } @@ -133,7 +130,6 @@ namespace MediaBrowser.Api.Playback protected IAuthorizationContext AuthorizationContext { get; private set; } protected IImageProcessor ImageProcessor { get; private set; } protected INetworkManager NetworkManager { get; private set; } - protected IEnvironmentInfo EnvironmentInfo { get; private set; } private ILoggerFactory _loggerFactory; private ILogger _logger; @@ -338,8 +334,7 @@ namespace MediaBrowser.Api.Playback DeviceManager, MediaSourceManager, JsonSerializer, - AuthorizationContext, - EnvironmentInfo) + AuthorizationContext) { Request = Request }; diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 3a4098612d..966448d630 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Plugins; using MediaBrowser.Model.Events; @@ -107,7 +106,7 @@ namespace MediaBrowser.Common /// /// Inits this instance. /// - Task Init(IServiceCollection serviceCollection); + Task InitAsync(IServiceCollection serviceCollection); /// /// Creates the instance. diff --git a/MediaBrowser.Common/System/OperatingSystem.cs b/MediaBrowser.Common/System/OperatingSystem.cs new file mode 100644 index 0000000000..640821d4d7 --- /dev/null +++ b/MediaBrowser.Common/System/OperatingSystem.cs @@ -0,0 +1,72 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; +using MediaBrowser.Model.System; + +namespace MediaBrowser.Common.System +{ + public static class OperatingSystem + { + // We can't use Interlocked.CompareExchange for enums + private static int _id = int.MaxValue; + + public static OperatingSystemId Id + { + get + { + if (_id == int.MaxValue) + { + Interlocked.CompareExchange(ref _id, (int)GetId(), int.MaxValue); + } + + return (OperatingSystemId)_id; + } + } + + public static string Name + { + get + { + switch (Id) + { + case OperatingSystemId.BSD: return "BSD"; + case OperatingSystemId.Linux: return "Linux"; + case OperatingSystemId.Darwin: return "macOS"; + case OperatingSystemId.Windows: return "Windows"; + default: throw new Exception($"Unknown OS {Id}"); + } + } + } + + private static OperatingSystemId GetId() + { + switch (Environment.OSVersion.Platform) + { + // On .NET Core `MacOSX` got replaced by `Unix`, this case should never be hit. + case PlatformID.MacOSX: + return OperatingSystemId.Darwin; + case PlatformID.Win32NT: + return OperatingSystemId.Windows; + case PlatformID.Unix: + default: + { + string osDescription = RuntimeInformation.OSDescription; + if (osDescription.IndexOf("linux", StringComparison.OrdinalIgnoreCase) != -1) + { + return OperatingSystemId.Linux; + } + else if (osDescription.IndexOf("darwin", StringComparison.OrdinalIgnoreCase) != -1) + { + return OperatingSystemId.Darwin; + } + else if (osDescription.IndexOf("bsd", StringComparison.OrdinalIgnoreCase) != -1) + { + return OperatingSystemId.BSD; + } + + throw new Exception($"Can't resolve OS with description: '{osDescription}'"); + } + } + } + } +} diff --git a/MediaBrowser.Model/System/IEnvironmentInfo.cs b/MediaBrowser.Model/System/IEnvironmentInfo.cs deleted file mode 100644 index 3ffcc7de14..0000000000 --- a/MediaBrowser.Model/System/IEnvironmentInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Runtime.InteropServices; - -namespace MediaBrowser.Model.System -{ - public interface IEnvironmentInfo - { - OperatingSystem OperatingSystem { get; } - string OperatingSystemName { get; } - string OperatingSystemVersion { get; } - Architecture SystemArchitecture { get; } - } - - public enum OperatingSystem - { - Windows, - Linux, - OSX, - BSD, - Android - } -} diff --git a/MediaBrowser.Model/System/OperatingSystemId.cs b/MediaBrowser.Model/System/OperatingSystemId.cs new file mode 100644 index 0000000000..e81dd4213f --- /dev/null +++ b/MediaBrowser.Model/System/OperatingSystemId.cs @@ -0,0 +1,10 @@ +namespace MediaBrowser.Model.System +{ + public enum OperatingSystemId + { + Windows, + Linux, + Darwin, + BSD + } +} From 80fb3dc2cb720269050a7a2d952bbb269c9e88c8 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 8 Mar 2019 06:36:00 +0100 Subject: [PATCH 14/48] Fix error --- MediaBrowser.Controller/Entities/BaseItem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 154b9470ef..e20641c99a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -39,7 +39,7 @@ namespace MediaBrowser.Controller.Entities /// /// The supported image extensions /// - public static readonly IReadOnlyList SupportedImageExtensions + public static readonly string[] SupportedImageExtensions = new [] { ".png", ".jpg", ".jpeg", ".tbn", ".gif" }; private static readonly List _supportedExtensions = new List(SupportedImageExtensions) From 045a0419f6983acfffe53591d24386c6c59d3901 Mon Sep 17 00:00:00 2001 From: Anthony Lavado Date: Fri, 8 Mar 2019 02:33:08 -0500 Subject: [PATCH 15/48] remove new file header text, and remove it from solution This removes the new file header text file from the repository, and also removes the include that was in the project solution. --- MediaBrowser.sln | 2 +- new-file-header.txt | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 new-file-header.txt diff --git a/MediaBrowser.sln b/MediaBrowser.sln index e43a582242..a3c0569bad 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -180,7 +180,7 @@ Global GlobalSection(MonoDevelopProperties) = preSolution Policies = $0 $0.StandardHeader = $1 - $1.Text = @### This header should be used to start new files.\n### It provides an explicit per-file license reference that should be present on all new files.\n### To use this header, delete these lines and the following empty line, modify to\n### the proper full path, and then add new code following the header and a single empty line.\n\n// ${FileName}\n// Part of the Jellyfin project (https://jellyfin.media)\n//\n// All copyright belongs to the Jellyfin contributors; a full list can\n// be found in the file CONTRIBUTORS.md\n//\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, version 2.\n//\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n + $1.IncludeInNewFiles = False $0.DotNetNamingPolicy = $2 $2.DirectoryNamespaceAssociation = PrefixedHierarchical EndGlobalSection diff --git a/new-file-header.txt b/new-file-header.txt deleted file mode 100644 index 4247a8e246..0000000000 --- a/new-file-header.txt +++ /dev/null @@ -1,22 +0,0 @@ -### This header should be used to start new files. -### It provides an explicit per-file license reference that should be present on all new files. -### To use this header, delete these lines and the following empty line, modify to -### the proper full path, and then add new code following the header and a single empty line. - -// -// Part of the Jellyfin project (https://jellyfin.media) -// -// All copyright belongs to the Jellyfin contributors; a full list can -// be found in the file CONTRIBUTORS.md -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . From e498e471091c8dd6f03b71c9f269dd546bc8dde3 Mon Sep 17 00:00:00 2001 From: dkanada Date: Fri, 8 Mar 2019 18:39:41 +0900 Subject: [PATCH 16/48] remove mirror images from library thumbnail --- Jellyfin.Drawing.Skia/StripCollageBuilder.cs | 52 ++------------------ 1 file changed, 5 insertions(+), 47 deletions(-) diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs index dfdf398710..f2162432a9 100644 --- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs +++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs @@ -78,20 +78,15 @@ namespace Jellyfin.Drawing.Skia canvas.Clear(SKColors.Black); // determine sizes for each image that will composited into the final image - var iSlice = Convert.ToInt32(width * 0.23475); - int iTrans = Convert.ToInt32(height * .25); - int iHeight = Convert.ToInt32(height * .70); - var horizontalImagePadding = Convert.ToInt32(width * 0.0125); - var verticalSpacing = Convert.ToInt32(height * 0.01111111111111111111111111111111); + var iSlice = Convert.ToInt32(width * 0.33); + int iTrans = Convert.ToInt32(height * 0.25); + int iHeight = Convert.ToInt32(height * 1.00); int imageIndex = 0; - - for (int i = 0; i < 4; i++) + for (int i = 0; i < 3; i++) { - using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) { imageIndex = newIndex; - if (currentBitmap == null) { continue; @@ -108,44 +103,7 @@ namespace Jellyfin.Drawing.Skia using (var subset = image.Subset(SKRectI.Create(ix, 0, iSlice, iHeight))) { // draw image onto canvas - canvas.DrawImage(subset ?? image, (horizontalImagePadding * (i + 1)) + (iSlice * i), verticalSpacing); - - if (subset == null) - { - continue; - } - // create reflection of image below the drawn image - using (var croppedBitmap = SKBitmap.FromImage(subset)) - using (var reflectionBitmap = new SKBitmap(croppedBitmap.Width, croppedBitmap.Height / 2, croppedBitmap.ColorType, croppedBitmap.AlphaType)) - { - // resize to half height - currentBitmap.ScalePixels(reflectionBitmap, SKFilterQuality.High); - - using (var flippedBitmap = new SKBitmap(reflectionBitmap.Width, reflectionBitmap.Height, reflectionBitmap.ColorType, reflectionBitmap.AlphaType)) - using (var flippedCanvas = new SKCanvas(flippedBitmap)) - { - // flip image vertically - var matrix = SKMatrix.MakeScale(1, -1); - matrix.SetScaleTranslate(1, -1, 0, flippedBitmap.Height); - flippedCanvas.SetMatrix(matrix); - flippedCanvas.DrawBitmap(reflectionBitmap, 0, 0); - flippedCanvas.ResetMatrix(); - - // create gradient to make image appear as a reflection - var remainingHeight = height - (iHeight + (2 * verticalSpacing)); - flippedCanvas.ClipRect(SKRect.Create(reflectionBitmap.Width, remainingHeight)); - using (var gradient = new SKPaint()) - { - gradient.IsAntialias = true; - gradient.BlendMode = SKBlendMode.SrcOver; - gradient.Shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(0, remainingHeight), new[] { new SKColor(0, 0, 0, 128), new SKColor(0, 0, 0, 208), new SKColor(0, 0, 0, 240), new SKColor(0, 0, 0, 255) }, null, SKShaderTileMode.Clamp); - flippedCanvas.DrawPaint(gradient); - } - - // finally draw reflection onto canvas - canvas.DrawBitmap(flippedBitmap, (horizontalImagePadding * (i + 1)) + (iSlice * i), iHeight + (2 * verticalSpacing)); - } - } + canvas.DrawImage(subset ?? image, iSlice * i, 0); } } } From 58061a729528e3969b07b35fdaac534f5948eb89 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Fri, 8 Mar 2019 17:15:52 +0100 Subject: [PATCH 17/48] Make MusicBrainz base url configurable --- Emby.Server.Implementations/ConfigurationOptions.cs | 3 ++- MediaBrowser.Providers/MediaBrowser.Providers.csproj | 1 + .../Music/MusicBrainzAlbumProvider.cs | 12 ++++++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs index 30bfd87498..9bc60972a1 100644 --- a/Emby.Server.Implementations/ConfigurationOptions.cs +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -6,7 +6,8 @@ namespace Emby.Server.Implementations { public static readonly Dictionary Configuration = new Dictionary { - {"HttpListenerHost:DefaultRedirectPath", "web/index.html"} + {"HttpListenerHost:DefaultRedirectPath", "web/index.html"}, + {"MusicBrainz:BaseUrl", "https://www.musicbrainz.org"} }; } } diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 52a52efdc0..cfbb85ea6b 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -11,6 +11,7 @@ + diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index e4bb52217c..7e47c0b2a5 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -16,6 +16,7 @@ using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Xml; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace MediaBrowser.Providers.Music @@ -30,15 +31,22 @@ namespace MediaBrowser.Providers.Music private readonly IJsonSerializer _json; private readonly IXmlReaderSettingsFactory _xmlSettings; - public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org"; + public readonly string MusicBrainzBaseUrl; - public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger, IJsonSerializer json, IXmlReaderSettingsFactory xmlSettings) + public MusicBrainzAlbumProvider( + IHttpClient httpClient, + IApplicationHost appHost, + ILogger logger, + IJsonSerializer json, + IXmlReaderSettingsFactory xmlSettings, + IConfiguration configuration) { _httpClient = httpClient; _appHost = appHost; _logger = logger; _json = json; _xmlSettings = xmlSettings; + MusicBrainzBaseUrl = configuration["MusicBrainz:BaseUrl"]; Current = this; } From f2062ba19bb38a2dfa6b10ab778718730fe0f14a Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Fri, 8 Mar 2019 22:25:45 +0100 Subject: [PATCH 18/48] Disable HTTPS in Kestrel if Certificate is null --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f7d9bad1b0..ae54606747 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -629,7 +629,7 @@ namespace Emby.Server.Implementations { options.ListenAnyIP(HttpPort); - if (EnableHttps) + if (EnableHttps && Certificate != null) { options.ListenAnyIP(HttpsPort, listenOptions => { listenOptions.UseHttps(Certificate); }); } From 47095e6cf87d73aad2abf2f9f326631cf95704fa Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 9 Mar 2019 11:17:02 +0900 Subject: [PATCH 19/48] move a variable out of for loop --- Jellyfin.Drawing.Skia/StripCollageBuilder.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs index f2162432a9..7d404ce644 100644 --- a/Jellyfin.Drawing.Skia/StripCollageBuilder.cs +++ b/Jellyfin.Drawing.Skia/StripCollageBuilder.cs @@ -77,12 +77,14 @@ namespace Jellyfin.Drawing.Skia { canvas.Clear(SKColors.Black); + // number of images used in the thumbnail + var iCount = 3; + // determine sizes for each image that will composited into the final image - var iSlice = Convert.ToInt32(width * 0.33); - int iTrans = Convert.ToInt32(height * 0.25); + var iSlice = Convert.ToInt32(width / iCount); int iHeight = Convert.ToInt32(height * 1.00); int imageIndex = 0; - for (int i = 0; i < 3; i++) + for (int i = 0; i < iCount; i++) { using (var currentBitmap = GetNextValidImage(paths, imageIndex, out int newIndex)) { From 93fe7957fb4ed4f85b14bc4560f8e595540e91bd Mon Sep 17 00:00:00 2001 From: Matsuri Date: Fri, 1 Mar 2019 05:50:39 +0000 Subject: [PATCH 20/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index 8910a6bce8..6f7d362d3b 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 服务器加载中。请稍后再试。", From 16adaa64c9c94ea35ffd99df114a0b8de9249cf6 Mon Sep 17 00:00:00 2001 From: WWWesten Date: Mon, 4 Mar 2019 12:00:32 +0000 Subject: [PATCH 21/48] 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(-) diff --git a/Emby.Server.Implementations/Localization/Core/kk.json b/Emby.Server.Implementations/Localization/Core/kk.json index 658d168e9f..23841f37d6 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", From 93d15cd96972588bbbc29a9398c9d4b050d30411 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 16:17:48 -0400 Subject: [PATCH 22/48] Add configuration flag for Web directory --- .../AppBase/BaseApplicationPaths.cs | 4 +++- .../ServerApplicationPaths.cs | 6 ++++-- Jellyfin.Server/Program.cs | 19 ++++++++++++++++++- Jellyfin.Server/StartupOptions.cs | 3 +++ 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index 65cdccfa5d..3ee09c9c04 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -17,12 +17,14 @@ namespace Emby.Server.Implementations.AppBase string programDataPath, string logDirectoryPath, string configurationDirectoryPath, - string cacheDirectoryPath) + string cacheDirectoryPath, + string webDirectoryPath) { ProgramDataPath = programDataPath; LogDirectoryPath = logDirectoryPath; ConfigurationDirectoryPath = configurationDirectoryPath; CachePath = cacheDirectoryPath; + WebPath = webDirectoryPath; DataPath = Path.Combine(ProgramDataPath, "data"); } diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index 05f6469ece..adaf23234f 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -17,11 +17,13 @@ namespace Emby.Server.Implementations string programDataPath, string logDirectoryPath, string configurationDirectoryPath, - string cacheDirectoryPath) + string cacheDirectoryPath, + string webDirectoryPath) : base(programDataPath, logDirectoryPath, configurationDirectoryPath, - cacheDirectoryPath) + cacheDirectoryPath, + webDirectoryPath) { } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 0ef1711d4c..3d81ade35c 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -264,6 +264,23 @@ namespace Jellyfin.Server } } + // webDir + // IF --webdir + // ELSE IF $JELLYFIN_WEB_DIR + // ELSE use /jellyfin-web + var webDir = options.WebDir; + + if (string.IsNullOrEmpty(webDir)) + { + webDir = Environment.GetEnvironmentVariable("JELLYFIN_WEB_DIR"); + + if (string.IsNullOrEmpty(webDir)) + { + // Use default location under ResourcesPath + webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web") + } + } + // logDir // IF --logdir // ELSE IF $JELLYFIN_LOG_DIR @@ -296,7 +313,7 @@ namespace Jellyfin.Server Environment.Exit(1); } - return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir); + return new ServerApplicationPaths(dataDir, logDir, configDir, cacheDir, webDir); } private static async Task CreateConfiguration(IApplicationPaths appPaths) diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index c8cdb984db..2b01c7bbdf 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -11,6 +11,9 @@ namespace Jellyfin.Server [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")] public string DataDir { get; set; } + [Option('w', "webdir", Required = false, HelpText = "Path to the Jellyfin web resources.")] + public string WebDir { get; set; } + [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")] public string CacheDir { get; set; } From 25deca95793581df85dab8c454d53a1d07a6ab53 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 16:20:46 -0400 Subject: [PATCH 23/48] Make use of WebPath --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- MediaBrowser.WebDashboard/Api/DashboardService.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ae54606747..05ede0ddab 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -621,7 +621,7 @@ namespace Emby.Server.Implementations string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; if (string.IsNullOrEmpty(contentRoot)) { - contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths.ApplicationResourcesPath, "jellyfin-web", "src"); + contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths,WebPath, "src"); } var host = new WebHostBuilder() diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 531978e1dd..05df54b115 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.WebDashboard.Api return _serverConfigurationManager.Configuration.DashboardSourcePath; } - return Path.Combine(_serverConfigurationManager.ApplicationPaths.ApplicationResourcesPath, "jellyfin-web", "src"); + return Path.Combine(_serverConfigurationManager.ApplicationPaths.WebPath, "src"); } } From 132ce3ece14ff7ca756c81e0a12172744c5c50aa Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 17:04:18 -0400 Subject: [PATCH 24/48] Add further resources to complete WebPath --- Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs | 6 ++++++ Emby.Server.Implementations/ApplicationHost.cs | 4 +++- Emby.Server.Implementations/ServerApplicationPaths.cs | 6 ++++++ Jellyfin.Server/Program.cs | 2 +- MediaBrowser.Common/Configuration/IApplicationPaths.cs | 6 ++++++ MediaBrowser.Model/System/SystemInfo.cs | 6 ++++++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index 3ee09c9c04..fd9ce3a364 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -35,6 +35,12 @@ namespace Emby.Server.Implementations.AppBase /// The program data path. public string ProgramDataPath { get; private set; } + /// + /// Gets the path to the web resources folder + /// + /// The web resources path. + public string WebPath { get; set; } + /// /// Gets the path to the system folder /// diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 05ede0ddab..f240ef871a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -621,7 +621,7 @@ namespace Emby.Server.Implementations string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; if (string.IsNullOrEmpty(contentRoot)) { - contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths,WebPath, "src"); + contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths.WebPath, "src"); } var host = new WebHostBuilder() @@ -921,6 +921,7 @@ namespace Emby.Server.Implementations logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive); logger.LogInformation("Processor count: {ProcessorCount}", Environment.ProcessorCount); logger.LogInformation("Program data path: {ProgramDataPath}", appPaths.ProgramDataPath); + logger.LogInformation("Web resources path: {WebPath}", appPaths.WebPath); logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath); } @@ -1393,6 +1394,7 @@ namespace Emby.Server.Implementations CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(), Id = SystemId, ProgramDataPath = ApplicationPaths.ProgramDataPath, + WebPath = ApplicationPaths.WebPath, LogPath = ApplicationPaths.LogDirectoryPath, ItemsByNamePath = ApplicationPaths.InternalMetadataPath, InternalMetadataPath = ApplicationPaths.InternalMetadataPath, diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index adaf23234f..68d5881220 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -35,6 +35,12 @@ namespace Emby.Server.Implementations /// The root folder path. public string RootFolderPath => Path.Combine(ProgramDataPath, "root"); +/* /// + /// Gets the path to the Web resources + /// + /// The web folder path. + public string WebPath => WebPath; */ + /// /// Gets the path to the default user view directory. Used if no specific user view is defined. /// diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 3d81ade35c..8f1498b13b 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -277,7 +277,7 @@ namespace Jellyfin.Server if (string.IsNullOrEmpty(webDir)) { // Use default location under ResourcesPath - webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web") + webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web"); } } diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index cb4e8bf5f0..1f56c98fd8 100644 --- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -11,6 +11,12 @@ namespace MediaBrowser.Common.Configuration /// The program data path. string ProgramDataPath { get; } + /// + /// Gets the path to the web resources folder + /// + /// The web resources path. + string WebPath { get; } + /// /// Gets the path to the program system folder /// diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index 6482f2c840..fa72624819 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -83,6 +83,12 @@ namespace MediaBrowser.Model.System /// The program data path. public string ProgramDataPath { get; set; } + /// + /// Gets or sets the web resources path. + /// + /// The web resources path. + public string WebPath { get; set; } + /// /// Gets or sets the items by name path. /// From ecf85a73ec4aa918dc9a816dc60e6e5d76a36ecd Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 17:09:51 -0400 Subject: [PATCH 25/48] Use environment variables instead of opts for Deb --- deployment/debian-package-x64/pkg-src/conf/jellyfin | 10 +++++----- deployment/debian-package-x64/pkg-src/jellyfin.service | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin b/deployment/debian-package-x64/pkg-src/conf/jellyfin index 58fe79332a..7db482d428 100644 --- a/deployment/debian-package-x64/pkg-src/conf/jellyfin +++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin @@ -13,10 +13,10 @@ # # Program directories -JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin" -JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin" -JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin" -JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin" +JELLYFIN_DATA_DIR="/var/lib/jellyfin" +JELLYFIN_CONFIG_DIR="/etc/jellyfin" +JELLYFIN_LOG_DIR="/var/log/jellyfin" +JELLYFIN_CACHE_DIR="/var/cache/jellyfin" # Restart script for in-app server control JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh" @@ -38,4 +38,4 @@ JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/share/jellyfin-ffmpeg/ffprobe" # Application username JELLYFIN_USER="jellyfin" # Full application command -JELLYFIN_ARGS="--datadir=$JELLYFIN_DATA_DIRECTORY --configdir=$JELLYFIN_CONFIG_DIRECTORY --logdir=$JELLYFIN_LOG_DIRECTORY --cachedir=$JELLYFIN_CACHE_DIRECTORY $JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_FFPROBE_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT" +JELLYFIN_ARGS="$JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_FFPROBE_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT" diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.service b/deployment/debian-package-x64/pkg-src/jellyfin.service index 9c6c6667f1..b4da3a945b 100644 --- a/deployment/debian-package-x64/pkg-src/jellyfin.service +++ b/deployment/debian-package-x64/pkg-src/jellyfin.service @@ -6,7 +6,7 @@ After = network.target Type = simple EnvironmentFile = /etc/default/jellyfin User = jellyfin -ExecStart = /usr/bin/jellyfin --datadir=${JELLYFIN_DATA_DIRECTORY} --configdir=${JELLYFIN_CONFIG_DIRECTORY} --logdir=${JELLYFIN_LOG_DIRECTORY} --cachedir=${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} +ExecStart = /usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} Restart = on-failure TimeoutSec = 15 From 86f5221f96b09bde177c881eb34cad0ec10cbe90 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 17:11:16 -0400 Subject: [PATCH 26/48] Use environment variables instead of opts for RPM --- deployment/fedora-package-x64/pkg-src/jellyfin.env | 8 ++++---- deployment/fedora-package-x64/pkg-src/jellyfin.service | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env index abfa670e4a..143a317c43 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.env +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.env @@ -15,10 +15,10 @@ # # Program directories -JELLYFIN_DATA_DIRECTORY="/var/lib/jellyfin" -JELLYFIN_CONFIG_DIRECTORY="/etc/jellyfin" -JELLYFIN_LOG_DIRECTORY="/var/log/jellyfin" -JELLYFIN_CACHE_DIRECTORY="/var/cache/jellyfin" +JELLYFIN_DATA_DIR="/var/lib/jellyfin" +JELLYFIN_CONFIG_DIR="/etc/jellyfin" +JELLYFIN_LOG_DIR="/var/log/jellyfin" +JELLYFIN_CACHE_DIR="/var/cache/jellyfin" # In-App service control JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh" diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.service b/deployment/fedora-package-x64/pkg-src/jellyfin.service index d58df9d949..1f83d3d386 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.service +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.service @@ -5,7 +5,7 @@ Description=Jellyfin is a free software media system that puts you in control of [Service] EnvironmentFile=/etc/sysconfig/jellyfin WorkingDirectory=/var/lib/jellyfin -ExecStart=/usr/bin/jellyfin --datadir=${JELLYFIN_DATA_DIRECTORY} --configdir=${JELLYFIN_CONFIG_DIRECTORY} --logdir=${JELLYFIN_LOG_DIRECTORY} --cachedir=${JELLYFIN_CACHE_DIRECTORY} ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} +ExecStart=/usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} TimeoutSec=15 Restart=on-failure User=jellyfin From 5f7524aca26797a3dc7acbed8cd50e113e2f9a4d Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 17:21:10 -0400 Subject: [PATCH 27/48] Remove unneccessary string --- Emby.Server.Implementations/ServerApplicationPaths.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Emby.Server.Implementations/ServerApplicationPaths.cs b/Emby.Server.Implementations/ServerApplicationPaths.cs index 68d5881220..adaf23234f 100644 --- a/Emby.Server.Implementations/ServerApplicationPaths.cs +++ b/Emby.Server.Implementations/ServerApplicationPaths.cs @@ -35,12 +35,6 @@ namespace Emby.Server.Implementations /// The root folder path. public string RootFolderPath => Path.Combine(ProgramDataPath, "root"); -/* /// - /// Gets the path to the Web resources - /// - /// The web folder path. - public string WebPath => WebPath; */ - /// /// Gets the path to the default user view directory. Used if no specific user view is defined. /// From 5268553e7fae2975ede06a944944f3b508453a1a Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 18:24:11 -0400 Subject: [PATCH 28/48] Have datadir envvar match the others --- Jellyfin.Server/Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 0ef1711d4c..c2268c8025 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -174,7 +174,7 @@ namespace Jellyfin.Server { // dataDir // IF --datadir - // ELSE IF $JELLYFIN_DATA_PATH + // ELSE IF $JELLYFIN_DATA_DIR // ELSE IF windows, use <%APPDATA%>/jellyfin // ELSE IF $XDG_DATA_HOME then use $XDG_DATA_HOME/jellyfin // ELSE use $HOME/.local/share/jellyfin @@ -182,7 +182,7 @@ namespace Jellyfin.Server if (string.IsNullOrEmpty(dataDir)) { - dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_PATH"); + dataDir = Environment.GetEnvironmentVariable("JELLYFIN_DATA_DIR"); if (string.IsNullOrEmpty(dataDir)) { From 037cf9e1eeb4e500b4bdc379c76fe5a5922c7f54 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Sun, 10 Mar 2019 18:30:10 -0400 Subject: [PATCH 29/48] Move CreateDirectory for dataDir to try block --- Jellyfin.Server/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index c2268c8025..fa4b7b8e52 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -191,8 +191,6 @@ namespace Jellyfin.Server } } - Directory.CreateDirectory(dataDir); - // configDir // IF --configdir // ELSE IF $JELLYFIN_CONFIG_DIR @@ -285,6 +283,7 @@ namespace Jellyfin.Server // Ensure the main folders exist before we continue try { + Directory.CreateDirectory(dataDir); Directory.CreateDirectory(logDir); Directory.CreateDirectory(configDir); Directory.CreateDirectory(cacheDir); From 7322485a6d264037f2e26bf40bac93d6598e7bff Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 11 Mar 2019 20:44:12 +0100 Subject: [PATCH 30/48] Skip processing of images that don't exist --- Emby.Drawing/ImageProcessor.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Emby.Drawing/ImageProcessor.cs b/Emby.Drawing/ImageProcessor.cs index faaeb5af84..6d209d8d01 100644 --- a/Emby.Drawing/ImageProcessor.cs +++ b/Emby.Drawing/ImageProcessor.cs @@ -180,6 +180,12 @@ namespace Emby.Drawing var supportedImageInfo = await GetSupportedImage(originalImagePath, dateModified).ConfigureAwait(false); originalImagePath = supportedImageInfo.path; + + if (!File.Exists(originalImagePath)) + { + return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); + } + dateModified = supportedImageInfo.dateModified; bool requiresTransparency = TransparentImageTypes.Contains(Path.GetExtension(originalImagePath)); @@ -265,8 +271,6 @@ namespace Emby.Drawing { // If it fails for whatever reason, return the original image _logger.LogError(ex, "Error encoding image"); - - // Just spit out the original file if all the options are default return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified); } finally From 0ff038f0a2c90ba0ad671eae1ac3c74a7602b855 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 11 Mar 2019 23:13:01 +0100 Subject: [PATCH 31/48] Fix nullref --- Emby.Server.Implementations/ApplicationHost.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ae54606747..d7696393db 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -700,6 +700,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(ApplicationPaths); + serviceCollection.AddSingleton(_configuration); + serviceCollection.AddSingleton(JsonSerializer); serviceCollection.AddSingleton(LoggerFactory); From 715ddbb3b08cab2ff64919f577d5f72d9af5ea22 Mon Sep 17 00:00:00 2001 From: dkanada Date: Mon, 11 Mar 2019 18:10:31 -0700 Subject: [PATCH 32/48] remove open subtitles from the server --- .../Emby.Server.Implementations.csproj | 1 - .../MediaBrowser.MediaEncoding.csproj | 1 - .../Subtitles/ConfigurationExtension.cs | 29 - .../Subtitles/OpenSubtitleDownloader.cs | 347 --- MediaBrowser.sln | 2 - OpenSubtitlesHandler/Console/OSHConsole.cs | 92 - .../Interfaces/IMethodResponse.cs | 71 - .../Interfaces/MethodResponseAttr.cs | 40 - .../Languages/DetectLanguageResult.cs | 31 - .../MethodResponseAddComment.cs | 32 - .../MethodResponseAddRequest.cs | 35 - .../MethodResponseAutoUpdate.cs | 59 - .../MethodResponseCheckMovieHash.cs | 37 - .../MethodResponseCheckMovieHash2.cs | 37 - .../MethodResponseCheckSubHash.cs | 38 - .../MethodResponseDetectLanguage.cs | 37 - .../MethodResponses/MethodResponseError.cs | 36 - .../MethodResponseGetAvailableTranslations.cs | 37 - .../MethodResponseGetComments.cs | 39 - .../MethodResponseGetSubLanguages.cs | 39 - .../MethodResponseGetTranslation.cs | 36 - .../MethodResponseInsertMovie.cs | 36 - .../MethodResponseInsertMovieHash.cs | 38 - .../MethodResponses/MethodResponseLogIn.cs | 39 - .../MethodResponseMovieDetails.cs | 73 - .../MethodResponseMovieSearch.cs | 43 - .../MethodResponseNoOperation.cs | 52 - .../MethodResponseReportWrongImdbMovie.cs | 33 - .../MethodResponseReportWrongMovieHash.cs | 33 - .../MethodResponseSearchToMail.cs | 32 - .../MethodResponseServerInfo.cs | 131 - .../MethodResponseSubtitleDownload.cs | 44 - .../MethodResponseSubtitleSearch.cs | 46 - .../MethodResponseSubtitlesVote.cs | 43 - .../MethodResponseTryUploadSubtitles.cs | 40 - .../MethodResponseUploadSubtitles.cs | 38 - OpenSubtitlesHandler/Methods Implemeted.txt | 39 - OpenSubtitlesHandler/MovieHasher.cs | 48 - .../Movies/CheckMovieHash2Data.cs | 42 - .../Movies/CheckMovieHash2Result.cs | 37 - .../Movies/CheckMovieHashResult.cs | 41 - .../Movies/InsertMovieHashParameters.cs | 38 - .../Movies/MovieSearchResult.cs | 40 - .../Movies/SearchToMailMovieParameter.cs | 30 - OpenSubtitlesHandler/OpenSubtitles.cs | 2744 ----------------- .../OpenSubtitlesHandler.csproj | 13 - .../GetAvailableTranslationsResult.cs | 39 - .../OtherTypes/GetCommentsResult.cs | 36 - .../Properties/AssemblyInfo.cs | 24 - OpenSubtitlesHandler/Readme.txt | 20 - .../SubtitleTypes/CheckSubHashResult.cs | 30 - .../SubtitleTypes/SubtitleDownloadResult.cs | 43 - .../SubtitleTypes/SubtitleLanguage.cs | 39 - .../SubtitleTypes/SubtitleSearchParameters.cs | 82 - .../SubtitleTypes/SubtitleSearchResult.cs | 136 - .../TryUploadSubtitlesParameters.cs | 47 - .../UploadSubtitleInfoParameter.cs | 46 - .../SubtitleTypes/UploadSubtitleParameters.cs | 52 - OpenSubtitlesHandler/Utilities.cs | 174 -- OpenSubtitlesHandler/XML-RPC/Docs/XML-RPC.txt | 225 -- .../XML-RPC/Enums/XmlRpcValueType.cs | 25 - .../XML-RPC/Types/XmlRpcMethodCall.cs | 63 - .../XML-RPC/Values/IXmlRpcValue.cs | 36 - .../XML-RPC/Values/XmlRpcStructMember.cs | 43 - .../XML-RPC/Values/XmlRpcValueArray.cs | 121 - .../XML-RPC/Values/XmlRpcValueBasic.cs | 99 - .../XML-RPC/Values/XmlRpcValueStruct.cs | 43 - .../XML-RPC/XmlRpcGenerator.cs | 350 --- 68 files changed, 6642 deletions(-) delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs delete mode 100644 OpenSubtitlesHandler/Console/OSHConsole.cs delete mode 100644 OpenSubtitlesHandler/Interfaces/IMethodResponse.cs delete mode 100644 OpenSubtitlesHandler/Interfaces/MethodResponseAttr.cs delete mode 100644 OpenSubtitlesHandler/Languages/DetectLanguageResult.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseAddComment.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseAddRequest.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseAutoUpdate.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash2.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseCheckSubHash.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseDetectLanguage.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseError.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseGetAvailableTranslations.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseGetComments.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseGetSubLanguages.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseGetTranslation.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovie.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovieHash.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseLogIn.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseMovieDetails.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseMovieSearch.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseNoOperation.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongImdbMovie.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongMovieHash.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseSearchToMail.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseServerInfo.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleDownload.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleSearch.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitlesVote.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseTryUploadSubtitles.cs delete mode 100644 OpenSubtitlesHandler/MethodResponses/MethodResponseUploadSubtitles.cs delete mode 100644 OpenSubtitlesHandler/Methods Implemeted.txt delete mode 100644 OpenSubtitlesHandler/MovieHasher.cs delete mode 100644 OpenSubtitlesHandler/Movies/CheckMovieHash2Data.cs delete mode 100644 OpenSubtitlesHandler/Movies/CheckMovieHash2Result.cs delete mode 100644 OpenSubtitlesHandler/Movies/CheckMovieHashResult.cs delete mode 100644 OpenSubtitlesHandler/Movies/InsertMovieHashParameters.cs delete mode 100644 OpenSubtitlesHandler/Movies/MovieSearchResult.cs delete mode 100644 OpenSubtitlesHandler/Movies/SearchToMailMovieParameter.cs delete mode 100644 OpenSubtitlesHandler/OpenSubtitles.cs delete mode 100644 OpenSubtitlesHandler/OpenSubtitlesHandler.csproj delete mode 100644 OpenSubtitlesHandler/OtherTypes/GetAvailableTranslationsResult.cs delete mode 100644 OpenSubtitlesHandler/OtherTypes/GetCommentsResult.cs delete mode 100644 OpenSubtitlesHandler/Properties/AssemblyInfo.cs delete mode 100644 OpenSubtitlesHandler/Readme.txt delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/CheckSubHashResult.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/SubtitleDownloadResult.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/SubtitleLanguage.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchParameters.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchResult.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/TryUploadSubtitlesParameters.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleInfoParameter.cs delete mode 100644 OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleParameters.cs delete mode 100644 OpenSubtitlesHandler/Utilities.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Docs/XML-RPC.txt delete mode 100644 OpenSubtitlesHandler/XML-RPC/Enums/XmlRpcValueType.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Types/XmlRpcMethodCall.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Values/IXmlRpcValue.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Values/XmlRpcStructMember.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueArray.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueBasic.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueStruct.cs delete mode 100644 OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 39e9ed3756..0b0dab2139 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -13,7 +13,6 @@ - diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 68b8bd4fae..e4757543ea 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -14,7 +14,6 @@ - diff --git a/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs b/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs deleted file mode 100644 index 92544f4f62..0000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/ConfigurationExtension.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Model.Providers; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - public static class ConfigurationExtension - { - public static SubtitleOptions GetSubtitleConfiguration(this IConfigurationManager manager) - { - return manager.GetConfiguration("subtitles"); - } - } - - public class SubtitleConfigurationFactory : IConfigurationFactory - { - public IEnumerable GetConfigurations() - { - return new List - { - new ConfigurationStore - { - Key = "subtitles", - ConfigurationType = typeof (SubtitleOptions) - } - }; - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs b/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs deleted file mode 100644 index a7e3f61972..0000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/OpenSubtitleDownloader.cs +++ /dev/null @@ -1,347 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Providers; -using MediaBrowser.Controller.Security; -using MediaBrowser.Controller.Subtitles; -using MediaBrowser.Model.Dto; -using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Providers; -using MediaBrowser.Model.Serialization; -using Microsoft.Extensions.Logging; -using OpenSubtitlesHandler; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - public class OpenSubtitleDownloader : ISubtitleProvider, IDisposable - { - private readonly ILogger _logger; - private readonly IHttpClient _httpClient; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - - private readonly IServerConfigurationManager _config; - - private readonly IJsonSerializer _json; - private readonly IFileSystem _fileSystem; - - public OpenSubtitleDownloader(ILoggerFactory loggerFactory, IHttpClient httpClient, IServerConfigurationManager config, IJsonSerializer json, IFileSystem fileSystem) - { - _logger = loggerFactory.CreateLogger(GetType().Name); - _httpClient = httpClient; - _config = config; - _json = json; - _fileSystem = fileSystem; - - _config.NamedConfigurationUpdating += _config_NamedConfigurationUpdating; - - Utilities.HttpClient = httpClient; - OpenSubtitles.SetUserAgent("jellyfin"); - } - - private const string PasswordHashPrefix = "h:"; - void _config_NamedConfigurationUpdating(object sender, ConfigurationUpdateEventArgs e) - { - if (!string.Equals(e.Key, "subtitles", StringComparison.OrdinalIgnoreCase)) - { - return; - } - - var options = (SubtitleOptions)e.NewConfiguration; - - if (options != null && - !string.IsNullOrWhiteSpace(options.OpenSubtitlesPasswordHash) && - !options.OpenSubtitlesPasswordHash.StartsWith(PasswordHashPrefix, StringComparison.OrdinalIgnoreCase)) - { - options.OpenSubtitlesPasswordHash = EncodePassword(options.OpenSubtitlesPasswordHash); - } - } - - private static string EncodePassword(string password) - { - var bytes = Encoding.UTF8.GetBytes(password); - return PasswordHashPrefix + Convert.ToBase64String(bytes); - } - - private static string DecodePassword(string password) - { - if (password == null || - !password.StartsWith(PasswordHashPrefix, StringComparison.OrdinalIgnoreCase)) - { - return string.Empty; - } - - var bytes = Convert.FromBase64String(password.Substring(2)); - return Encoding.UTF8.GetString(bytes, 0, bytes.Length); - } - - public string Name => "Open Subtitles"; - - private SubtitleOptions GetOptions() - { - return _config.GetSubtitleConfiguration(); - } - - public IEnumerable SupportedMediaTypes - { - get - { - var options = GetOptions(); - - if (string.IsNullOrWhiteSpace(options.OpenSubtitlesUsername) || - string.IsNullOrWhiteSpace(options.OpenSubtitlesPasswordHash)) - { - return new VideoContentType[] { }; - } - - return new[] { VideoContentType.Episode, VideoContentType.Movie }; - } - } - - public Task GetSubtitles(string id, CancellationToken cancellationToken) - { - return GetSubtitlesInternal(id, GetOptions(), cancellationToken); - } - - private DateTime _lastRateLimitException; - private async Task GetSubtitlesInternal(string id, - SubtitleOptions options, - CancellationToken cancellationToken) - { - if (string.IsNullOrWhiteSpace(id)) - { - throw new ArgumentNullException(nameof(id)); - } - - var idParts = id.Split(new[] { '-' }, 3); - - var format = idParts[0]; - var language = idParts[1]; - var ossId = idParts[2]; - - var downloadsList = new[] { int.Parse(ossId, _usCulture) }; - - await Login(cancellationToken).ConfigureAwait(false); - - if ((DateTime.UtcNow - _lastRateLimitException).TotalHours < 1) - { - throw new RateLimitExceededException("OpenSubtitles rate limit reached"); - } - - var resultDownLoad = await OpenSubtitles.DownloadSubtitlesAsync(downloadsList, cancellationToken).ConfigureAwait(false); - - if ((resultDownLoad.Status ?? string.Empty).IndexOf("407", StringComparison.OrdinalIgnoreCase) != -1) - { - _lastRateLimitException = DateTime.UtcNow; - throw new RateLimitExceededException("OpenSubtitles rate limit reached"); - } - - if (!(resultDownLoad is MethodResponseSubtitleDownload)) - { - throw new Exception("Invalid response type"); - } - - var results = ((MethodResponseSubtitleDownload)resultDownLoad).Results; - - _lastRateLimitException = DateTime.MinValue; - - if (results.Count == 0) - { - var msg = string.Format("Subtitle with Id {0} was not found. Name: {1}. Status: {2}. Message: {3}", - ossId, - resultDownLoad.Name ?? string.Empty, - resultDownLoad.Status ?? string.Empty, - resultDownLoad.Message ?? string.Empty); - - throw new ResourceNotFoundException(msg); - } - - var data = Convert.FromBase64String(results.First().Data); - - return new SubtitleResponse - { - Format = format, - Language = language, - - Stream = new MemoryStream(Utilities.Decompress(new MemoryStream(data))) - }; - } - - private DateTime _lastLogin; - private async Task Login(CancellationToken cancellationToken) - { - if ((DateTime.UtcNow - _lastLogin).TotalSeconds < 60) - { - return; - } - - var options = GetOptions(); - - var user = options.OpenSubtitlesUsername ?? string.Empty; - var password = DecodePassword(options.OpenSubtitlesPasswordHash); - - var loginResponse = await OpenSubtitles.LogInAsync(user, password, "en", cancellationToken).ConfigureAwait(false); - - if (!(loginResponse is MethodResponseLogIn)) - { - throw new Exception("Authentication to OpenSubtitles failed."); - } - - _lastLogin = DateTime.UtcNow; - } - - public async Task> GetSupportedLanguages(CancellationToken cancellationToken) - { - await Login(cancellationToken).ConfigureAwait(false); - - var result = OpenSubtitles.GetSubLanguages("en"); - if (!(result is MethodResponseGetSubLanguages)) - { - _logger.LogError("Invalid response type"); - return new List(); - } - - var results = ((MethodResponseGetSubLanguages)result).Languages; - - return results.Select(i => new NameIdPair - { - Name = i.LanguageName, - Id = i.SubLanguageID - }); - } - - private string NormalizeLanguage(string language) - { - // Problem with Greek subtitle download #1349 - if (string.Equals(language, "gre", StringComparison.OrdinalIgnoreCase)) - { - - return "ell"; - } - - return language; - } - - public async Task> Search(SubtitleSearchRequest request, CancellationToken cancellationToken) - { - var imdbIdText = request.GetProviderId(MetadataProviders.Imdb); - long imdbId = 0; - - switch (request.ContentType) - { - case VideoContentType.Episode: - if (!request.IndexNumber.HasValue || !request.ParentIndexNumber.HasValue || string.IsNullOrEmpty(request.SeriesName)) - { - _logger.LogDebug("Episode information missing"); - return new List(); - } - break; - case VideoContentType.Movie: - if (string.IsNullOrEmpty(request.Name)) - { - _logger.LogDebug("Movie name missing"); - return new List(); - } - if (string.IsNullOrWhiteSpace(imdbIdText) || !long.TryParse(imdbIdText.TrimStart('t'), NumberStyles.Any, _usCulture, out imdbId)) - { - _logger.LogDebug("Imdb id missing"); - return new List(); - } - break; - } - - if (string.IsNullOrEmpty(request.MediaPath)) - { - _logger.LogDebug("Path Missing"); - return new List(); - } - - await Login(cancellationToken).ConfigureAwait(false); - - var subLanguageId = NormalizeLanguage(request.Language); - string hash; - - using (var fileStream = File.OpenRead(request.MediaPath)) - { - hash = Utilities.ComputeHash(fileStream); - } - var fileInfo = _fileSystem.GetFileInfo(request.MediaPath); - var movieByteSize = fileInfo.Length; - var searchImdbId = request.ContentType == VideoContentType.Movie ? imdbId.ToString(_usCulture) : ""; - var subtitleSearchParameters = request.ContentType == VideoContentType.Episode - ? new List { - new SubtitleSearchParameters(subLanguageId, - query: request.SeriesName, - season: request.ParentIndexNumber.Value.ToString(_usCulture), - episode: request.IndexNumber.Value.ToString(_usCulture)) - } - : new List { - new SubtitleSearchParameters(subLanguageId, imdbid: searchImdbId), - new SubtitleSearchParameters(subLanguageId, query: request.Name, imdbid: searchImdbId) - }; - var parms = new List { - new SubtitleSearchParameters( subLanguageId, - movieHash: hash, - movieByteSize: movieByteSize, - imdbid: searchImdbId ), - }; - parms.AddRange(subtitleSearchParameters); - var result = await OpenSubtitles.SearchSubtitlesAsync(parms.ToArray(), cancellationToken).ConfigureAwait(false); - if (!(result is MethodResponseSubtitleSearch)) - { - _logger.LogError("Invalid response type"); - return new List(); - } - - Predicate mediaFilter = - x => - request.ContentType == VideoContentType.Episode - ? !string.IsNullOrEmpty(x.SeriesSeason) && !string.IsNullOrEmpty(x.SeriesEpisode) && - int.Parse(x.SeriesSeason, _usCulture) == request.ParentIndexNumber && - int.Parse(x.SeriesEpisode, _usCulture) == request.IndexNumber - : !string.IsNullOrEmpty(x.IDMovieImdb) && long.Parse(x.IDMovieImdb, _usCulture) == imdbId; - - var results = ((MethodResponseSubtitleSearch)result).Results; - - // Avoid implicitly captured closure - var hasCopy = hash; - - return results.Where(x => x.SubBad == "0" && mediaFilter(x) && (!request.IsPerfectMatch || string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase))) - .OrderBy(x => (string.Equals(x.MovieHash, hash, StringComparison.OrdinalIgnoreCase) ? 0 : 1)) - .ThenBy(x => Math.Abs(long.Parse(x.MovieByteSize, _usCulture) - movieByteSize)) - .ThenByDescending(x => int.Parse(x.SubDownloadsCnt, _usCulture)) - .ThenByDescending(x => double.Parse(x.SubRating, _usCulture)) - .Select(i => new RemoteSubtitleInfo - { - Author = i.UserNickName, - Comment = i.SubAuthorComment, - CommunityRating = float.Parse(i.SubRating, _usCulture), - DownloadCount = int.Parse(i.SubDownloadsCnt, _usCulture), - Format = i.SubFormat, - ProviderName = Name, - ThreeLetterISOLanguageName = i.SubLanguageID, - - Id = i.SubFormat + "-" + i.SubLanguageID + "-" + i.IDSubtitleFile, - - Name = i.SubFileName, - DateCreated = DateTime.Parse(i.SubAddDate, _usCulture), - IsHashMatch = i.MovieHash == hasCopy - - }).Where(i => !string.Equals(i.Format, "sub", StringComparison.OrdinalIgnoreCase) && !string.Equals(i.Format, "idx", StringComparison.OrdinalIgnoreCase)); - } - - public void Dispose() - { - _config.NamedConfigurationUpdating -= _config_NamedConfigurationUpdating; - } - } -} diff --git a/MediaBrowser.sln b/MediaBrowser.sln index a3c0569bad..3ed86d65c7 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -15,8 +15,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.WebDashboard", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.Providers", "MediaBrowser.Providers\MediaBrowser.Providers.csproj", "{442B5058-DCAF-4263-BB6A-F21E31120A1B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenSubtitlesHandler", "OpenSubtitlesHandler\OpenSubtitlesHandler.csproj", "{4A4402D4-E910-443B-B8FC-2C18286A2CA0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.XbmcMetadata", "MediaBrowser.XbmcMetadata\MediaBrowser.XbmcMetadata.csproj", "{23499896-B135-4527-8574-C26E926EA99E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MediaBrowser.LocalMetadata", "MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj", "{7EF9F3E0-697D-42F3-A08F-19DEB5F84392}" diff --git a/OpenSubtitlesHandler/Console/OSHConsole.cs b/OpenSubtitlesHandler/Console/OSHConsole.cs deleted file mode 100644 index 396b28cbc6..0000000000 --- a/OpenSubtitlesHandler/Console/OSHConsole.cs +++ /dev/null @@ -1,92 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System; - -namespace OpenSubtitlesHandler.Console -{ - public class OSHConsole - { - /// - /// Write line to the console and raise the "LineWritten" event - /// - /// - /// The debug line - /// The status - public static void WriteLine(string text, DebugCode code = DebugCode.None) - { - if (LineWritten != null) - LineWritten(null, new DebugEventArgs(text, code)); - } - /// - /// Update the last written line - /// - /// The debug line - /// The status - public static void UpdateLine(string text, DebugCode code = DebugCode.None) - { - if (UpdateLastLine != null) - UpdateLastLine(null, new DebugEventArgs(text, code)); - } - - public static event EventHandler LineWritten; - public static event EventHandler UpdateLastLine; - } - public enum DebugCode - { - None, - Good, - Warning, - Error - } - /// - /// Console Debug Args - /// - public class DebugEventArgs : EventArgs - { - public DebugCode Code { get; private set; } - public string Text { get; private set; } - - /// - /// Console Debug Args - /// - /// The debug line - /// The status - public DebugEventArgs(string text, DebugCode code) - { - this.Text = text; - this.Code = code; - } - } - public struct DebugLine - { - public DebugLine(string debugLine, DebugCode status) - { - this.debugLine = debugLine; - this.status = status; - } - string debugLine; - DebugCode status; - - public string Text - { get { return debugLine; } set { debugLine = value; } } - public DebugCode Code - { get { return status; } set { status = value; } } - } -} diff --git a/OpenSubtitlesHandler/Interfaces/IMethodResponse.cs b/OpenSubtitlesHandler/Interfaces/IMethodResponse.cs deleted file mode 100644 index 3450beff59..0000000000 --- a/OpenSubtitlesHandler/Interfaces/IMethodResponse.cs +++ /dev/null @@ -1,71 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; - -namespace OpenSubtitlesHandler -{ - /// - /// When you call a method to communicate with OpenSubtitles server, that method should return this response with the reuired information. - /// - public abstract class IMethodResponse - { - public IMethodResponse() { LoadAttributes(); } - public IMethodResponse(string name, string message) - { - this.name = name; - this.message = message; - } - protected string name; - protected string message; - protected double seconds; - protected string status; - - protected void LoadAttributes() - { - //foreach (Attribute attr in Attribute.GetCustomAttributes(this.GetType())) - //{ - // if (attr.GetType() == typeof(MethodResponseDescription)) - // { - // this.name = ((MethodResponseDescription)attr).Name; - // this.message = ((MethodResponseDescription)attr).Message; - // break; - // } - //} - } - - [Description("The name of this response"), Category("MethodResponse")] - public virtual string Name { get { return name; } set { name = value; } } - [Description("The message about this response"), Category("MethodResponse")] - public virtual string Message { get { return message; } set { message = value; } } - [Description("Time taken to execute this command on server"), Category("MethodResponse")] - public double Seconds { get { return seconds; } set { seconds = value; } } - [Description("The status"), Category("MethodResponse")] - public string Status { get { return status; } set { status = value; } } - } - - public class DescriptionAttribute : Attribute - { - public DescriptionAttribute(string text) { } - } - - public class CategoryAttribute : Attribute - { - public CategoryAttribute(string text) { } - } -} diff --git a/OpenSubtitlesHandler/Interfaces/MethodResponseAttr.cs b/OpenSubtitlesHandler/Interfaces/MethodResponseAttr.cs deleted file mode 100644 index a7e49032de..0000000000 --- a/OpenSubtitlesHandler/Interfaces/MethodResponseAttr.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; - -namespace OpenSubtitlesHandler -{ - /// - /// Attributes to describe a method response object. - /// - public class MethodResponseDescription : Attribute - { - public MethodResponseDescription(string name, string message) - { - this.name = name; - this.message = message; - } - - private string name; - private string message; - - public string Name { get { return name; } set { name = value; } } - public string Message { get { return message; } set { message = value; } } - } -} diff --git a/OpenSubtitlesHandler/Languages/DetectLanguageResult.cs b/OpenSubtitlesHandler/Languages/DetectLanguageResult.cs deleted file mode 100644 index 3e72dc65c4..0000000000 --- a/OpenSubtitlesHandler/Languages/DetectLanguageResult.cs +++ /dev/null @@ -1,31 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - public struct DetectLanguageResult - { - private string inputSample; - private string languageID; - - public string LanguageID - { get { return languageID; } set { languageID = value; } } - public string InputSample - { get { return inputSample; } set { inputSample = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseAddComment.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseAddComment.cs deleted file mode 100644 index 03d0337d4c..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseAddComment.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("AddComment method response", - "AddComment method response hold all expected values from server.")] - public class MethodResponseAddComment : IMethodResponse - { - public MethodResponseAddComment() - : base() - { } - public MethodResponseAddComment(string name, string message) - : base(name, message) - { } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseAddRequest.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseAddRequest.cs deleted file mode 100644 index b996043c28..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseAddRequest.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("AddRequest method response", - "AddRequest method response hold all expected values from server.")] - public class MethodResponseAddRequest : IMethodResponse - { - public MethodResponseAddRequest() - : base() - { } - public MethodResponseAddRequest(string name, string message) - : base(name, message) - { } - private string _request_url; - - public string request_url { get { return _request_url; } set { _request_url = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseAutoUpdate.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseAutoUpdate.cs deleted file mode 100644 index 6ee14f1f8f..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseAutoUpdate.cs +++ /dev/null @@ -1,59 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("AutoUpdate method response", - "AutoUpdate method response hold all expected values from server.")] - public class MethodResponseAutoUpdate : IMethodResponse - { - public MethodResponseAutoUpdate() - : base() - { } - public MethodResponseAutoUpdate(string name, string message) - : base(name, message) - { } - - private string _version; - private string _url_windows; - private string _comments; - private string _url_linux; - /// - /// Latest application version - /// - [Description("Latest application version"), Category("AutoUpdate")] - public string version { get { return _version; } set { _version = value; } } - /// - /// Download URL for Windows version - /// - [Description("Download URL for Windows version"), Category("AutoUpdate")] - public string url_windows { get { return _url_windows; } set { _url_windows = value; } } - /// - /// Application changelog and other comments - /// - [Description("Application changelog and other comments"), Category("AutoUpdate")] - public string comments { get { return _comments; } set { _comments = value; } } - /// - /// Download URL for Linux version - /// - [Description("Download URL for Linux version"), Category("AutoUpdate")] - public string url_linux { get { return _url_linux; } set { _url_linux = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash.cs deleted file mode 100644 index 4bb3262442..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("CheckMovieHash method response", - "CheckMovieHash method response hold all expected values from server.")] - public class MethodResponseCheckMovieHash : IMethodResponse - { - public MethodResponseCheckMovieHash() - : base() - { } - public MethodResponseCheckMovieHash(string name, string message) - : base(name, message) - { } - private List results = new List(); - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash2.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash2.cs deleted file mode 100644 index 72b4c3b152..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckMovieHash2.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("CheckMovieHash2 method response", - "CheckMovieHash2 method response hold all expected values from server.")] - public class MethodResponseCheckMovieHash2 : IMethodResponse - { - public MethodResponseCheckMovieHash2() - : base() - { } - public MethodResponseCheckMovieHash2(string name, string message) - : base(name, message) - { } - private List results = new List(); - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckSubHash.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckSubHash.cs deleted file mode 100644 index 04e287ea74..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseCheckSubHash.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("CheckSubHash method response", - "CheckSubHash method response hold all expected values from server.")] - public class MethodResponseCheckSubHash : IMethodResponse - { - public MethodResponseCheckSubHash() - : base() - { } - public MethodResponseCheckSubHash(string name, string message) - : base(name, message) - { } - private List results = new List(); - - public List Results { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseDetectLanguage.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseDetectLanguage.cs deleted file mode 100644 index 6bf21d50e8..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseDetectLanguage.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("DetectLanguage method response", - "DetectLanguage method response hold all expected values from server.")] - public class MethodResponseDetectLanguage : IMethodResponse - { - public MethodResponseDetectLanguage() - : base() - { } - public MethodResponseDetectLanguage(string name, string message) - : base(name, message) - { } - private List results = new List(); - - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseError.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseError.cs deleted file mode 100644 index 7ed807067e..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseError.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - /// - /// Response that can be used for general error like internet connection fail. - /// - [MethodResponseDescription("Error method response", - "Error method response that describes error that occured")] - public class MethodResponseError : IMethodResponse - { - public MethodResponseError() - : base() - { } - public MethodResponseError(string name, string message) - : base(name, message) - { } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetAvailableTranslations.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseGetAvailableTranslations.cs deleted file mode 100644 index 91803f4b3d..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetAvailableTranslations.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("GetAvailableTranslations method response", - "GetAvailableTranslations method response hold all expected values from server.")] - public class MethodResponseGetAvailableTranslations : IMethodResponse - { - public MethodResponseGetAvailableTranslations() - : base() - { } - public MethodResponseGetAvailableTranslations(string name, string message) - : base(name, message) - { } - private List results = new List(); - public List Results { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetComments.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseGetComments.cs deleted file mode 100644 index 421e1783bc..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetComments.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("GetComments method response", - "GetComments method response hold all expected values from server.")] - public class MethodResponseGetComments : IMethodResponse - { - public MethodResponseGetComments() - : base() - { } - public MethodResponseGetComments(string name, string message) - : base(name, message) - { } - private List results = new List(); - - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetSubLanguages.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseGetSubLanguages.cs deleted file mode 100644 index 905b87c916..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetSubLanguages.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("GetSubLanguages method response", - "GetSubLanguages method response hold all expected values from server.")] - public class MethodResponseGetSubLanguages : IMethodResponse - { - public MethodResponseGetSubLanguages() - : base() - { } - public MethodResponseGetSubLanguages(string name, string message) - : base(name, message) - { } - private List languages = new List(); - - public List Languages - { get { return languages; } set { languages = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetTranslation.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseGetTranslation.cs deleted file mode 100644 index f008f7711d..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseGetTranslation.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("GetTranslation method response", - "GetTranslation method response hold all expected values from server.")] - public class MethodResponseGetTranslation : IMethodResponse - { - public MethodResponseGetTranslation() - : base() - { } - public MethodResponseGetTranslation(string name, string message) - : base(name, message) - { } - private string data; - - public string ContentData { get { return data; } set { data = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovie.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovie.cs deleted file mode 100644 index 1148b5f479..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovie.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("InsertMovie method response", - "InsertMovie method response hold all expected values from server.")] - public class MethodResponseInsertMovie : IMethodResponse - { - public MethodResponseInsertMovie() - : base() - { } - public MethodResponseInsertMovie(string name, string message) - : base(name, message) - { } - private string _ID; - public string ID - { get { return _ID; } set { _ID = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovieHash.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovieHash.cs deleted file mode 100644 index 74f52837c9..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseInsertMovieHash.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("InsertMovieHash method response", - "InsertMovieHash method response hold all expected values from server.")] - public class MethodResponseInsertMovieHash : IMethodResponse - { - public MethodResponseInsertMovieHash() - : base() - { } - public MethodResponseInsertMovieHash(string name, string message) - : base(name, message) - { } - private List _accepted_moviehashes = new List(); - private List _new_imdbs = new List(); - - public List accepted_moviehashes { get { return _accepted_moviehashes; } set { _accepted_moviehashes = value; } } - public List new_imdbs { get { return _new_imdbs; } set { _new_imdbs = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseLogIn.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseLogIn.cs deleted file mode 100644 index 44d2943824..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseLogIn.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - /// - /// Response can be used for log in/out operation. - /// - [MethodResponseDescription("LogIn method response", - "LogIn method response hold all expected values from server.")] - public class MethodResponseLogIn : IMethodResponse - { - public MethodResponseLogIn() - : base() - { } - public MethodResponseLogIn(string name, string message) - : base(name, message) - { } - private string token; - - public string Token { get { return token; } set { token = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieDetails.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieDetails.cs deleted file mode 100644 index 6126c0053a..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieDetails.cs +++ /dev/null @@ -1,73 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("MovieDetails method response", - "MovieDetails method response hold all expected values from server.")] - public class MethodResponseMovieDetails : IMethodResponse - { - public MethodResponseMovieDetails() - : base() - { } - public MethodResponseMovieDetails(string name, string message) - : base(name, message) - { } - // Details - private string id; - private string title; - private string year; - private string coverLink; - - private string duration; - private string tagline; - private string plot; - private string goofs; - private string trivia; - private List cast = new List(); - private List directors = new List(); - private List writers = new List(); - private List awards = new List(); - private List genres = new List(); - private List country = new List(); - private List language = new List(); - private List certification = new List(); - - // Details - public string ID { get { return id; } set { id = value; } } - public string Title { get { return title; } set { title = value; } } - public string Year { get { return year; } set { year = value; } } - public string CoverLink { get { return coverLink; } set { coverLink = value; } } - public string Duration { get { return duration; } set { duration = value; } } - public string Tagline { get { return tagline; } set { tagline = value; } } - public string Plot { get { return plot; } set { plot = value; } } - public string Goofs { get { return goofs; } set { goofs = value; } } - public string Trivia { get { return trivia; } set { trivia = value; } } - public List Cast { get { return cast; } set { cast = value; } } - public List Directors { get { return directors; } set { directors = value; } } - public List Writers { get { return writers; } set { writers = value; } } - public List Genres { get { return genres; } set { genres = value; } } - public List Awards { get { return awards; } set { awards = value; } } - public List Country { get { return country; } set { country = value; } } - public List Language { get { return language; } set { language = value; } } - public List Certification { get { return certification; } set { certification = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieSearch.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieSearch.cs deleted file mode 100644 index 93cd703462..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseMovieSearch.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("MovieSearch method response", - "MovieSearch method response hold all expected values from server.")] - public class MethodResponseMovieSearch : IMethodResponse - { - public MethodResponseMovieSearch() - : base() - { - results = new List(); - } - public MethodResponseMovieSearch(string name, string message) - : base(name, message) - { - results = new List(); - } - private List results; - - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseNoOperation.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseNoOperation.cs deleted file mode 100644 index 02a9993cb1..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseNoOperation.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("NoOperation method response", - "NoOperation method response hold all expected values from server.")] - public class MethodResponseNoOperation : IMethodResponse - { - public MethodResponseNoOperation() - : base() { } - public MethodResponseNoOperation(string name, string message) - : base(name, message) - { } - - private string _global_wrh_download_limit; - private string _client_ip; - private string _limit_check_by; - private string _client_24h_download_count; - private string _client_downlaod_quota; - private string _client_24h_download_limit; - - public string global_wrh_download_limit - { get { return _global_wrh_download_limit; } set { _global_wrh_download_limit = value; } } - public string client_ip - { get { return _client_ip; } set { _client_ip = value; } } - public string limit_check_by - { get { return _limit_check_by; } set { _limit_check_by = value; } } - public string client_24h_download_count - { get { return _client_24h_download_count; } set { _client_24h_download_count = value; } } - public string client_downlaod_quota - { get { return _client_downlaod_quota; } set { _client_downlaod_quota = value; } } - public string client_24h_download_limit - { get { return _client_24h_download_limit; } set { _client_24h_download_limit = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongImdbMovie.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongImdbMovie.cs deleted file mode 100644 index 391fec58a0..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongImdbMovie.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("ReportWrongImdbMovie method response", - "ReportWrongImdbMovie method response hold all expected values from server.")] - public class MethodResponseReportWrongImdbMovie : IMethodResponse - { - public MethodResponseReportWrongImdbMovie() - : base() - { } - public MethodResponseReportWrongImdbMovie(string name, string message) - : base(name, message) - { } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongMovieHash.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongMovieHash.cs deleted file mode 100644 index 5696e7084c..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseReportWrongMovieHash.cs +++ /dev/null @@ -1,33 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("ReportWrongMovieHash method response", - "ReportWrongMovieHash method response hold all expected values from server.")] - public class MethodResponseReportWrongMovieHash : IMethodResponse - { - public MethodResponseReportWrongMovieHash() - : base() - { } - public MethodResponseReportWrongMovieHash(string name, string message) - : base(name, message) - { } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseSearchToMail.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseSearchToMail.cs deleted file mode 100644 index ea248bc22c..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseSearchToMail.cs +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("SearchToMail method response", - "SearchToMail method response hold all expected values from server.")] - public class MethodResponseSearchToMail : IMethodResponse - { - public MethodResponseSearchToMail() - : base() - { } - public MethodResponseSearchToMail(string name, string message) - : base(name, message) - { } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseServerInfo.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseServerInfo.cs deleted file mode 100644 index 973550e9f0..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseServerInfo.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("ServerInfo method response", - "ServerInfo method response hold all expected values from server.")] - public class MethodResponseServerInfo : IMethodResponse - { - public MethodResponseServerInfo() - : base() - { } - public MethodResponseServerInfo(string name, string message) - : base(name, message) - { } - private string _xmlrpc_version; - private string _xmlrpc_url; - private string _application; - private string _contact; - private string _website_url; - private int _users_online_total; - private int _users_online_program; - private int _users_loggedin; - private string _users_max_alltime; - private string _users_registered; - private string _subs_downloads; - private string _subs_subtitle_files; - private string _movies_total; - private string _movies_aka; - private string _total_subtitles_languages; - private List _last_update_strings = new List(); - - /// - /// Version of server's XML-RPC API implementation - /// - [Description("Version of server's XML-RPC API implementation"), Category("OS")] - public string xmlrpc_version { get { return _xmlrpc_version; } set { _xmlrpc_version = value; } } - /// - /// XML-RPC interface URL - /// - [Description("XML-RPC interface URL"), Category("OS")] - public string xmlrpc_url { get { return _xmlrpc_url; } set { _xmlrpc_url = value; } } - /// - /// Server's application name and version - /// - [Description("Server's application name and version"), Category("OS")] - public string application { get { return _application; } set { _application = value; } } - /// - /// Contact e-mail address for server related quuestions and problems - /// - [Description("Contact e-mail address for server related quuestions and problems"), Category("OS")] - public string contact { get { return _contact; } set { _contact = value; } } - /// - /// Main server URL - /// - [Description("Main server URL"), Category("OS")] - public string website_url { get { return _website_url; } set { _website_url = value; } } - /// - /// Number of users currently online - /// - [Description("Number of users currently online"), Category("OS")] - public int users_online_total { get { return _users_online_total; } set { _users_online_total = value; } } - /// - /// Number of users currently online using a client application (XML-RPC API) - /// - [Description("Number of users currently online using a client application (XML-RPC API)"), Category("OS")] - public int users_online_program { get { return _users_online_program; } set { _users_online_program = value; } } - /// - /// Number of currently logged-in users - /// - [Description("Number of currently logged-in users"), Category("OS")] - public int users_loggedin { get { return _users_loggedin; } set { _users_loggedin = value; } } - /// - /// Maximum number of users throughout the history - /// - [Description("Maximum number of users throughout the history"), Category("OS")] - public string users_max_alltime { get { return _users_max_alltime; } set { _users_max_alltime = value; } } - /// - /// Number of registered users - /// - [Description("Number of registered users"), Category("OS")] - public string users_registered { get { return _users_registered; } set { _users_registered = value; } } - /// - /// Total number of subtitle downloads - /// - [Description("Total number of subtitle downloads"), Category("OS")] - public string subs_downloads { get { return _subs_downloads; } set { _subs_downloads = value; } } - /// - /// Total number of subtitle files stored on the server - /// - [Description("Total number of subtitle files stored on the server"), Category("OS")] - public string subs_subtitle_files { get { return _subs_subtitle_files; } set { _subs_subtitle_files = value; } } - /// - /// Total number of movies in the database - /// - [Description("Total number of movies in the database"), Category("OS")] - public string movies_total { get { return _movies_total; } set { _movies_total = value; } } - /// - /// Total number of movie A.K.A. titles in the database - /// - [Description("Total number of movie A.K.A. titles in the database"), Category("OS")] - public string movies_aka { get { return _movies_aka; } set { _movies_aka = value; } } - /// - /// Total number of subtitle languages supported - /// - [Description("Total number of subtitle languages supported"), Category("OS")] - public string total_subtitles_languages { get { return _total_subtitles_languages; } set { _total_subtitles_languages = value; } } - /// - /// Structure containing information about last updates of translations. - /// - [Description("Structure containing information about last updates of translations"), Category("OS")] - public List last_update_strings { get { return _last_update_strings; } set { _last_update_strings = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleDownload.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleDownload.cs deleted file mode 100644 index 6a5d57d19a..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleDownload.cs +++ /dev/null @@ -1,44 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; -namespace OpenSubtitlesHandler -{ - /// - /// The response that should be used by subtitle download methods. - /// - [MethodResponseDescription("SubtitleDownload method response", - "SubtitleDownload method response hold all expected values from server.")] - public class MethodResponseSubtitleDownload : IMethodResponse - { - public MethodResponseSubtitleDownload() - : base() - { - results = new List(); - } - public MethodResponseSubtitleDownload(string name, string message) - : base(name, message) - { - results = new List(); - } - private List results; - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleSearch.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleSearch.cs deleted file mode 100644 index 0dce203495..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitleSearch.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - /// - /// Response to SearchSubtitle successed call. - /// - [MethodResponseDescription("SubtitleSearch method response", - "SubtitleSearch method response hold all expected values from server.")] - public class MethodResponseSubtitleSearch : IMethodResponse - { - public MethodResponseSubtitleSearch() - : base() - { - results = new List(); - } - public MethodResponseSubtitleSearch(string name, string message) - : base(name, message) - { - results = new List(); - } - - private List results; - public List Results - { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitlesVote.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitlesVote.cs deleted file mode 100644 index f02f822f05..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseSubtitlesVote.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("SubtitlesVote method response", - "SubtitlesVote method response hold all expected values from server.")] - public class MethodResponseSubtitlesVote : IMethodResponse - { - public MethodResponseSubtitlesVote() - : base() - { } - public MethodResponseSubtitlesVote(string name, string message) - : base(name, message) - { } - private string _SubRating; - private string _SubSumVotes; - private string _IDSubtitle; - - public string SubRating - { get { return _SubRating; } set { _SubRating = value; } } - public string SubSumVotes - { get { return _SubSumVotes; } set { _SubSumVotes = value; } } - public string IDSubtitle - { get { return _IDSubtitle; } set { _IDSubtitle = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseTryUploadSubtitles.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseTryUploadSubtitles.cs deleted file mode 100644 index cb3866a628..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseTryUploadSubtitles.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("TryUploadSubtitles method response", - "TryUploadSubtitles method response hold all expected values from server.")] - public class MethodResponseTryUploadSubtitles : IMethodResponse - { - public MethodResponseTryUploadSubtitles() - : base() - { } - public MethodResponseTryUploadSubtitles(string name, string message) - : base(name, message) - { } - private int alreadyindb; - private List results = new List(); - - public int AlreadyInDB { get { return alreadyindb; } set { alreadyindb = value; } } - public List Results { get { return results; } set { results = value; } } - } -} diff --git a/OpenSubtitlesHandler/MethodResponses/MethodResponseUploadSubtitles.cs b/OpenSubtitlesHandler/MethodResponses/MethodResponseUploadSubtitles.cs deleted file mode 100644 index bda950befc..0000000000 --- a/OpenSubtitlesHandler/MethodResponses/MethodResponseUploadSubtitles.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - [MethodResponseDescription("UploadSubtitles method response", - "UploadSubtitles method response hold all expected values from server.")] - public class MethodResponseUploadSubtitles : IMethodResponse - { - public MethodResponseUploadSubtitles() - : base() - { } - public MethodResponseUploadSubtitles(string name, string message) - : base(name, message) - { } - private string _data; - private bool _subtitles; - - public string Data { get { return _data; } set { _data = value; } } - public bool SubTitles { get { return _subtitles; } set { _subtitles = value; } } - } -} diff --git a/OpenSubtitlesHandler/Methods Implemeted.txt b/OpenSubtitlesHandler/Methods Implemeted.txt deleted file mode 100644 index e3493d9a2c..0000000000 --- a/OpenSubtitlesHandler/Methods Implemeted.txt +++ /dev/null @@ -1,39 +0,0 @@ -List of available OpenSubtitles.org server XML-RPC methods. -========================================================== -Legends: -* OK: this method is fully implemented, tested and works fine. -* TODO: this method is in the plan to be added. -* NOT TESTED: this method added and expected to work fine but never tested. -* NOT WORK (x): this method added but not work. x= Description of the error. - --------------------------------------------- -Method name | Status --------------------------|------------------ -LogIn | OK -LogOut | OK -NoOperation | OK -SearchSubtitles | OK -DownloadSubtitles | OK -SearchToMail | OK -TryUploadSubtitles | OK -UploadSubtitles | OK -SearchMoviesOnIMDB | OK -GetIMDBMovieDetails | OK -InsertMovie | OK -InsertMovieHash | OK -ServerInfo | OK -ReportWrongMovieHash | OK -ReportWrongImdbMovie | OK -SubtitlesVote | OK -AddComment | OK -AddRequest | OK -GetComments | OK -GetSubLanguages | OK -DetectLanguage | OK -GetAvailableTranslations | OK -GetTranslation | NOT WORK (Returns status of error 410 'Other or unknown error') -AutoUpdate | NOT WORK (Returns status: 'parse error. not well formed') -CheckMovieHash | OK -CheckMovieHash2 | OK -CheckSubHash | OK --------------------------------------------- diff --git a/OpenSubtitlesHandler/MovieHasher.cs b/OpenSubtitlesHandler/MovieHasher.cs deleted file mode 100644 index 25d91c1aca..0000000000 --- a/OpenSubtitlesHandler/MovieHasher.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace OpenSubtitlesHandler -{ - public class MovieHasher - { - public static byte[] ComputeMovieHash(Stream input) - { - using (input) - { - long lhash, streamsize; - streamsize = input.Length; - lhash = streamsize; - - long i = 0; - byte[] buffer = new byte[sizeof(long)]; - while (i < 65536 / sizeof(long) && (input.Read(buffer, 0, sizeof(long)) > 0)) - { - i++; - lhash += BitConverter.ToInt64(buffer, 0); - } - - input.Position = Math.Max(0, streamsize - 65536); - i = 0; - while (i < 65536 / sizeof(long) && (input.Read(buffer, 0, sizeof(long)) > 0)) - { - i++; - lhash += BitConverter.ToInt64(buffer, 0); - } - byte[] result = BitConverter.GetBytes(lhash); - Array.Reverse(result); - return result; - } - } - - public static string ToHexadecimal(byte[] bytes) - { - var hexBuilder = new StringBuilder(); - for (int i = 0; i < bytes.Length; i++) - { - hexBuilder.Append(bytes[i].ToString("x2")); - } - return hexBuilder.ToString(); - } - } -} diff --git a/OpenSubtitlesHandler/Movies/CheckMovieHash2Data.cs b/OpenSubtitlesHandler/Movies/CheckMovieHash2Data.cs deleted file mode 100644 index 9535901375..0000000000 --- a/OpenSubtitlesHandler/Movies/CheckMovieHash2Data.cs +++ /dev/null @@ -1,42 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct CheckMovieHash2Data - { - private string _MovieHash; - private string _MovieImdbID; - private string _MovieName; - private string _MovieYear; - private string _MovieKind; - private string _SeriesSeason; - private string _SeriesEpisode; - private string _SeenCount; - - public string MovieHash { get { return _MovieHash; } set { _MovieHash = value; } } - public string MovieImdbID { get { return _MovieImdbID; } set { _MovieImdbID = value; } } - public string MovieName { get { return _MovieName; } set { _MovieName = value; } } - public string MovieYear { get { return _MovieYear; } set { _MovieYear = value; } } - public string MovieKind { get { return _MovieKind; } set { _MovieKind = value; } } - public string SeriesSeason { get { return _SeriesSeason; } set { _SeriesSeason = value; } } - public string SeriesEpisode { get { return _SeriesEpisode; } set { _SeriesEpisode = value; } } - public string SeenCount { get { return _SeenCount; } set { _SeenCount = value; } } - } -} diff --git a/OpenSubtitlesHandler/Movies/CheckMovieHash2Result.cs b/OpenSubtitlesHandler/Movies/CheckMovieHash2Result.cs deleted file mode 100644 index 96652fae74..0000000000 --- a/OpenSubtitlesHandler/Movies/CheckMovieHash2Result.cs +++ /dev/null @@ -1,37 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - public class CheckMovieHash2Result - { - private string name; - private List data = new List(); - - public string Name { get { return name; } set { name = value; } } - public List Items { get { return data; } set { data = value; } } - - public override string ToString() - { - return name; - } - } -} diff --git a/OpenSubtitlesHandler/Movies/CheckMovieHashResult.cs b/OpenSubtitlesHandler/Movies/CheckMovieHashResult.cs deleted file mode 100644 index 0d6c79f80b..0000000000 --- a/OpenSubtitlesHandler/Movies/CheckMovieHashResult.cs +++ /dev/null @@ -1,41 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct CheckMovieHashResult - { - private string name; - private string _MovieHash; - private string _MovieImdbID; - private string _MovieName; - private string _MovieYear; - - public string MovieHash { get { return _MovieHash; } set { _MovieHash = value; } } - public string MovieImdbID { get { return _MovieImdbID; } set { _MovieImdbID = value; } } - public string MovieName { get { return _MovieName; } set { _MovieName = value; } } - public string MovieYear { get { return _MovieYear; } set { _MovieYear = value; } } - public string Name { get { return name; } set { name = value; } } - - public override string ToString() - { - return name; - } - } -} diff --git a/OpenSubtitlesHandler/Movies/InsertMovieHashParameters.cs b/OpenSubtitlesHandler/Movies/InsertMovieHashParameters.cs deleted file mode 100644 index d0de7f8c64..0000000000 --- a/OpenSubtitlesHandler/Movies/InsertMovieHashParameters.cs +++ /dev/null @@ -1,38 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public class InsertMovieHashParameters - { - private string _moviehash = ""; - private string _moviebytesize = ""; - private string _imdbid = ""; - private string _movietimems = ""; - private string _moviefps = ""; - private string _moviefilename = ""; - - public string moviehash { get { return _moviehash; } set { _moviehash = value; } } - public string moviebytesize { get { return _moviebytesize; } set { _moviebytesize = value; } } - public string imdbid { get { return _imdbid; } set { _imdbid = value; } } - public string movietimems { get { return _movietimems; } set { _movietimems = value; } } - public string moviefps { get { return _moviefps; } set { _moviefps = value; } } - public string moviefilename { get { return _moviefilename; } set { _moviefilename = value; } } - } -} diff --git a/OpenSubtitlesHandler/Movies/MovieSearchResult.cs b/OpenSubtitlesHandler/Movies/MovieSearchResult.cs deleted file mode 100644 index d771165830..0000000000 --- a/OpenSubtitlesHandler/Movies/MovieSearchResult.cs +++ /dev/null @@ -1,40 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct MovieSearchResult - { - private string id; - private string title; - - public string ID - { get { return id; } set { id = value; } } - public string Title - { get { return title; } set { title = value; } } - /// - /// Title - /// - /// - public override string ToString() - { - return title; - } - } -} diff --git a/OpenSubtitlesHandler/Movies/SearchToMailMovieParameter.cs b/OpenSubtitlesHandler/Movies/SearchToMailMovieParameter.cs deleted file mode 100644 index a0ecc87f8a..0000000000 --- a/OpenSubtitlesHandler/Movies/SearchToMailMovieParameter.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct SearchToMailMovieParameter - { - private string _moviehash; - private double _moviesize; - - public string moviehash { get { return _moviehash; } set { _moviehash = value; } } - public double moviesize { get { return _moviesize; } set { _moviesize = value; } } - } -} diff --git a/OpenSubtitlesHandler/OpenSubtitles.cs b/OpenSubtitlesHandler/OpenSubtitles.cs deleted file mode 100644 index 76f70dc070..0000000000 --- a/OpenSubtitlesHandler/OpenSubtitles.cs +++ /dev/null @@ -1,2744 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using OpenSubtitlesHandler.Console; -using XmlRpcHandler; - -namespace OpenSubtitlesHandler -{ - /// - /// The core of the OpenSubtitles Handler library. All members are static. - /// - public sealed class OpenSubtitles - { - private static string XML_PRC_USERAGENT = ""; - // This is session id after log in, important value and MUST be set by LogIn before any other call. - private static string TOKEN = ""; - - /// - /// Set the useragent value. This must be called before doing anything else. - /// - /// The useragent value - public static void SetUserAgent(string agent) - { - XML_PRC_USERAGENT = agent; - } - - /*Session handling*/ - /// - /// Send a LogIn request, this must be called before anything else in this class. - /// - /// The user name of OpenSubtitles - /// The password - /// The language, usally en - /// Status of the login operation - public static IMethodResponse LogIn(string userName, string password, string language) - { - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(userName)); - parms.Add(new XmlRpcValueBasic(password)); - parms.Add(new XmlRpcValueBasic(language)); - parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT)); - var call = new XmlRpcMethodCall("LogIn", parms); - OSHConsole.WriteLine("Sending LogIn request to the server ...", DebugCode.Good); - - //File.WriteAllText(".\\request.txt", Encoding.UTF8.GetString(XmlRpcGenerator.Generate(call))); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. We expect Struct here. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - var re = new MethodResponseLogIn("Success", "Log in successful."); - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "token": re.Token = TOKEN = MEMBER.Data.Data.ToString(); OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": re.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "status": re.Status = MEMBER.Data.Data.ToString(); OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - return re; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "Log in failed !"); - } - - public static async Task LogInAsync(string userName, string password, string language, CancellationToken cancellationToken) - { - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(userName)); - parms.Add(new XmlRpcValueBasic(password)); - parms.Add(new XmlRpcValueBasic(language)); - parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT)); - var call = new XmlRpcMethodCall("LogIn", parms); - OSHConsole.WriteLine("Sending LogIn request to the server ...", DebugCode.Good); - - //File.WriteAllText(".\\request.txt", Encoding.UTF8.GetString(XmlRpcGenerator.Generate(call))); - // Send the request to the server - var stream = await Utilities.SendRequestAsync(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT, cancellationToken) - .ConfigureAwait(false); - - string response = Utilities.GetStreamString(stream); - - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. We expect Struct here. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - var re = new MethodResponseLogIn("Success", "Log in successful."); - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "token": - re.Token = TOKEN = MEMBER.Data.Data.ToString(); - OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "seconds": - re.Seconds = double.Parse(MEMBER.Data.Data.ToString(), CultureInfo.InvariantCulture); - OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "status": - re.Status = MEMBER.Data.Data.ToString(); - OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - } - } - return re; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "Log in failed !"); - } - - /// - /// Log out from the server. Call this to terminate the session. - /// - /// - public static IMethodResponse LogOut() - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var call = new XmlRpcMethodCall("LogOut", parms); - - OSHConsole.WriteLine("Sending LogOut request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. We expect Struct here. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var strct = (XmlRpcValueStruct)calls[0].Parameters[0]; - OSHConsole.WriteLine("STATUS=" + ((XmlRpcValueBasic)strct.Members[0].Data).Data.ToString()); - OSHConsole.WriteLine("SECONDS=" + ((XmlRpcValueBasic)strct.Members[1].Data).Data.ToString()); - var re = new MethodResponseLogIn("Success", "Log out successful."); - re.Status = ((XmlRpcValueBasic)strct.Members[0].Data).Data.ToString(); - re.Seconds = (double)((XmlRpcValueBasic)strct.Members[1].Data).Data; - return re; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "Log out failed !"); - } - /// - /// keep-alive user's session, verify token/session validity - /// - /// Status of the call operation - public static IMethodResponse NoOperation() - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT, XmlRpcBasicValueType.String)); - var call = new XmlRpcMethodCall("NoOperation", parms); - - OSHConsole.WriteLine("Sending NoOperation request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. We expect Struct here. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var R = new MethodResponseNoOperation(); - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(MEMBER.Name + "= " + MEMBER.Data.Data); break; - case "download_limits": - var dlStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dlmember in dlStruct.Members) - { - OSHConsole.WriteLine(" >" + dlmember.Name + "= " + dlmember.Data.Data.ToString()); - switch (dlmember.Name) - { - case "global_wrh_download_limit": R.global_wrh_download_limit = dlmember.Data.Data.ToString(); break; - case "client_ip": R.client_ip = dlmember.Data.Data.ToString(); break; - case "limit_check_by": R.limit_check_by = dlmember.Data.Data.ToString(); break; - case "client_24h_download_count": R.client_24h_download_count = dlmember.Data.Data.ToString(); break; - case "client_downlaod_quota": R.client_downlaod_quota = dlmember.Data.Data.ToString(); break; - case "client_24h_download_limit": R.client_24h_download_limit = dlmember.Data.Data.ToString(); break; - } - } - break; - } - } - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "NoOperation call failed !"); - } - /*Search and download*/ - /// - /// Search for subtitle files matching your videos using either video file hashes or IMDb IDs. - /// - /// List of search subtitle parameters which each one represents 'struct parameter' as descriped at http://trac.opensubtitles.org/projects/opensubtitles/wiki/XmlRpcSearchSubtitles - /// Status of the call operation. If the call success the response will be 'MethodResponseSubtitleSearch' - public static IMethodResponse SearchSubtitles(SubtitleSearchParameters[] parameters) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - if (parameters == null) - { - OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle search parameter passed"); - } - if (parameters.Length == 0) - { - OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle search parameter passed"); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add subtitle search parameters. Each one will be like 'array' of structs. - var array = new XmlRpcValueArray(); - foreach (SubtitleSearchParameters param in parameters) - { - var strct = new XmlRpcValueStruct(new List()); - // sublanguageid member - var member = new XmlRpcStructMember("sublanguageid", - new XmlRpcValueBasic(param.SubLangaugeID, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - // moviehash member - if (param.MovieHash.Length > 0 && param.MovieByteSize > 0) - { - member = new XmlRpcStructMember("moviehash", - new XmlRpcValueBasic(param.MovieHash, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - // moviehash member - member = new XmlRpcStructMember("moviebytesize", - new XmlRpcValueBasic(param.MovieByteSize, XmlRpcBasicValueType.Int)); - strct.Members.Add(member); - } - if (param.Query.Length > 0) - { - member = new XmlRpcStructMember("query", - new XmlRpcValueBasic(param.Query, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - - if (param.Episode.Length > 0 && param.Season.Length > 0) - { - member = new XmlRpcStructMember("season", - new XmlRpcValueBasic(param.Season, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - member = new XmlRpcStructMember("episode", - new XmlRpcValueBasic(param.Episode, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - - // imdbid member - if (param.IMDbID.Length > 0) - { - member = new XmlRpcStructMember("imdbid", - new XmlRpcValueBasic(param.IMDbID, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - // Add the struct to the array - array.Values.Add(strct); - } - // Add the array to the parameters - parms.Add(array); - // Call ! - var call = new XmlRpcMethodCall("SearchSubtitles", parms); - OSHConsole.WriteLine("Sending SearchSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - // We expect Struct of 3 members: - //* the first is status - //* the second is [array of structs, each one includes subtitle file]. - //* the third is [double basic value] represent seconds token by server. - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSubtitleSearch(); - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Search results: "); - - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new SubtitleSearchResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "IDMovie": result.IDMovie = submember.Data.Data.ToString(); break; - case "IDMovieImdb": result.IDMovieImdb = submember.Data.Data.ToString(); break; - case "IDSubMovieFile": result.IDSubMovieFile = submember.Data.Data.ToString(); break; - case "IDSubtitle": result.IDSubtitle = submember.Data.Data.ToString(); break; - case "IDSubtitleFile": result.IDSubtitleFile = submember.Data.Data.ToString(); break; - case "ISO639": result.ISO639 = submember.Data.Data.ToString(); break; - case "LanguageName": result.LanguageName = submember.Data.Data.ToString(); break; - case "MovieByteSize": result.MovieByteSize = submember.Data.Data.ToString(); break; - case "MovieHash": result.MovieHash = submember.Data.Data.ToString(); break; - case "MovieImdbRating": result.MovieImdbRating = submember.Data.Data.ToString(); break; - case "MovieName": result.MovieName = submember.Data.Data.ToString(); break; - case "MovieNameEng": result.MovieNameEng = submember.Data.Data.ToString(); break; - case "MovieReleaseName": result.MovieReleaseName = submember.Data.Data.ToString(); break; - case "MovieTimeMS": result.MovieTimeMS = submember.Data.Data.ToString(); break; - case "MovieYear": result.MovieYear = submember.Data.Data.ToString(); break; - case "SubActualCD": result.SubActualCD = submember.Data.Data.ToString(); break; - case "SubAddDate": result.SubAddDate = submember.Data.Data.ToString(); break; - case "SubAuthorComment": result.SubAuthorComment = submember.Data.Data.ToString(); break; - case "SubBad": result.SubBad = submember.Data.Data.ToString(); break; - case "SubDownloadLink": result.SubDownloadLink = submember.Data.Data.ToString(); break; - case "SubDownloadsCnt": result.SubDownloadsCnt = submember.Data.Data.ToString(); break; - case "SeriesEpisode": result.SeriesEpisode = submember.Data.Data.ToString(); break; - case "SeriesSeason": result.SeriesSeason = submember.Data.Data.ToString(); break; - case "SubFileName": result.SubFileName = submember.Data.Data.ToString(); break; - case "SubFormat": result.SubFormat = submember.Data.Data.ToString(); break; - case "SubHash": result.SubHash = submember.Data.Data.ToString(); break; - case "SubLanguageID": result.SubLanguageID = submember.Data.Data.ToString(); break; - case "SubRating": result.SubRating = submember.Data.Data.ToString(); break; - case "SubSize": result.SubSize = submember.Data.Data.ToString(); break; - case "SubSumCD": result.SubSumCD = submember.Data.Data.ToString(); break; - case "UserID": result.UserID = submember.Data.Data.ToString(); break; - case "UserNickName": result.UserNickName = submember.Data.Data.ToString(); break; - case "ZipDownloadLink": result.ZipDownloadLink = submember.Data.Data.ToString(); break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine(">" + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "Search Subtitles call failed !"); - } - - public static async Task SearchSubtitlesAsync(SubtitleSearchParameters[] parameters, CancellationToken cancellationToken) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - if (parameters == null) - { - OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle search parameter passed"); - } - if (parameters.Length == 0) - { - OSHConsole.UpdateLine("No subtitle search parameter passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle search parameter passed"); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add subtitle search parameters. Each one will be like 'array' of structs. - var array = new XmlRpcValueArray(); - foreach (SubtitleSearchParameters param in parameters) - { - var strct = new XmlRpcValueStruct(new List()); - // sublanguageid member - var member = new XmlRpcStructMember("sublanguageid", - new XmlRpcValueBasic(param.SubLangaugeID, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - // moviehash member - if (param.MovieHash.Length > 0 && param.MovieByteSize > 0) - { - member = new XmlRpcStructMember("moviehash", - new XmlRpcValueBasic(param.MovieHash, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - // moviehash member - member = new XmlRpcStructMember("moviebytesize", - new XmlRpcValueBasic(param.MovieByteSize, XmlRpcBasicValueType.Int)); - strct.Members.Add(member); - } - if (param.Query.Length > 0) - { - member = new XmlRpcStructMember("query", - new XmlRpcValueBasic(param.Query, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - - if (param.Episode.Length > 0 && param.Season.Length > 0) - { - member = new XmlRpcStructMember("season", - new XmlRpcValueBasic(param.Season, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - member = new XmlRpcStructMember("episode", - new XmlRpcValueBasic(param.Episode, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - - // imdbid member - if (param.IMDbID.Length > 0) - { - member = new XmlRpcStructMember("imdbid", - new XmlRpcValueBasic(param.IMDbID, XmlRpcBasicValueType.String)); - strct.Members.Add(member); - } - // Add the struct to the array - array.Values.Add(strct); - } - // Add the array to the parameters - parms.Add(array); - // Call ! - var call = new XmlRpcMethodCall("SearchSubtitles", parms); - OSHConsole.WriteLine("Sending SearchSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(await Utilities.SendRequestAsync(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT, cancellationToken).ConfigureAwait(false)); - - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - // We expect Struct of 3 members: - //* the first is status - //* the second is [array of structs, each one includes subtitle file]. - //* the third is [double basic value] represent seconds token by server. - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSubtitleSearch(); - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Search results: "); - - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new SubtitleSearchResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "IDMovie": result.IDMovie = submember.Data.Data.ToString(); break; - case "IDMovieImdb": result.IDMovieImdb = submember.Data.Data.ToString(); break; - case "IDSubMovieFile": result.IDSubMovieFile = submember.Data.Data.ToString(); break; - case "IDSubtitle": result.IDSubtitle = submember.Data.Data.ToString(); break; - case "IDSubtitleFile": result.IDSubtitleFile = submember.Data.Data.ToString(); break; - case "ISO639": result.ISO639 = submember.Data.Data.ToString(); break; - case "LanguageName": result.LanguageName = submember.Data.Data.ToString(); break; - case "MovieByteSize": result.MovieByteSize = submember.Data.Data.ToString(); break; - case "MovieHash": result.MovieHash = submember.Data.Data.ToString(); break; - case "MovieImdbRating": result.MovieImdbRating = submember.Data.Data.ToString(); break; - case "MovieName": result.MovieName = submember.Data.Data.ToString(); break; - case "MovieNameEng": result.MovieNameEng = submember.Data.Data.ToString(); break; - case "MovieReleaseName": result.MovieReleaseName = submember.Data.Data.ToString(); break; - case "MovieTimeMS": result.MovieTimeMS = submember.Data.Data.ToString(); break; - case "MovieYear": result.MovieYear = submember.Data.Data.ToString(); break; - case "SubActualCD": result.SubActualCD = submember.Data.Data.ToString(); break; - case "SubAddDate": result.SubAddDate = submember.Data.Data.ToString(); break; - case "SubAuthorComment": result.SubAuthorComment = submember.Data.Data.ToString(); break; - case "SubBad": result.SubBad = submember.Data.Data.ToString(); break; - case "SubDownloadLink": result.SubDownloadLink = submember.Data.Data.ToString(); break; - case "SubDownloadsCnt": result.SubDownloadsCnt = submember.Data.Data.ToString(); break; - case "SeriesEpisode": result.SeriesEpisode = submember.Data.Data.ToString(); break; - case "SeriesSeason": result.SeriesSeason = submember.Data.Data.ToString(); break; - case "SubFileName": result.SubFileName = submember.Data.Data.ToString(); break; - case "SubFormat": result.SubFormat = submember.Data.Data.ToString(); break; - case "SubHash": result.SubHash = submember.Data.Data.ToString(); break; - case "SubLanguageID": result.SubLanguageID = submember.Data.Data.ToString(); break; - case "SubRating": result.SubRating = submember.Data.Data.ToString(); break; - case "SubSize": result.SubSize = submember.Data.Data.ToString(); break; - case "SubSumCD": result.SubSumCD = submember.Data.Data.ToString(); break; - case "UserID": result.UserID = submember.Data.Data.ToString(); break; - case "UserNickName": result.UserNickName = submember.Data.Data.ToString(); break; - case "ZipDownloadLink": result.ZipDownloadLink = submember.Data.Data.ToString(); break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine(">" + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "Search Subtitles call failed !"); - } - - /// - /// Download subtitle file(s) - /// - /// The subtitle IDS (an array of IDSubtitleFile value that given by server as SearchSubtiles results) - /// Status of the call operation. If the call success the response will be 'MethodResponseSubtitleDownload' which will hold downloaded subtitles - public static IMethodResponse DownloadSubtitles(int[] subIDS) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - if (subIDS == null) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - if (subIDS.Length == 0) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add subtitle search parameters. Each one will be like 'array' of structs. - var array = new XmlRpcValueArray(); - foreach (int id in subIDS) - { - array.Values.Add(new XmlRpcValueBasic(id, XmlRpcBasicValueType.Int)); - } - // Add the array to the parameters - parms.Add(array); - // Call ! - var call = new XmlRpcMethodCall("DownloadSubtitles", parms); - OSHConsole.WriteLine("Sending DownloadSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - // We expect Struct of 3 members: - //* the first is status - //* the second is [array of structs, each one includes subtitle file]. - //* the third is [double basic value] represent seconds token by server. - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSubtitleDownload(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Download results:"); - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new SubtitleDownloadResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "idsubtitlefile": result.IdSubtitleFile = (string)submember.Data.Data; break; - case "data": result.Data = (string)submember.Data.Data; break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine("> IDSubtilteFile= " + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "DownloadSubtitles call failed !"); - } - - public static async Task DownloadSubtitlesAsync(int[] subIDS, CancellationToken cancellationToken) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - if (subIDS == null) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - if (subIDS.Length == 0) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add subtitle search parameters. Each one will be like 'array' of structs. - var array = new XmlRpcValueArray(); - foreach (int id in subIDS) - { - array.Values.Add(new XmlRpcValueBasic(id, XmlRpcBasicValueType.Int)); - } - // Add the array to the parameters - parms.Add(array); - // Call ! - var call = new XmlRpcMethodCall("DownloadSubtitles", parms); - OSHConsole.WriteLine("Sending DownloadSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - - var httpResponse = await Utilities.SendRequestAsync(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT, cancellationToken).ConfigureAwait(false); - - string response = Utilities.GetStreamString(httpResponse); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - // We expect Struct of 3 members: - //* the first is status - //* the second is [array of structs, each one includes subtitle file]. - //* the third is [double basic value] represent seconds token by server. - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSubtitleDownload(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Download results:"); - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new SubtitleDownloadResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "idsubtitlefile": result.IdSubtitleFile = (string)submember.Data.Data; break; - case "data": result.Data = (string)submember.Data.Data; break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine("> IDSubtilteFile= " + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "DownloadSubtitles call failed !"); - } - - /// - /// Returns comments for subtitles - /// - /// The subtitle IDS (an array of IDSubtitleFile value that given by server as SearchSubtiles results) - /// Status of the call operation. If the call success the response will be 'MethodResponseGetComments' - public static IMethodResponse GetComments(int[] subIDS) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - if (subIDS == null) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - if (subIDS.Length == 0) - { - OSHConsole.UpdateLine("No subtitle id passed !!", DebugCode.Error); - return new MethodResponseError("Fail", "No subtitle id passed"); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN)); - // Add subtitle search parameters. Each one will be like 'array' of structs. - var array = new XmlRpcValueArray(subIDS); - // Add the array to the parameters - parms.Add(array); - // Call ! - var call = new XmlRpcMethodCall("GetComments", parms); - OSHConsole.WriteLine("Sending GetComments request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseGetComments(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Comments results:"); - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue commentStruct in rarray.Values) - { - if (commentStruct == null) continue; - if (!(commentStruct is XmlRpcValueStruct)) continue; - - var result = new GetCommentsResult(); - foreach (XmlRpcStructMember commentmember in ((XmlRpcValueStruct)commentStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (commentmember.Name) - { - case "IDSubtitle": result.IDSubtitle = (string)commentmember.Data.Data; break; - case "UserID": result.UserID = (string)commentmember.Data.Data; break; - case "UserNickName": result.UserNickName = (string)commentmember.Data.Data; break; - case "Comment": result.Comment = (string)commentmember.Data.Data; break; - case "Created": result.Created = (string)commentmember.Data.Data; break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine("> IDSubtitle= " + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "GetComments call failed !"); - } - - /// - /// Schedule a periodical search for subtitles matching given video files, send results to user's e-mail address. - /// - /// The language 3 lenght ids array - /// The movies parameters - /// Status of the call operation. If the call success the response will be 'MethodResponseSearchToMail' - public static IMethodResponse SearchToMail(string[] languageIDS, SearchToMailMovieParameter[] movies) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Array of sub langs - var a = new XmlRpcValueArray(languageIDS); - parms.Add(a); - // Array of video parameters - a = new XmlRpcValueArray(); - foreach (SearchToMailMovieParameter p in movies) - { - var str = new XmlRpcValueStruct(new List()); - str.Members.Add(new XmlRpcStructMember("moviehash", new XmlRpcValueBasic(p.moviehash))); - str.Members.Add(new XmlRpcStructMember("moviesize", new XmlRpcValueBasic(p.moviesize))); - a.Values.Add(str); - } - parms.Add(a); - var call = new XmlRpcMethodCall("SearchToMail", parms); - - OSHConsole.WriteLine("Sending SearchToMail request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSearchToMail(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "SearchToMail call failed !"); - } - /*Movies*/ - /// - /// Search for a movie (using movie title) - /// - /// Movie title user is searching for, this is cleaned-up a bit (remove dvdrip, etc.) before searching - /// Status of the call operation. If the call success the response will be 'MethodResponseSubtitleSearch' - public static IMethodResponse SearchMoviesOnIMDB(string query) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add query param - parms.Add(new XmlRpcValueBasic(query, XmlRpcBasicValueType.String)); - // Call ! - var call = new XmlRpcMethodCall("SearchMoviesOnIMDB", parms); - OSHConsole.WriteLine("Sending SearchMoviesOnIMDB request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseMovieSearch(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Search results:"); - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new MovieSearchResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "id": result.ID = (string)submember.Data.Data; break; - case "title": result.Title = (string)submember.Data.Data; break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine(">" + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "SearchMoviesOnIMDB call failed !"); - } - /// - /// Get movie details for given IMDb ID - /// - /// http://www.imdb.com/ - /// Status of the call operation. If the call success the response will be 'MethodResponseMovieDetails' - public static IMethodResponse GetIMDBMovieDetails(string imdbid) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN)); - // Add query param - parms.Add(new XmlRpcValueBasic(imdbid)); - // Call ! - var call = new XmlRpcMethodCall("GetIMDBMovieDetails", parms); - OSHConsole.WriteLine("Sending GetIMDBMovieDetails request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseMovieDetails(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "data") - { - // We expect struct with details... - if (MEMBER.Data is XmlRpcValueStruct) - { - OSHConsole.WriteLine("Details result:"); - var detailsStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dmem in detailsStruct.Members) - { - switch (dmem.Name) - { - case "id": R.ID = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "title": R.Title = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "year": R.Year = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "cover": R.CoverLink = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "duration": R.Duration = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "tagline": R.Tagline = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "plot": R.Plot = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "goofs": R.Goofs = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "trivia": R.Trivia = dmem.Data.Data.ToString(); OSHConsole.WriteLine(">" + dmem.Name + "= " + dmem.Data.Data.ToString()); break; - case "cast": - // this is another struct with cast members... - OSHConsole.WriteLine(">" + dmem.Name + "= "); - var castStruct = (XmlRpcValueStruct)dmem.Data; - foreach (XmlRpcStructMember castMemeber in castStruct.Members) - { - R.Cast.Add(castMemeber.Data.Data.ToString()); - OSHConsole.WriteLine(" >" + castMemeber.Data.Data.ToString()); - } - break; - case "directors": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is another struct with directors members... - var directorsStruct = (XmlRpcValueStruct)dmem.Data; - foreach (XmlRpcStructMember directorsMember in directorsStruct.Members) - { - R.Directors.Add(directorsMember.Data.Data.ToString()); - OSHConsole.WriteLine(" >" + directorsMember.Data.Data.ToString()); - } - break; - case "writers": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is another struct with writers members... - var writersStruct = (XmlRpcValueStruct)dmem.Data; - foreach (XmlRpcStructMember writersMember in writersStruct.Members) - { - R.Writers.Add(writersMember.Data.Data.ToString()); - OSHConsole.WriteLine("+->" + writersMember.Data.Data.ToString()); - } - break; - case "awards": - // this is an array of genres... - var awardsArray = (XmlRpcValueArray)dmem.Data; - foreach (XmlRpcValueBasic award in awardsArray.Values) - { - R.Awards.Add(award.Data.ToString()); - OSHConsole.WriteLine(" >" + award.Data.ToString()); - } - break; - case "genres": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is an array of genres... - var genresArray = (XmlRpcValueArray)dmem.Data; - foreach (XmlRpcValueBasic genre in genresArray.Values) - { - R.Genres.Add(genre.Data.ToString()); - OSHConsole.WriteLine(" >" + genre.Data.ToString()); - } - break; - case "country": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is an array of country... - var countryArray = (XmlRpcValueArray)dmem.Data; - foreach (XmlRpcValueBasic country in countryArray.Values) - { - R.Country.Add(country.Data.ToString()); - OSHConsole.WriteLine(" >" + country.Data.ToString()); - } - break; - case "language": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is an array of language... - var languageArray = (XmlRpcValueArray)dmem.Data; - foreach (XmlRpcValueBasic language in languageArray.Values) - { - R.Language.Add(language.Data.ToString()); - OSHConsole.WriteLine(" >" + language.Data.ToString()); - } - break; - case "certification": - OSHConsole.WriteLine(">" + dmem.Name + "= "); - // this is an array of certification... - var certificationArray = (XmlRpcValueArray)dmem.Data; - foreach (XmlRpcValueBasic certification in certificationArray.Values) - { - R.Certification.Add(certification.Data.ToString()); - OSHConsole.WriteLine(" >" + certification.Data.ToString()); - } - break; - } - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "GetIMDBMovieDetails call failed !"); - } - /// - /// Allows registered users to insert new movies (not stored in IMDb) to the database. - /// - /// Movie title - /// Release year - /// Status of the call operation. If the call success the response will be 'MethodResponseInsertMovie' - public static IMethodResponse InsertMovie(string movieName, string movieyear) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - // Add token param - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // Add movieinfo struct - var movieinfo = new XmlRpcValueStruct(new List()); - movieinfo.Members.Add(new XmlRpcStructMember("moviename", new XmlRpcValueBasic(movieName))); - movieinfo.Members.Add(new XmlRpcStructMember("movieyear", new XmlRpcValueBasic(movieyear))); - parms.Add(movieinfo); - // Call ! - var call = new XmlRpcMethodCall("InsertMovie", parms); - OSHConsole.WriteLine("Sending InsertMovie request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseInsertMovie(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - if (MEMBER.Name == "status") - { - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("Status= " + R.Status); - } - else if (MEMBER.Name == "seconds") - { - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine("Seconds= " + R.Seconds); - } - else if (MEMBER.Name == "id") - { - R.ID = (string)MEMBER.Data.Data; - OSHConsole.WriteLine("ID= " + R.Seconds); - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "InsertMovie call failed !"); - } - /// - /// Inserts or updates data to tables, which are used for CheckMovieHash() and !CheckMovieHash2(). - /// - /// The parameters - /// Status of the call operation. If the call success the response will be 'MethodResponseInsertMovieHash' - public static IMethodResponse InsertMovieHash(InsertMovieHashParameters[] parameters) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - foreach (InsertMovieHashParameters p in parameters) - { - var pstruct = new XmlRpcValueStruct(new List()); - pstruct.Members.Add(new XmlRpcStructMember("moviehash", new XmlRpcValueBasic(p.moviehash))); - pstruct.Members.Add(new XmlRpcStructMember("moviebytesize", new XmlRpcValueBasic(p.moviebytesize))); - pstruct.Members.Add(new XmlRpcStructMember("imdbid", new XmlRpcValueBasic(p.imdbid))); - pstruct.Members.Add(new XmlRpcStructMember("movietimems", new XmlRpcValueBasic(p.movietimems))); - pstruct.Members.Add(new XmlRpcStructMember("moviefps", new XmlRpcValueBasic(p.moviefps))); - pstruct.Members.Add(new XmlRpcStructMember("moviefilename", new XmlRpcValueBasic(p.moviefilename))); - parms.Add(pstruct); - } - var call = new XmlRpcMethodCall("InsertMovieHash", parms); - - OSHConsole.WriteLine("Sending InsertMovieHash request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseInsertMovieHash(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "seconds": - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - switch (dataMember.Name) - { - case "accepted_moviehashes": - var mh = (XmlRpcValueArray)dataMember.Data; - foreach (IXmlRpcValue val in mh.Values) - { - if (val is XmlRpcValueBasic) - { - R.accepted_moviehashes.Add(val.Data.ToString()); - } - } - break; - case "new_imdbs": - var mi = (XmlRpcValueArray)dataMember.Data; - foreach (IXmlRpcValue val in mi.Values) - { - if (val is XmlRpcValueBasic) - { - R.new_imdbs.Add(val.Data.ToString()); - } - } - break; - } - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "InsertMovieHash call failed !"); - } - /*Reporting and rating*/ - /// - /// Get basic server information and statistics - /// - /// Status of the call operation. If the call success the response will be 'MethodResponseServerInfo' - public static IMethodResponse ServerInfo() - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT, XmlRpcBasicValueType.String)); - var call = new XmlRpcMethodCall("ServerInfo", parms); - - OSHConsole.WriteLine("Sending ServerInfo request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseServerInfo(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "seconds": - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "xmlrpc_version": - R.xmlrpc_version = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "xmlrpc_url": - R.xmlrpc_url = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "application": - R.application = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "contact": - R.contact = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "website_url": - R.website_url = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "users_online_total": - R.users_online_total = (int)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "users_online_program": - R.users_online_program = (int)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "users_loggedin": - R.users_loggedin = (int)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "users_max_alltime": - R.users_max_alltime = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "users_registered": - R.users_registered = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "subs_downloads": - R.subs_downloads = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "subs_subtitle_files": - R.subs_subtitle_files = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "movies_total": - R.movies_total = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "movies_aka": - R.movies_aka = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "total_subtitles_languages": - R.total_subtitles_languages = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "last_update_strings": - //R.total_subtitles_languages = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + ":"); - var luStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember luMemeber in luStruct.Members) - { - R.last_update_strings.Add(luMemeber.Name + " [" + luMemeber.Data.Data.ToString() + "]"); - OSHConsole.WriteLine(" >" + luMemeber.Name + "= " + luMemeber.Data.Data.ToString()); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "ServerInfo call failed !"); - } - /// - /// Report wrong subtitle file <--> video file combination - /// - /// Identifier of the subtitle file <--> video file combination - /// Status of the call operation. If the call success the response will be 'MethodResponseReportWrongMovieHash' - public static IMethodResponse ReportWrongMovieHash(string IDSubMovieFile) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - parms.Add(new XmlRpcValueBasic(IDSubMovieFile, XmlRpcBasicValueType.String)); - var call = new XmlRpcMethodCall("ReportWrongMovieHash", parms); - - OSHConsole.WriteLine("Sending ReportWrongMovieHash request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseReportWrongMovieHash(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": - R.Status = (string)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - case "seconds": - R.Seconds = (double)MEMBER.Data.Data; - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "ReportWrongMovieHash call failed !"); - } - /// - /// This method is needed to report bad movie hash for imdbid. This method should be used for correcting wrong entries, - /// when using CheckMovieHash2. Pass moviehash and moviebytesize for file, and imdbid as new, corrected one IMDBID - /// (id number without trailing zeroes). After some reports, moviehash will be linked to new imdbid. - /// - /// The movie hash - /// The movie size in bytes - /// The movie imbid - /// Status of the call operation. If the call success the response will be 'MethodResponseReportWrongImdbMovie' - public static IMethodResponse ReportWrongImdbMovie(string moviehash, string moviebytesize, string imdbid) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var s = new XmlRpcValueStruct(new List()); - s.Members.Add(new XmlRpcStructMember("moviehash", new XmlRpcValueBasic(moviehash))); - s.Members.Add(new XmlRpcStructMember("moviebytesize", new XmlRpcValueBasic(moviebytesize))); - s.Members.Add(new XmlRpcStructMember("imdbid", new XmlRpcValueBasic(imdbid))); - parms.Add(s); - var call = new XmlRpcMethodCall("ReportWrongImdbMovie", parms); - - OSHConsole.WriteLine("Sending ReportWrongImdbMovie request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseAddComment(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "ReportWrongImdbMovie call failed !"); - } - /// - /// Rate subtitles - /// - /// Id of subtitle (NOT subtitle file) user wants to rate - /// Subtitle rating, must be in interval 1 (worst) to 10 (best). - /// Status of the call operation. If the call success the response will be 'MethodResponseSubtitlesVote' - public static IMethodResponse SubtitlesVote(int idsubtitle, int score) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var s = new XmlRpcValueStruct(new List()); - s.Members.Add(new XmlRpcStructMember("idsubtitle", new XmlRpcValueBasic(idsubtitle))); - s.Members.Add(new XmlRpcStructMember("score", new XmlRpcValueBasic(score))); - parms.Add(s); - var call = new XmlRpcMethodCall("SubtitlesVote", parms); - - OSHConsole.WriteLine("Sending SubtitlesVote request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseSubtitlesVote(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dataMemeber in dataStruct.Members) - { - OSHConsole.WriteLine(" >" + dataMemeber.Name + "= " + dataMemeber.Data.Data.ToString()); - switch (dataMemeber.Name) - { - case "SubRating": R.SubRating = dataMemeber.Data.Data.ToString(); break; - case "SubSumVotes": R.SubSumVotes = dataMemeber.Data.Data.ToString(); break; - case "IDSubtitle": R.IDSubtitle = dataMemeber.Data.Data.ToString(); break; - } - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "SubtitlesVote call failed !"); - } - /// - /// Add comment to a subtitle - /// - /// Subtitle identifier (BEWARE! this is not the ID of subtitle file but of the whole subtitle (a subtitle can contain multiple subtitle files)) - /// User's comment - /// Optional parameter. If set to 1, subtitles are marked as bad. - /// Status of the call operation. If the call success the response will be 'MethodResponseAddComment' - public static IMethodResponse AddComment(int idsubtitle, string comment, int badsubtitle) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var s = new XmlRpcValueStruct(new List()); - s.Members.Add(new XmlRpcStructMember("idsubtitle", new XmlRpcValueBasic(idsubtitle))); - s.Members.Add(new XmlRpcStructMember("comment", new XmlRpcValueBasic(comment))); - s.Members.Add(new XmlRpcStructMember("badsubtitle", new XmlRpcValueBasic(badsubtitle))); - parms.Add(s); - var call = new XmlRpcMethodCall("AddComment", parms); - - OSHConsole.WriteLine("Sending AddComment request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseAddComment(); - - // To make sure response is not currepted by server, do it in loop - foreach (var MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "AddComment call failed !"); - } - /// - /// Add new request for subtitles, user must be logged in - /// - /// The subtitle language id 3 length - /// http://www.imdb.com/ - /// The comment - /// Status of the call operation. If the call success the response will be 'MethodResponseAddRequest' - public static IMethodResponse AddRequest(string sublanguageid, string idmovieimdb, string comment) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var s = new XmlRpcValueStruct(new List()); - s.Members.Add(new XmlRpcStructMember("sublanguageid", new XmlRpcValueBasic(sublanguageid))); - s.Members.Add(new XmlRpcStructMember("idmovieimdb", new XmlRpcValueBasic(idmovieimdb))); - s.Members.Add(new XmlRpcStructMember("comment", new XmlRpcValueBasic(comment))); - parms.Add(s); - var call = new XmlRpcMethodCall("AddRequest", parms); - - OSHConsole.WriteLine("Sending AddRequest request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseAddRequest(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dataMemeber in dataStruct.Members) - { - switch (dataMemeber.Name) - { - case "request_url": R.request_url = dataMemeber.Data.Data.ToString(); OSHConsole.WriteLine(">" + dataMemeber.Name + "= " + dataMemeber.Data.Data.ToString()); break; - } - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "AddRequest call failed !"); - } - /*User interface*/ - /// - /// Get list of supported subtitle languages - /// - /// ISO639-1 2-letter language code of user's interface language. - /// Status of the call operation. If the call success the response will be 'MethodResponseGetSubLanguages' - public static IMethodResponse GetSubLanguages(string language) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueBasic(language)); - var call = new XmlRpcMethodCall("GetSubLanguages", parms); - - OSHConsole.WriteLine("Sending GetSubLanguages request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseGetSubLanguages(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data":// array of structs - var array = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue value in array.Values) - { - if (value is XmlRpcValueStruct) - { - var valueStruct = (XmlRpcValueStruct)value; - var lang = new SubtitleLanguage(); - OSHConsole.WriteLine(">SubLanguage:"); - foreach (XmlRpcStructMember langMemeber in valueStruct.Members) - { - OSHConsole.WriteLine(" >" + langMemeber.Name + "= " + langMemeber.Data.Data.ToString()); - switch (langMemeber.Name) - { - case "SubLanguageID": lang.SubLanguageID = langMemeber.Data.Data.ToString(); break; - case "LanguageName": lang.LanguageName = langMemeber.Data.Data.ToString(); break; - case "ISO639": lang.ISO639 = langMemeber.Data.Data.ToString(); break; - } - } - R.Languages.Add(lang); - } - else - { - OSHConsole.WriteLine(">" + MEMBER.Name + "= " + - MEMBER.Data.Data.ToString() + " [Struct expected !]", DebugCode.Warning); - } - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "GetSubLanguages call failed !"); - } - /// - /// Detect language for given strings - /// - /// Array of strings you want language detected for - /// The encoding that will be used to get buffer of given strings. (this is not OS official parameter) - /// Status of the call operation. If the call success the response will be 'MethodResponseDetectLanguage' - public static IMethodResponse DetectLanguage(string[] texts, Encoding encodingUsed) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - // We need to gzip texts then code them with base 24 - var decodedTexts = new List(); - foreach (string text in texts) - { - // compress - Stream str = new MemoryStream(); - byte[] stringData = encodingUsed.GetBytes(text); - str.Write(stringData, 0, stringData.Length); - str.Position = 0; - byte[] data = Utilities.Compress(str); - //base 64 - decodedTexts.Add(Convert.ToBase64String(data)); - } - parms.Add(new XmlRpcValueArray(decodedTexts.ToArray())); - var call = new XmlRpcMethodCall("DetectLanguage", parms); - - OSHConsole.WriteLine("Sending DetectLanguage request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseDetectLanguage(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - if (MEMBER.Data is XmlRpcValueStruct) - { - OSHConsole.WriteLine(">Languages:"); - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - var lang = new DetectLanguageResult(); - lang.InputSample = dataMember.Name; - lang.LanguageID = dataMember.Data.Data.ToString(); - R.Results.Add(lang); - OSHConsole.WriteLine(" >" + dataMember.Name + " (" + dataMember.Data.Data.ToString() + ")"); - } - } - else - { - OSHConsole.WriteLine(">Languages ?? Struct expected but server return another type!!", DebugCode.Warning); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "DetectLanguage call failed !"); - } - /// - /// Get available translations for given program - /// - /// Name of the program/client application you want translations for. Currently supported values: subdownloader, oscar - /// Status of the call operation. If the call success the response will be 'MethodResponseGetAvailableTranslations' - public static IMethodResponse GetAvailableTranslations(string program) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueBasic(program)); - var call = new XmlRpcMethodCall("GetAvailableTranslations", parms); - - OSHConsole.WriteLine("Sending GetAvailableTranslations request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseGetAvailableTranslations(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - OSHConsole.WriteLine(">data:"); - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - if (dataMember.Data is XmlRpcValueStruct) - { - var resStruct = (XmlRpcValueStruct)dataMember.Data; - var res = new GetAvailableTranslationsResult(); - res.LanguageID = dataMember.Name; - OSHConsole.WriteLine(" >LanguageID: " + dataMember.Name); - foreach (XmlRpcStructMember resMember in resStruct.Members) - { - switch (resMember.Name) - { - case "LastCreated": res.LastCreated = resMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + resMember.Name + "= " + resMember.Data.Data.ToString()); break; - case "StringsNo": res.StringsNo = resMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + resMember.Name + "= " + resMember.Data.Data.ToString()); break; - } - R.Results.Add(res); - } - } - else - { - OSHConsole.WriteLine(" >Struct expected !!", DebugCode.Warning); - } - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "GetAvailableTranslations call failed !"); - } - /// - /// Get a translation for given program and language - /// - /// language ​ISO639-1 2-letter code - /// available formats: [gnugettext compatible: mo, po] and [additional: txt, xml] - /// Name of the program/client application you want translations for. (currently supported values: subdownloader, oscar) - /// Status of the call operation. If the call success the response will be 'MethodResponseGetTranslation' - public static IMethodResponse GetTranslation(string iso639, string format, string program) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueBasic(iso639)); - parms.Add(new XmlRpcValueBasic(format)); - parms.Add(new XmlRpcValueBasic(program)); - var call = new XmlRpcMethodCall("GetTranslation", parms); - - OSHConsole.WriteLine("Sending GetTranslation request to the server ...", DebugCode.Good); - // Send the request to the server - //File.WriteAllText(".\\REQUEST_GetTranslation.xml", Encoding.ASCII.GetString(XmlRpcGenerator.Generate(call))); - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseGetTranslation(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": R.ContentData = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "GetTranslation call failed !"); - } - /// - /// Check for the latest version of given application - /// - /// name of the program/client application you want to check. (Currently supported values: subdownloader, oscar) - /// Status of the call operation. If the call success the response will be 'MethodResponseAutoUpdate' - public static IMethodResponse AutoUpdate(string program) - { - /*if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - }*/ - // Method call .. - var parms = new List(); - // parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueBasic(program)); - // parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT)); - - var call = new XmlRpcMethodCall("AutoUpdate", parms); - OSHConsole.WriteLine("Sending AutoUpdate request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseAutoUpdate(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "version": R.version = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "url_windows": R.url_windows = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "url_linux": R.url_linux = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "comments": R.comments = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "AutoUpdate call failed !"); - } - /*Checking*/ - /// - /// Check if video file hashes are already stored in the database - /// - /// Array of video file hashes - /// Status of the call operation. If the call success the response will be 'MethodResponseCheckMovieHash' - public static IMethodResponse CheckMovieHash(string[] hashes) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueArray(hashes)); - var call = new XmlRpcMethodCall("CheckMovieHash", parms); - - OSHConsole.WriteLine("Sending CheckMovieHash request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseCheckMovieHash(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - OSHConsole.WriteLine(">Data:"); - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - var res = new CheckMovieHashResult(); - res.Name = dataMember.Name; - OSHConsole.WriteLine(" >" + res.Name + ":"); - var movieStruct = (XmlRpcValueStruct)dataMember.Data; - foreach (XmlRpcStructMember movieMember in movieStruct.Members) - { - switch (movieMember.Name) - { - case "MovieHash": res.MovieHash = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieImdbID": res.MovieImdbID = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieName": res.MovieName = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieYear": res.MovieYear = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - } - } - R.Results.Add(res); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "CheckMovieHash call failed !"); - } - /// - /// Check if video file hashes are already stored in the database. This method returns matching !MovieImdbID, MovieName, MovieYear, SeriesSeason, SeriesEpisode, - /// MovieKind if available for each $moviehash, always sorted by SeenCount DESC. - /// - /// Array of video file hashes - /// Status of the call operation. If the call success the response will be 'MethodResponseCheckMovieHash2' - public static IMethodResponse CheckMovieHash2(string[] hashes) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueArray(hashes)); - var call = new XmlRpcMethodCall("CheckMovieHash2", parms); - - OSHConsole.WriteLine("Sending CheckMovieHash2 request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseCheckMovieHash2(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - OSHConsole.WriteLine(">Data:"); - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - var res = new CheckMovieHash2Result(); - res.Name = dataMember.Name; - OSHConsole.WriteLine(" >" + res.Name + ":"); - - var dataArray = (XmlRpcValueArray)dataMember.Data; - foreach (XmlRpcValueStruct movieStruct in dataArray.Values) - { - var d = new CheckMovieHash2Data(); - foreach (XmlRpcStructMember movieMember in movieStruct.Members) - { - switch (movieMember.Name) - { - case "MovieHash": d.MovieHash = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieImdbID": d.MovieImdbID = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieName": d.MovieName = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieYear": d.MovieYear = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "MovieKind": d.MovieKind = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "SeriesSeason": d.SeriesSeason = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "SeriesEpisode": d.SeriesEpisode = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - case "SeenCount": d.MovieYear = movieMember.Data.Data.ToString(); OSHConsole.WriteLine(" >" + movieMember.Name + "= " + movieMember.Data.Data.ToString()); break; - } - } - res.Items.Add(d); - } - R.Results.Add(res); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "CheckMovieHash2 call failed !"); - } - /// - /// Check if given subtitle files are already stored in the database - /// - /// Array of subtitle file hashes (MD5 hashes of subtitle file contents) - /// Status of the call operation. If the call success the response will be 'MethodResponseCheckSubHash' - public static IMethodResponse CheckSubHash(string[] hashes) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - parms.Add(new XmlRpcValueArray(hashes)); - var call = new XmlRpcMethodCall("CheckSubHash", parms); - - OSHConsole.WriteLine("Sending CheckSubHash request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseCheckSubHash(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - OSHConsole.WriteLine(">Data:"); - var dataStruct = (XmlRpcValueStruct)MEMBER.Data; - foreach (XmlRpcStructMember dataMember in dataStruct.Members) - { - OSHConsole.WriteLine(" >" + dataMember.Name + "= " + dataMember.Data.Data.ToString()); - var r = new CheckSubHashResult(); - r.Hash = dataMember.Name; - r.SubID = dataMember.Data.Data.ToString(); - R.Results.Add(r); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "CheckSubHash call failed !"); - } - /*Upload*/ - /// - /// Try to upload subtitles, perform pre-upload checking (i.e. check if subtitles already exist on server) - /// - /// The subtitle parameters collection to try to upload - /// Status of the call operation. If the call success the response will be 'MethodResponseTryUploadSubtitles' - public static IMethodResponse TryUploadSubtitles(TryUploadSubtitlesParameters[] subs) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN, XmlRpcBasicValueType.String)); - var s = new XmlRpcValueStruct(new List()); - int i = 1; - foreach (var cd in subs) - { - var member = new XmlRpcStructMember("cd" + i, null); - var memberStruct = new XmlRpcValueStruct(new List()); - memberStruct.Members.Add(new XmlRpcStructMember("subhash", new XmlRpcValueBasic(cd.subhash))); - memberStruct.Members.Add(new XmlRpcStructMember("subfilename", new XmlRpcValueBasic(cd.subfilename))); - memberStruct.Members.Add(new XmlRpcStructMember("moviehash", new XmlRpcValueBasic(cd.moviehash))); - memberStruct.Members.Add(new XmlRpcStructMember("moviebytesize", new XmlRpcValueBasic(cd.moviebytesize))); - memberStruct.Members.Add(new XmlRpcStructMember("moviefps", new XmlRpcValueBasic(cd.moviefps))); - memberStruct.Members.Add(new XmlRpcStructMember("movietimems", new XmlRpcValueBasic(cd.movietimems))); - memberStruct.Members.Add(new XmlRpcStructMember("movieframes", new XmlRpcValueBasic(cd.movieframes))); - memberStruct.Members.Add(new XmlRpcStructMember("moviefilename", new XmlRpcValueBasic(cd.moviefilename))); - member.Data = memberStruct; - s.Members.Add(member); - i++; - } - parms.Add(s); - var call = new XmlRpcMethodCall("TryUploadSubtitles", parms); - - OSHConsole.WriteLine("Sending TryUploadSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseTryUploadSubtitles(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "alreadyindb": R.AlreadyInDB = (int)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": - if (MEMBER.Data is XmlRpcValueArray) - { - OSHConsole.WriteLine("Results: "); - - var rarray = (XmlRpcValueArray)MEMBER.Data; - foreach (IXmlRpcValue subStruct in rarray.Values) - { - if (subStruct == null) continue; - if (!(subStruct is XmlRpcValueStruct)) continue; - - var result = new SubtitleSearchResult(); - foreach (XmlRpcStructMember submember in ((XmlRpcValueStruct)subStruct).Members) - { - // To avoid errors of arranged info or missing ones, let's do it with switch.. - switch (submember.Name) - { - case "IDMovie": result.IDMovie = submember.Data.Data.ToString(); break; - case "IDMovieImdb": result.IDMovieImdb = submember.Data.Data.ToString(); break; - case "IDSubMovieFile": result.IDSubMovieFile = submember.Data.Data.ToString(); break; - case "IDSubtitle": result.IDSubtitle = submember.Data.Data.ToString(); break; - case "IDSubtitleFile": result.IDSubtitleFile = submember.Data.Data.ToString(); break; - case "ISO639": result.ISO639 = submember.Data.Data.ToString(); break; - case "LanguageName": result.LanguageName = submember.Data.Data.ToString(); break; - case "MovieByteSize": result.MovieByteSize = submember.Data.Data.ToString(); break; - case "MovieHash": result.MovieHash = submember.Data.Data.ToString(); break; - case "MovieImdbRating": result.MovieImdbRating = submember.Data.Data.ToString(); break; - case "MovieName": result.MovieName = submember.Data.Data.ToString(); break; - case "MovieNameEng": result.MovieNameEng = submember.Data.Data.ToString(); break; - case "MovieReleaseName": result.MovieReleaseName = submember.Data.Data.ToString(); break; - case "MovieTimeMS": result.MovieTimeMS = submember.Data.Data.ToString(); break; - case "MovieYear": result.MovieYear = submember.Data.Data.ToString(); break; - case "SubActualCD": result.SubActualCD = submember.Data.Data.ToString(); break; - case "SubAddDate": result.SubAddDate = submember.Data.Data.ToString(); break; - case "SubAuthorComment": result.SubAuthorComment = submember.Data.Data.ToString(); break; - case "SubBad": result.SubBad = submember.Data.Data.ToString(); break; - case "SubDownloadLink": result.SubDownloadLink = submember.Data.Data.ToString(); break; - case "SubDownloadsCnt": result.SubDownloadsCnt = submember.Data.Data.ToString(); break; - case "SubFileName": result.SubFileName = submember.Data.Data.ToString(); break; - case "SubFormat": result.SubFormat = submember.Data.Data.ToString(); break; - case "SubHash": result.SubHash = submember.Data.Data.ToString(); break; - case "SubLanguageID": result.SubLanguageID = submember.Data.Data.ToString(); break; - case "SubRating": result.SubRating = submember.Data.Data.ToString(); break; - case "SubSize": result.SubSize = submember.Data.Data.ToString(); break; - case "SubSumCD": result.SubSumCD = submember.Data.Data.ToString(); break; - case "UserID": result.UserID = submember.Data.Data.ToString(); break; - case "UserNickName": result.UserNickName = submember.Data.Data.ToString(); break; - case "ZipDownloadLink": result.ZipDownloadLink = submember.Data.Data.ToString(); break; - } - } - R.Results.Add(result); - OSHConsole.WriteLine(">" + result.ToString()); - } - } - else// Unknown data ? - { - OSHConsole.WriteLine("Data= " + MEMBER.Data.Data.ToString(), DebugCode.Warning); - } - break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "TryUploadSubtitles call failed !"); - } - /// - /// Upload given subtitles to OSDb server - /// - /// The pamaters of upload method - /// Status of the call operation. If the call success the response will be 'MethodResponseUploadSubtitles' - public static IMethodResponse UploadSubtitles(UploadSubtitleInfoParameters info) - { - if (TOKEN == "") - { - OSHConsole.WriteLine("Can't do this call, 'token' value not set. Please use Log In method first.", DebugCode.Error); - return new MethodResponseError("Fail", "Can't do this call, 'token' value not set. Please use Log In method first."); - } - // Method call .. - var parms = new List(); - parms.Add(new XmlRpcValueBasic(TOKEN)); - // Main struct - var s = new XmlRpcValueStruct(new List()); - - // Base info member as struct - var member = new XmlRpcStructMember("baseinfo", null); - var memberStruct = new XmlRpcValueStruct(new List()); - memberStruct.Members.Add(new XmlRpcStructMember("idmovieimdb", new XmlRpcValueBasic(info.idmovieimdb))); - memberStruct.Members.Add(new XmlRpcStructMember("sublanguageid", new XmlRpcValueBasic(info.sublanguageid))); - memberStruct.Members.Add(new XmlRpcStructMember("moviereleasename", new XmlRpcValueBasic(info.moviereleasename))); - memberStruct.Members.Add(new XmlRpcStructMember("movieaka", new XmlRpcValueBasic(info.movieaka))); - memberStruct.Members.Add(new XmlRpcStructMember("subauthorcomment", new XmlRpcValueBasic(info.subauthorcomment))); - // memberStruct.Members.Add(new XmlRpcStructMember("hearingimpaired", new XmlRpcValueBasic(info.hearingimpaired))); - // memberStruct.Members.Add(new XmlRpcStructMember("highdefinition", new XmlRpcValueBasic(info.highdefinition))); - // memberStruct.Members.Add(new XmlRpcStructMember("automatictranslation", new XmlRpcValueBasic(info.automatictranslation))); - member.Data = memberStruct; - s.Members.Add(member); - - // CDS members - int i = 1; - foreach (UploadSubtitleParameters cd in info.CDS) - { - var member2 = new XmlRpcStructMember("cd" + i, null); - var memberStruct2 = new XmlRpcValueStruct(new List()); - memberStruct2.Members.Add(new XmlRpcStructMember("subhash", new XmlRpcValueBasic(cd.subhash))); - memberStruct2.Members.Add(new XmlRpcStructMember("subfilename", new XmlRpcValueBasic(cd.subfilename))); - memberStruct2.Members.Add(new XmlRpcStructMember("moviehash", new XmlRpcValueBasic(cd.moviehash))); - memberStruct2.Members.Add(new XmlRpcStructMember("moviebytesize", new XmlRpcValueBasic(cd.moviebytesize))); - memberStruct2.Members.Add(new XmlRpcStructMember("moviefps", new XmlRpcValueBasic(cd.moviefps))); - memberStruct2.Members.Add(new XmlRpcStructMember("movietimems", new XmlRpcValueBasic(cd.movietimems))); - memberStruct2.Members.Add(new XmlRpcStructMember("movieframes", new XmlRpcValueBasic(cd.movieframes))); - memberStruct2.Members.Add(new XmlRpcStructMember("moviefilename", new XmlRpcValueBasic(cd.moviefilename))); - memberStruct2.Members.Add(new XmlRpcStructMember("subcontent", new XmlRpcValueBasic(cd.subcontent))); - member2.Data = memberStruct2; - s.Members.Add(member2); - i++; - } - - // add main struct to parameters - parms.Add(s); - // add user agent - //parms.Add(new XmlRpcValueBasic(XML_PRC_USERAGENT)); - var call = new XmlRpcMethodCall("UploadSubtitles", parms); - OSHConsole.WriteLine("Sending UploadSubtitles request to the server ...", DebugCode.Good); - // Send the request to the server - string response = Utilities.GetStreamString(Utilities.SendRequest(XmlRpcGenerator.Generate(call), XML_PRC_USERAGENT)); - if (!response.Contains("ERROR:")) - { - // No error occur, get and decode the response. - XmlRpcMethodCall[] calls = XmlRpcGenerator.DecodeMethodResponse(response); - if (calls.Length > 0) - { - if (calls[0].Parameters.Count > 0) - { - var mainStruct = (XmlRpcValueStruct)calls[0].Parameters[0]; - // Create the response, we'll need it later - var R = new MethodResponseUploadSubtitles(); - - // To make sure response is not currepted by server, do it in loop - foreach (XmlRpcStructMember MEMBER in mainStruct.Members) - { - switch (MEMBER.Name) - { - case "status": R.Status = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "seconds": R.Seconds = (double)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "data": R.Data = (string)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - case "subtitles": R.SubTitles = (bool)MEMBER.Data.Data; OSHConsole.WriteLine(">" + MEMBER.Name + "= " + MEMBER.Data.Data.ToString()); break; - } - } - // Return the response to user !! - return R; - } - } - } - else - { - OSHConsole.WriteLine(response, DebugCode.Error); - return new MethodResponseError("Fail", response); - } - return new MethodResponseError("Fail", "UploadSubtitles call failed !"); - } - } -} diff --git a/OpenSubtitlesHandler/OpenSubtitlesHandler.csproj b/OpenSubtitlesHandler/OpenSubtitlesHandler.csproj deleted file mode 100644 index eabd3e070c..0000000000 --- a/OpenSubtitlesHandler/OpenSubtitlesHandler.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - netstandard2.0 - false - - - diff --git a/OpenSubtitlesHandler/OtherTypes/GetAvailableTranslationsResult.cs b/OpenSubtitlesHandler/OtherTypes/GetAvailableTranslationsResult.cs deleted file mode 100644 index 39d0485459..0000000000 --- a/OpenSubtitlesHandler/OtherTypes/GetAvailableTranslationsResult.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - public struct GetAvailableTranslationsResult - { - private string _language; - private string _LastCreated; - private string _StringsNo; - - public string LanguageID { get { return _language; } set { _language = value; } } - public string LastCreated { get { return _LastCreated; } set { _LastCreated = value; } } - public string StringsNo { get { return _StringsNo; } set { _StringsNo = value; } } - /// - /// LanguageID (LastCreated) - /// - /// - public override string ToString() - { - return _language + " (" + _LastCreated + ")"; - } - } -} diff --git a/OpenSubtitlesHandler/OtherTypes/GetCommentsResult.cs b/OpenSubtitlesHandler/OtherTypes/GetCommentsResult.cs deleted file mode 100644 index 8f4aa9db42..0000000000 --- a/OpenSubtitlesHandler/OtherTypes/GetCommentsResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct GetCommentsResult - { - private string _IDSubtitle; - private string _UserID; - private string _UserNickName; - private string _Comment; - private string _Created; - - public string IDSubtitle { get { return _IDSubtitle; } set { _IDSubtitle = value; } } - public string UserID { get { return _UserID; } set { _UserID = value; } } - public string UserNickName { get { return _UserNickName; } set { _UserNickName = value; } } - public string Comment { get { return _Comment; } set { _Comment = value; } } - public string Created { get { return _Created; } set { _Created = value; } } - } -} diff --git a/OpenSubtitlesHandler/Properties/AssemblyInfo.cs b/OpenSubtitlesHandler/Properties/AssemblyInfo.cs deleted file mode 100644 index b5ae23021c..0000000000 --- a/OpenSubtitlesHandler/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("OpenSubtitlesHandler")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] -[assembly: AssemblyCopyright("Copyright © 2013 Ala Ibrahim Hadid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NeutralResourcesLanguage("en")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -[assembly: AssemblyVersion("1.0.3.0")] -[assembly: AssemblyFileVersion("2019.1.20.3")] diff --git a/OpenSubtitlesHandler/Readme.txt b/OpenSubtitlesHandler/Readme.txt deleted file mode 100644 index d5814aec16..0000000000 --- a/OpenSubtitlesHandler/Readme.txt +++ /dev/null @@ -1,20 +0,0 @@ -OpenSubtitlesHandler -==================== -This project is for OpenSubtitles.org integration‏. The point is to allow user to access OpenSubtitles.org database directly -within ASM without the need to open internet browser. -The plan: Implement the "OSDb protocol" http://trac.opensubtitles.org/projects/opensubtitles/wiki/OSDb - -Copyright: -========= -This library ann all its content are written by Ala Ibrahim Hadid. -Copyright © Ala Ibrahim Hadid 2013 -mailto:ahdsoftwares@hotmail.com - -Resources: -========== -* GetHash.dll: this dll is used to compute hash for movie. - For more information please visit http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes#C2 - -XML_RPC: -======== -This class is created to generate XML-RPC requests as XML String. All you need is to call XML_RPC.Generate() method. diff --git a/OpenSubtitlesHandler/SubtitleTypes/CheckSubHashResult.cs b/OpenSubtitlesHandler/SubtitleTypes/CheckSubHashResult.cs deleted file mode 100644 index a2fbe87736..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/CheckSubHashResult.cs +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct CheckSubHashResult - { - private string _hash; - private string _id; - - public string Hash { get { return _hash; } set { _hash = value; } } - public string SubID { get { return _id; } set { _id = value; } } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/SubtitleDownloadResult.cs b/OpenSubtitlesHandler/SubtitleTypes/SubtitleDownloadResult.cs deleted file mode 100644 index e4194994c3..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/SubtitleDownloadResult.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct SubtitleDownloadResult - { - private string idsubtitlefile; - private string data; - - public string IdSubtitleFile - { get { return idsubtitlefile; } set { idsubtitlefile = value; } } - /// - /// Get or set the data of subtitle file. To decode, decode the string to base64 and then decompress with GZIP. - /// - public string Data - { get { return data; } set { data = value; } } - /// - /// IdSubtitleFile - /// - /// - public override string ToString() - { - return idsubtitlefile.ToString(); - } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/SubtitleLanguage.cs b/OpenSubtitlesHandler/SubtitleTypes/SubtitleLanguage.cs deleted file mode 100644 index b2dc154133..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/SubtitleLanguage.cs +++ /dev/null @@ -1,39 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace OpenSubtitlesHandler -{ - public struct SubtitleLanguage - { - private string _SubLanguageID; - private string _LanguageName; - private string _ISO639; - - public string SubLanguageID { get { return _SubLanguageID; } set { _SubLanguageID = value; } } - public string LanguageName { get { return _LanguageName; } set { _LanguageName = value; } } - public string ISO639 { get { return _ISO639; } set { _ISO639 = value; } } - /// - /// LanguageName [SubLanguageID] - /// - /// LanguageName [SubLanguageID] - public override string ToString() - { - return _LanguageName + " [" + _SubLanguageID + "]"; - } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchParameters.cs b/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchParameters.cs deleted file mode 100644 index 5c8f8c01a4..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchParameters.cs +++ /dev/null @@ -1,82 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - /// - /// Paramaters for subtitle search call - /// - public struct SubtitleSearchParameters - { - public SubtitleSearchParameters(string subLanguageId, string query = "", string season = "", string episode = "", string movieHash = "", long movieByteSize = 0, string imdbid = "") - { - this.subLanguageId = subLanguageId; - this.movieHash = movieHash; - this.movieByteSize = movieByteSize; - this.imdbid = imdbid; - this._episode = episode; - this._season = season; - this._query = query; - } - - private string subLanguageId; - private string movieHash; - private long movieByteSize; - private string imdbid; - private string _query; - private string _episode; - - public string Episode - { - get { return _episode; } - set { _episode = value; } - } - - public string Season - { - get { return _season; } - set { _season = value; } - } - - private string _season; - - public string Query - { - get { return _query; } - set { _query = value; } - } - - /// - /// List of language ISO639-3 language codes to search for, divided by ',' (e.g. 'cze,eng,slo') - /// - public string SubLangaugeID { get { return subLanguageId; } set { subLanguageId = value; } } - /// - /// Video file hash as calculated by one of the implementation functions as seen on http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes - /// - public string MovieHash { get { return movieHash; } set { movieHash = value; } } - /// - /// Size of video file in bytes - /// - public long MovieByteSize { get { return movieByteSize; } set { movieByteSize = value; } } - /// - /// ​IMDb ID of movie this video is part of, belongs to. - /// - public string IMDbID { get { return imdbid; } set { imdbid = value; } } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchResult.cs b/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchResult.cs deleted file mode 100644 index a4a8dd3e69..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/SubtitleSearchResult.cs +++ /dev/null @@ -1,136 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - /// - /// The subtitle search result that comes with server response on SearchSubtitles successed call - /// - public struct SubtitleSearchResult - { - private string _IDSubMovieFile; - private string _MovieHash; - private string _MovieByteSize; - private string _MovieTimeMS; - private string _IDSubtitleFile; - private string _SubFileName; - private string _SubActualCD; - private string _SubSize; - private string _SubHash; - private string _IDSubtitle; - private string _UserID; - private string _SubLanguageID; - private string _SubFormat; - private string _SeriesSeason; - private string _SeriesEpisode; - private string _SubSumCD; - private string _SubAuthorComment; - private string _SubAddDate; - private string _SubBad; - private string _SubRating; - private string _SubDownloadsCnt; - private string _MovieReleaseName; - private string _IDMovie; - private string _IDMovieImdb; - private string _MovieName; - private string _MovieNameEng; - private string _MovieYear; - private string _MovieImdbRating; - private string _UserNickName; - private string _ISO639; - private string _LanguageName; - private string _SubDownloadLink; - private string _ZipDownloadLink; - - public string IDSubMovieFile - { get { return _IDSubMovieFile; } set { _IDSubMovieFile = value; } } - public string MovieHash - { get { return _MovieHash; } set { _MovieHash = value; } } - public string MovieByteSize - { get { return _MovieByteSize; } set { _MovieByteSize = value; } } - public string MovieTimeMS - { get { return _MovieTimeMS; } set { _MovieTimeMS = value; } } - public string IDSubtitleFile - { get { return _IDSubtitleFile; } set { _IDSubtitleFile = value; } } - public string SubFileName - { get { return _SubFileName; } set { _SubFileName = value; } } - public string SubActualCD - { get { return _SubActualCD; } set { _SubActualCD = value; } } - public string SubSize - { get { return _SubSize; } set { _SubSize = value; } } - public string SubHash - { get { return _SubHash; } set { _SubHash = value; } } - public string IDSubtitle - { get { return _IDSubtitle; } set { _IDSubtitle = value; } } - public string UserID - { get { return _UserID; } set { _UserID = value; } } - public string SubLanguageID - { get { return _SubLanguageID; } set { _SubLanguageID = value; } } - public string SubFormat - { get { return _SubFormat; } set { _SubFormat = value; } } - public string SubSumCD - { get { return _SubSumCD; } set { _SubSumCD = value; } } - public string SubAuthorComment - { get { return _SubAuthorComment; } set { _SubAuthorComment = value; } } - public string SubAddDate - { get { return _SubAddDate; } set { _SubAddDate = value; } } - public string SubBad - { get { return _SubBad; } set { _SubBad = value; } } - public string SubRating - { get { return _SubRating; } set { _SubRating = value; } } - public string SubDownloadsCnt - { get { return _SubDownloadsCnt; } set { _SubDownloadsCnt = value; } } - public string MovieReleaseName - { get { return _MovieReleaseName; } set { _MovieReleaseName = value; } } - public string IDMovie - { get { return _IDMovie; } set { _IDMovie = value; } } - public string IDMovieImdb - { get { return _IDMovieImdb; } set { _IDMovieImdb = value; } } - public string MovieName - { get { return _MovieName; } set { _MovieName = value; } } - public string MovieNameEng - { get { return _MovieNameEng; } set { _MovieNameEng = value; } } - public string MovieYear - { get { return _MovieYear; } set { _MovieYear = value; } } - public string MovieImdbRating - { get { return _MovieImdbRating; } set { _MovieImdbRating = value; } } - public string UserNickName - { get { return _UserNickName; } set { _UserNickName = value; } } - public string ISO639 - { get { return _ISO639; } set { _ISO639 = value; } } - public string LanguageName - { get { return _LanguageName; } set { _LanguageName = value; } } - public string SubDownloadLink - { get { return _SubDownloadLink; } set { _SubDownloadLink = value; } } - public string ZipDownloadLink - { get { return _ZipDownloadLink; } set { _ZipDownloadLink = value; } } - public string SeriesSeason - { get { return _SeriesSeason; } set { _SeriesSeason = value; } } - public string SeriesEpisode - { get { return _SeriesEpisode; } set { _SeriesEpisode = value; } } - /// - /// SubFileName + " (" + SubFormat + ")" - /// - /// - public override string ToString() - { - return _SubFileName + " (" + _SubFormat + ")"; - } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/TryUploadSubtitlesParameters.cs b/OpenSubtitlesHandler/SubtitleTypes/TryUploadSubtitlesParameters.cs deleted file mode 100644 index 11f3a706c1..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/TryUploadSubtitlesParameters.cs +++ /dev/null @@ -1,47 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public class TryUploadSubtitlesParameters - { - private string _subhash = ""; - private string _subfilename = ""; - private string _moviehash = ""; - private string _moviebytesize = ""; - private int _movietimems = 0; - private int _movieframes = 0; - private double _moviefps = 0; - private string _moviefilename = ""; - - public string subhash { get { return _subhash; } set { _subhash = value; } } - public string subfilename { get { return _subfilename; } set { _subfilename = value; } } - public string moviehash { get { return _moviehash; } set { _moviehash = value; } } - public string moviebytesize { get { return _moviebytesize; } set { _moviebytesize = value; } } - public int movietimems { get { return _movietimems; } set { _movietimems = value; } } - public int movieframes { get { return _movieframes; } set { _movieframes = value; } } - public double moviefps { get { return _moviefps; } set { _moviefps = value; } } - public string moviefilename { get { return _moviefilename; } set { _moviefilename = value; } } - - public override string ToString() - { - return _subfilename + " (" + _subhash + ")"; - } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleInfoParameter.cs b/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleInfoParameter.cs deleted file mode 100644 index 133cc1d238..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleInfoParameter.cs +++ /dev/null @@ -1,46 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace OpenSubtitlesHandler -{ - public class UploadSubtitleInfoParameters - { - private string _idmovieimdb; - private string _moviereleasename; - private string _movieaka; - private string _sublanguageid; - private string _subauthorcomment; - private bool _hearingimpaired; - private bool _highdefinition; - private bool _automatictranslation; - private List cds; - - public string idmovieimdb { get { return _idmovieimdb; } set { _idmovieimdb = value; } } - public string moviereleasename { get { return _moviereleasename; } set { _moviereleasename = value; } } - public string movieaka { get { return _movieaka; } set { _movieaka = value; } } - public string sublanguageid { get { return _sublanguageid; } set { _sublanguageid = value; } } - public string subauthorcomment { get { return _subauthorcomment; } set { _subauthorcomment = value; } } - public bool hearingimpaired { get { return _hearingimpaired; } set { _hearingimpaired = value; } } - public bool highdefinition { get { return _highdefinition; } set { _highdefinition = value; } } - public bool automatictranslation { get { return _automatictranslation; } set { _automatictranslation = value; } } - public List CDS { get { return cds; } set { cds = value; } } - } -} diff --git a/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleParameters.cs b/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleParameters.cs deleted file mode 100644 index 9910dadc56..0000000000 --- a/OpenSubtitlesHandler/SubtitleTypes/UploadSubtitleParameters.cs +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace OpenSubtitlesHandler -{ - public struct UploadSubtitleParameters - { - private string _subhash; - private string _subfilename; - private string _moviehash; - private double _moviebytesize; - private int _movietimems; - private int _movieframes; - private double _moviefps; - private string _moviefilename; - private string _subcontent; - - public string subhash { get { return _subhash; } set { _subhash = value; } } - public string subfilename { get { return _subfilename; } set { _subfilename = value; } } - public string moviehash { get { return _moviehash; } set { _moviehash = value; } } - public double moviebytesize { get { return _moviebytesize; } set { _moviebytesize = value; } } - public int movietimems { get { return _movietimems; } set { _movietimems = value; } } - public int movieframes { get { return _movieframes; } set { _movieframes = value; } } - public double moviefps { get { return _moviefps; } set { _moviefps = value; } } - public string moviefilename { get { return _moviefilename; } set { _moviefilename = value; } } - /// - /// Sub content. Note: this value must be the subtitle file gziped and then base64 decoded. - /// - public string subcontent { get { return _subcontent; } set { _subcontent = value; } } - - public override string ToString() - { - return _subfilename + " (" + _subhash + ")"; - } - } -} diff --git a/OpenSubtitlesHandler/Utilities.cs b/OpenSubtitlesHandler/Utilities.cs deleted file mode 100644 index 429e28a8f4..0000000000 --- a/OpenSubtitlesHandler/Utilities.cs +++ /dev/null @@ -1,174 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Net; -using MediaBrowser.Model.Cryptography; - -namespace OpenSubtitlesHandler -{ - /// - /// Include helper methods. All member are statics. - /// - public sealed class Utilities - { - public static ICryptoProvider CryptographyProvider { get; set; } - public static IHttpClient HttpClient { get; set; } - private static string XML_RPC_SERVER = "https://api.opensubtitles.org/xml-rpc"; - //private static string XML_RPC_SERVER = "https://92.240.234.122/xml-rpc"; - private static string HostHeader = "api.opensubtitles.org:443"; - - /// - /// Compute movie hash - /// - /// The hash as Hexadecimal string - public static string ComputeHash(Stream stream) - { - byte[] hash = MovieHasher.ComputeMovieHash(stream); - return MovieHasher.ToHexadecimal(hash); - } - /// - /// Decompress data using GZip - /// - /// The stream that hold the data - /// Bytes array of decompressed data - public static byte[] Decompress(Stream dataToDecompress) - { - using (var target = new MemoryStream()) - { - using (var decompressionStream = new System.IO.Compression.GZipStream(dataToDecompress, System.IO.Compression.CompressionMode.Decompress)) - { - decompressionStream.CopyTo(target); - } - return target.ToArray(); - } - } - - /// - /// Compress data using GZip (the retunred buffer will be WITHOUT HEADER) - /// - /// The stream that hold the data - /// Bytes array of compressed data WITHOUT HEADER bytes - public static byte[] Compress(Stream dataToCompress) - { - /*using (var compressed = new MemoryStream()) - { - using (var compressor = new System.IO.Compression.GZipStream(compressed, - System.IO.Compression.CompressionMode.Compress)) - { - dataToCompress.CopyTo(compressor); - } - // Get the compressed bytes only after closing the GZipStream - return compressed.ToArray(); - }*/ - //using (var compressedOutput = new MemoryStream()) - //{ - // using (var compressedStream = new ZlibStream(compressedOutput, - // Ionic.Zlib.CompressionMode.Compress, - // CompressionLevel.Default, false)) - // { - // var buffer = new byte[4096]; - // int byteCount; - // do - // { - // byteCount = dataToCompress.Read(buffer, 0, buffer.Length); - - // if (byteCount > 0) - // { - // compressedStream.Write(buffer, 0, byteCount); - // } - // } while (byteCount > 0); - // } - // return compressedOutput.ToArray(); - //} - - throw new NotImplementedException(); - } - - /// - /// Handle server response stream and decode it as given encoding string. - /// - /// The string of the stream after decode using given encoding - public static string GetStreamString(Stream responseStream) - { - using (responseStream) - { - // Handle response, should be XML text. - var data = new List(); - while (true) - { - int r = responseStream.ReadByte(); - if (r < 0) - break; - data.Add((byte)r); - } - var bytes = data.ToArray(); - return Encoding.ASCII.GetString(bytes, 0, bytes.Length); - } - } - - public static byte[] GetASCIIBytes(string text) - { - return Encoding.ASCII.GetBytes(text); - } - - /// - /// Send a request to the server - /// - /// The request buffer to send as bytes array. - /// The user agent value. - /// Response of the server or stream of error message as string started with 'ERROR:' keyword. - public static Stream SendRequest(byte[] request, string userAgent) - { - return SendRequestAsync(request, userAgent, CancellationToken.None).Result; - } - - public static async Task SendRequestAsync(byte[] request, string userAgent, CancellationToken cancellationToken) - { - var options = new HttpRequestOptions - { - RequestContentBytes = request, - RequestContentType = "text/xml", - UserAgent = userAgent, - Host = HostHeader, - Url = XML_RPC_SERVER, - - // Response parsing will fail with this enabled - EnableHttpCompression = false, - - CancellationToken = cancellationToken, - BufferContent = false - }; - - if (string.IsNullOrEmpty(options.UserAgent)) - { - options.UserAgent = "xmlrpc-epi-php/0.2 (PHP)"; - } - - var result = await HttpClient.Post(options).ConfigureAwait(false); - - return result.Content; - } - - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Docs/XML-RPC.txt b/OpenSubtitlesHandler/XML-RPC/Docs/XML-RPC.txt deleted file mode 100644 index a4de38cdea..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Docs/XML-RPC.txt +++ /dev/null @@ -1,225 +0,0 @@ -XML-RPC Specification - -Tue, Jun 15, 1999; by Dave Winer. - -Updated 6/30/03 DW - -Updated 10/16/99 DW - -Updated 1/21/99 DW - -This specification documents the XML-RPC protocol implemented in UserLand Frontier 5.1. - -For a non-technical explanation, see XML-RPC for Newbies. - -This page provides all the information that an implementor needs. - -Overview - -XML-RPC is a Remote Procedure Calling protocol that works over the Internet. - -An XML-RPC message is an HTTP-POST request. The body of the request is in XML. A procedure executes on the server and the value it returns is also formatted in XML. - -Procedure parameters can be scalars, numbers, strings, dates, etc.; and can also be complex record and list structures. - -Request example - -Here's an example of an XML-RPC request: - -POST /RPC2 HTTP/1.0 -User-Agent: Frontier/5.1.2 (WinNT) -Host: betty.userland.com -Content-Type: text/xml -Content-length: 181 - - - - examples.getStateName - - - - 41 - - - - - -Header requirements - -The format of the URI in the first line of the header is not specified. For example, it could be empty, a single slash, if the server is only handling XML-RPC calls. However, if the server is handling a mix of incoming HTTP requests, we allow the URI to help route the request to the code that handles XML-RPC requests. (In the example, the URI is /RPC2, telling the server to route the request to the "RPC2" responder.) - -A User-Agent and Host must be specified. - -The Content-Type is text/xml. - -The Content-Length must be specified and must be correct. - -Payload format - -The payload is in XML, a single structure. - -The must contain a sub-item, a string, containing the name of the method to be called. The string may only contain identifier characters, upper and lower-case A-Z, the numeric characters, 0-9, underscore, dot, colon and slash. It's entirely up to the server to decide how to interpret the characters in a methodName. - -For example, the methodName could be the name of a file containing a script that executes on an incoming request. It could be the name of a cell in a database table. Or it could be a path to a file contained within a hierarchy of folders and files. - -If the procedure call has parameters, the must contain a sub-item. The sub-item can contain any number of s, each of which has a . - -Scalar s - -s can be scalars, type is indicated by nesting the value inside one of the tags listed in this table: - -Tag Type Example - or four-byte signed integer -12 - 0 (false) or 1 (true) 1 - string hello world - double-precision signed floating point number -12.214 - date/time 19980717T14:08:55 - base64-encoded binary eW91IGNhbid0IHJlYWQgdGhpcyE= - -If no type is indicated, the type is string. - -s - -A value can also be of type . - -A contains s and each contains a and a . - -Here's an example of a two-element : - - - - lowerBound - 18 - - - upperBound - 139 - - - -s can be recursive, any may contain a or any other type, including an , described below. - -s - -A value can also be of type . - -An contains a single element, which can contain any number of s. - -Here's an example of a four-element array: - - - - 12 - Egypt - 0 - -31 - - - - elements do not have names. - -You can mix types as the example above illustrates. - -s can be recursive, any value may contain an or any other type, including a , described above. - -Response example - -Here's an example of a response to an XML-RPC request: - -HTTP/1.1 200 OK -Connection: close -Content-Length: 158 -Content-Type: text/xml -Date: Fri, 17 Jul 1998 19:55:08 GMT -Server: UserLand Frontier/5.1.2-WinNT - - South Dakota - -Response format - -Unless there's a lower-level error, always return 200 OK. - -The Content-Type is text/xml. Content-Length must be present and correct. - -The body of the response is a single XML structure, a , which can contain a single which contains a single which contains a single . - -The could also contain a which contains a which is a containing two elements, one named , an and one named , a . - -A can not contain both a and a . - -Fault example - -HTTP/1.1 200 OK -Connection: close -Content-Length: 426 -Content-Type: text/xml -Date: Fri, 17 Jul 1998 19:55:02 GMT -Server: UserLand Frontier/5.1.2-WinNT - - faultCode 4 faultString Too many parameters. - -Strategies/Goals - -Firewalls. The goal of this protocol is to lay a compatible foundation across different environments, no new power is provided beyond the capabilities of the CGI interface. Firewall software can watch for POSTs whose Content-Type is text/xml. - -Discoverability. We wanted a clean, extensible format that's very simple. It should be possible for an HTML coder to be able to look at a file containing an XML-RPC procedure call, understand what it's doing, and be able to modify it and have it work on the first or second try. - -Easy to implement. We also wanted it to be an easy to implement protocol that could quickly be adapted to run in other environments or on other operating systems. - -Updated 1/21/99 DW - -The following questions came up on the UserLand discussion group as XML-RPC was being implemented in Python. - - The Response Format section says "The body of the response is a single XML structure, a , which can contain a single ..." This is confusing. Can we leave out the ? - - No you cannot leave it out if the procedure executed successfully. There are only two options, either a response contains a structure or it contains a structure. That's why we used the word "can" in that sentence. - - Is "boolean" a distinct data type, or can boolean values be interchanged with integers (e.g. zero=false, non-zero=true)? - - Yes, boolean is a distinct data type. Some languages/environments allow for an easy coercion from zero to false and one to true, but if you mean true, send a boolean type with the value true, so your intent can't possibly be misunderstood. - - What is the legal syntax (and range) for integers? How to deal with leading zeros? Is a leading plus sign allowed? How to deal with whitespace? - - An integer is a 32-bit signed number. You can include a plus or minus at the beginning of a string of numeric characters. Leading zeros are collapsed. Whitespace is not permitted. Just numeric characters preceeded by a plus or minus. - - What is the legal syntax (and range) for floating point values (doubles)? How is the exponent represented? How to deal with whitespace? Can infinity and "not a number" be represented? - - There is no representation for infinity or negative infinity or "not a number". At this time, only decimal point notation is allowed, a plus or a minus, followed by any number of numeric characters, followed by a period and any number of numeric characters. Whitespace is not allowed. The range of allowable values is implementation-dependent, is not specified. - - What characters are allowed in strings? Non-printable characters? Null characters? Can a "string" be used to hold an arbitrary chunk of binary data? - - Any characters are allowed in a string except < and &, which are encoded as < and &. A string can be used to encode binary data. - - Does the "struct" element keep the order of keys. Or in other words, is the struct "foo=1, bar=2" equivalent to "bar=2, foo=1" or not? - - The struct element does not preserve the order of the keys. The two structs are equivalent. - - Can the struct contain other members than and ? Is there a global list of faultCodes? (so they can be mapped to distinct exceptions for languages like Python and Java)? - - A struct may not contain members other than those specified. This is true for all other structures. We believe the specification is flexible enough so that all reasonable data-transfer needs can be accomodated within the specified structures. If you believe strongly that this is not true, please post a message on the discussion group. - - There is no global list of fault codes. It is up to the server implementer, or higher-level standards to specify fault codes. - - What timezone should be assumed for the dateTime.iso8601 type? UTC? localtime? - - Don't assume a timezone. It should be specified by the server in its documentation what assumptions it makes about timezones. - -Additions - - type. 1/21/99 DW. - -Updated 6/30/03 DW - -Removed "ASCII" from definition of string. - -Changed copyright dates, below, to 1999-2003 from 1998-99. - -Copyright and disclaimer - -© Copyright 1998-2003 UserLand Software. All Rights Reserved. - -This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and these paragraphs are included on all such copies and derivative works. - -This document may not be modified in any way, such as by removing the copyright notice or references to UserLand or other organizations. Further, while these copyright restrictions apply to the written XML-RPC specification, no claim of ownership is made by UserLand to the protocol it describes. Any party may, for commercial or non-commercial purposes, implement this protocol without royalty or license fee to UserLand. The limited permissions granted herein are perpetual and will not be revoked by UserLand or its successors or assigns. - -This document and the information contained herein is provided on an "AS IS" basis and USERLAND DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. diff --git a/OpenSubtitlesHandler/XML-RPC/Enums/XmlRpcValueType.cs b/OpenSubtitlesHandler/XML-RPC/Enums/XmlRpcValueType.cs deleted file mode 100644 index 51e0ee98f8..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Enums/XmlRpcValueType.cs +++ /dev/null @@ -1,25 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -namespace XmlRpcHandler -{ - public enum XmlRpcBasicValueType - { - String, Int, Boolean, Double, dateTime_iso8601, base64 - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Types/XmlRpcMethodCall.cs b/OpenSubtitlesHandler/XML-RPC/Types/XmlRpcMethodCall.cs deleted file mode 100644 index 7cc1a164f6..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Types/XmlRpcMethodCall.cs +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace XmlRpcHandler -{ - /// - /// A method call - /// - public struct XmlRpcMethodCall - { - /// - /// A method call - /// - /// The name of this method - public XmlRpcMethodCall(string name) - { - this.name = name; - this.parameters = new List(); - } - /// - /// A method call - /// - /// The name of this method - /// A list of parameters - public XmlRpcMethodCall(string name, List parameters) - { - this.name = name; - this.parameters = parameters; - } - - private string name; - private List parameters; - - /// - /// Get or set the name of this method - /// - public string Name - { get { return name; } set { name = value; } } - /// - /// Get or set the parameters to be sent - /// - public List Parameters - { get { return parameters; } set { parameters = value; } } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Values/IXmlRpcValue.cs b/OpenSubtitlesHandler/XML-RPC/Values/IXmlRpcValue.cs deleted file mode 100644 index c918790cba..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Values/IXmlRpcValue.cs +++ /dev/null @@ -1,36 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace XmlRpcHandler -{ - public abstract class IXmlRpcValue - { - public IXmlRpcValue() - { } - public IXmlRpcValue(object data) - { - this.data = data; - } - private object data; - /// - /// Get or set the data of this value - /// - public virtual object Data { get { return data; } set { data = value; } } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcStructMember.cs b/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcStructMember.cs deleted file mode 100644 index 2aad7ebffe..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcStructMember.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -namespace XmlRpcHandler -{ - public class XmlRpcStructMember - { - public XmlRpcStructMember(string name, IXmlRpcValue data) - { - this.name = name; - this.data = data; - } - private string name; - private IXmlRpcValue data; - - /// - /// Get or set the name of this member - /// - public string Name - { get { return name; } set { name = value; } } - /// - /// Get or set the data of this member - /// - public IXmlRpcValue Data - { get { return data; } set { data = value; } } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueArray.cs b/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueArray.cs deleted file mode 100644 index d10a80175b..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueArray.cs +++ /dev/null @@ -1,121 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; -using System.Collections.Generic; - -namespace XmlRpcHandler -{ - public class XmlRpcValueArray : IXmlRpcValue - { - public XmlRpcValueArray() : - base() - { - values = new List(); - } - public XmlRpcValueArray(object data) : - base(data) - { - values = new List(); - } - public XmlRpcValueArray(string[] texts) : - base() - { - values = new List(); - foreach (string val in texts) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(int[] ints) : - base() - { - values = new List(); - foreach (int val in ints) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(double[] doubles) : - base() - { - values = new List(); - foreach (double val in doubles) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(bool[] bools) : - base() - { - values = new List(); - foreach (bool val in bools) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(long[] base24s) : - base() - { - values = new List(); - foreach (long val in base24s) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(DateTime[] dates) : - base() - { - values = new List(); - foreach (var val in dates) - { - values.Add(new XmlRpcValueBasic(val)); - } - } - public XmlRpcValueArray(XmlRpcValueBasic[] basicValues) : - base() - { - values = new List(); - foreach (var val in basicValues) - { - values.Add(val); - } - } - public XmlRpcValueArray(XmlRpcValueStruct[] structs) : - base() - { - values = new List(); - foreach (var val in structs) - { - values.Add(val); - } - } - public XmlRpcValueArray(XmlRpcValueArray[] arrays) : - base() - { - values = new List(); - foreach (var val in arrays) - { - values.Add(val); - } - } - private List values; - - public List Values { get { return values; } set { values = value; } } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueBasic.cs b/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueBasic.cs deleted file mode 100644 index f2811b9889..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueBasic.cs +++ /dev/null @@ -1,99 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; - -namespace XmlRpcHandler -{ - public class XmlRpcValueBasic : IXmlRpcValue - { - public XmlRpcValueBasic() - : base() - { } - public XmlRpcValueBasic(string data) - : base(data) - { this.type = XmlRpcBasicValueType.String; } - public XmlRpcValueBasic(int data) - : base(data) - { this.type = XmlRpcBasicValueType.Int; } - public XmlRpcValueBasic(double data) - : base(data) - { this.type = XmlRpcBasicValueType.Double; } - public XmlRpcValueBasic(DateTime data) - : base(data) - { this.type = XmlRpcBasicValueType.dateTime_iso8601; } - public XmlRpcValueBasic(bool data) - : base(data) - { this.type = XmlRpcBasicValueType.Boolean; } - public XmlRpcValueBasic(long data) - : base(data) - { this.type = XmlRpcBasicValueType.base64; } - public XmlRpcValueBasic(object data, XmlRpcBasicValueType type) - : base(data) - { this.type = type; } - - private XmlRpcBasicValueType type = XmlRpcBasicValueType.String; - /// - /// Get or set the type of this basic value - /// - public XmlRpcBasicValueType ValueType { get { return type; } set { type = value; } } - /*Oprators. help a lot.*/ - public static implicit operator string(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return f.Data.ToString(); - else - throw new Exception("Unable to convert, this value is not string type."); - } - public static implicit operator int(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return (int)f.Data; - else - throw new Exception("Unable to convert, this value is not int type."); - } - public static implicit operator double(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return (double)f.Data; - else - throw new Exception("Unable to convert, this value is not double type."); - } - public static implicit operator bool(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return (bool)f.Data; - else - throw new Exception("Unable to convert, this value is not bool type."); - } - public static implicit operator long(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return (long)f.Data; - else - throw new Exception("Unable to convert, this value is not long type."); - } - public static implicit operator DateTime(XmlRpcValueBasic f) - { - if (f.type == XmlRpcBasicValueType.String) - return (DateTime)f.Data; - else - throw new Exception("Unable to convert, this value is not DateTime type."); - } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueStruct.cs b/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueStruct.cs deleted file mode 100644 index 4863e38e84..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/Values/XmlRpcValueStruct.cs +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -using System.Collections.Generic; - -namespace XmlRpcHandler -{ - /// - /// Represents XML-RPC struct - /// - public class XmlRpcValueStruct : IXmlRpcValue - { - /// - /// Represents XML-RPC struct - /// - /// - public XmlRpcValueStruct(List members) - { this.members = members; } - - private List members; - /// - /// Get or set the members collection - /// - public List Members - { get { return members; } set { members = value; } } - } -} diff --git a/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs b/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs deleted file mode 100644 index a79a278fa1..0000000000 --- a/OpenSubtitlesHandler/XML-RPC/XmlRpcGenerator.cs +++ /dev/null @@ -1,350 +0,0 @@ -/* This file is part of OpenSubtitles Handler - A library that handle OpenSubtitles.org XML-RPC methods. - - Copyright © Ala Ibrahim Hadid 2013 - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Text; -using System.Xml; -using OpenSubtitlesHandler; - -namespace XmlRpcHandler -{ - /// - /// A class for making XML-RPC requests. The requests then can be sent directly as http request. - /// - public class XmlRpcGenerator - { - /// - /// Generate XML-RPC request using method call. - /// - /// The method call - /// The request in xml. - public static byte[] Generate(XmlRpcMethodCall method) - { return Generate(new XmlRpcMethodCall[] { method }); } - /// - /// Generate XML-RPC request using method calls array. - /// - /// The method calls array - /// The request in utf8 xml string as buffer - public static byte[] Generate(XmlRpcMethodCall[] methods) - { - if (methods == null) - throw new Exception("No method to write !"); - if (methods.Length == 0) - throw new Exception("No method to write !"); - // Create xml - var sett = new XmlWriterSettings(); - sett.Indent = true; - - sett.Encoding = Encoding.UTF8; - - using (var ms = new MemoryStream()) - { - using (var XMLwrt = XmlWriter.Create(ms, sett)) - { - // Let's write the methods - foreach (XmlRpcMethodCall method in methods) - { - XMLwrt.WriteStartElement("methodCall");//methodCall - XMLwrt.WriteStartElement("methodName");//methodName - XMLwrt.WriteString(method.Name); - XMLwrt.WriteEndElement();//methodName - XMLwrt.WriteStartElement("params");//params - // Write values - foreach (IXmlRpcValue p in method.Parameters) - { - XMLwrt.WriteStartElement("param");//param - if (p is XmlRpcValueBasic) - { - WriteBasicValue(XMLwrt, (XmlRpcValueBasic)p); - } - else if (p is XmlRpcValueStruct) - { - WriteStructValue(XMLwrt, (XmlRpcValueStruct)p); - } - else if (p is XmlRpcValueArray) - { - WriteArrayValue(XMLwrt, (XmlRpcValueArray)p); - } - XMLwrt.WriteEndElement();//param - } - - XMLwrt.WriteEndElement();//params - XMLwrt.WriteEndElement();//methodCall - } - XMLwrt.Flush(); - return ms.ToArray(); - } - } - } - /// - /// Decode response then return the values - /// - /// The response xml string as provided by server as methodResponse - /// - public static XmlRpcMethodCall[] DecodeMethodResponse(string xmlResponse) - { - var methods = new List(); - var sett = new XmlReaderSettings(); - sett.DtdProcessing = DtdProcessing.Ignore; - sett.IgnoreWhitespace = true; - MemoryStream str; - if (xmlResponse.Contains(@"encoding=""utf-8""")) - { - str = new MemoryStream(Encoding.UTF8.GetBytes(xmlResponse)); - } - else - { - str = new MemoryStream(Utilities.GetASCIIBytes(xmlResponse)); - } - using (str) - { - using (var XMLread = XmlReader.Create(str, sett)) - { - var call = new XmlRpcMethodCall("methodResponse"); - // Read parameters - while (XMLread.Read()) - { - if (XMLread.Name == "param" && XMLread.IsStartElement()) - { - IXmlRpcValue val = ReadValue(XMLread); - if (val != null) - call.Parameters.Add(val); - } - } - methods.Add(call); - return methods.ToArray(); - } - } - } - - private static void WriteBasicValue(XmlWriter XMLwrt, XmlRpcValueBasic val) - { - XMLwrt.WriteStartElement("value");//value - switch (val.ValueType) - { - case XmlRpcBasicValueType.String: - XMLwrt.WriteStartElement("string"); - if (val.Data != null) - XMLwrt.WriteString(val.Data.ToString()); - XMLwrt.WriteEndElement(); - break; - case XmlRpcBasicValueType.Int: - XMLwrt.WriteStartElement("int"); - if (val.Data != null) - XMLwrt.WriteString(val.Data.ToString()); - XMLwrt.WriteEndElement(); - break; - case XmlRpcBasicValueType.Boolean: - XMLwrt.WriteStartElement("boolean"); - if (val.Data != null) - XMLwrt.WriteString(((bool)val.Data) ? "1" : "0"); - XMLwrt.WriteEndElement(); - break; - case XmlRpcBasicValueType.Double: - XMLwrt.WriteStartElement("double"); - if (val.Data != null) - XMLwrt.WriteString(val.Data.ToString()); - XMLwrt.WriteEndElement(); - break; - case XmlRpcBasicValueType.dateTime_iso8601: - XMLwrt.WriteStartElement("dateTime.iso8601"); - // Get date time format - if (val.Data != null) - { - var time = (DateTime)val.Data; - string dt = time.Year + time.Month.ToString("D2") + time.Day.ToString("D2") + - "T" + time.Hour.ToString("D2") + ":" + time.Minute.ToString("D2") + ":" + - time.Second.ToString("D2"); - XMLwrt.WriteString(dt); - } - XMLwrt.WriteEndElement(); - break; - case XmlRpcBasicValueType.base64: - XMLwrt.WriteStartElement("base64"); - if (val.Data != null) - XMLwrt.WriteString(Convert.ToBase64String(BitConverter.GetBytes((long)val.Data))); - XMLwrt.WriteEndElement(); - break; - } - XMLwrt.WriteEndElement();//value - } - private static void WriteStructValue(XmlWriter XMLwrt, XmlRpcValueStruct val) - { - XMLwrt.WriteStartElement("value");//value - XMLwrt.WriteStartElement("struct");//struct - foreach (XmlRpcStructMember member in val.Members) - { - XMLwrt.WriteStartElement("member");//member - - XMLwrt.WriteStartElement("name");//name - XMLwrt.WriteString(member.Name); - XMLwrt.WriteEndElement();//name - - if (member.Data is XmlRpcValueBasic) - { - WriteBasicValue(XMLwrt, (XmlRpcValueBasic)member.Data); - } - else if (member.Data is XmlRpcValueStruct) - { - WriteStructValue(XMLwrt, (XmlRpcValueStruct)member.Data); - } - else if (member.Data is XmlRpcValueArray) - { - WriteArrayValue(XMLwrt, (XmlRpcValueArray)member.Data); - } - - XMLwrt.WriteEndElement();//member - } - XMLwrt.WriteEndElement();//struct - XMLwrt.WriteEndElement();//value - } - private static void WriteArrayValue(XmlWriter XMLwrt, XmlRpcValueArray val) - { - XMLwrt.WriteStartElement("value");//value - XMLwrt.WriteStartElement("array");//array - XMLwrt.WriteStartElement("data");//data - foreach (IXmlRpcValue o in val.Values) - { - if (o is XmlRpcValueBasic) - { - WriteBasicValue(XMLwrt, (XmlRpcValueBasic)o); - } - else if (o is XmlRpcValueStruct) - { - WriteStructValue(XMLwrt, (XmlRpcValueStruct)o); - } - else if (o is XmlRpcValueArray) - { - WriteArrayValue(XMLwrt, (XmlRpcValueArray)o); - } - } - XMLwrt.WriteEndElement();//data - XMLwrt.WriteEndElement();//array - XMLwrt.WriteEndElement();//value - } - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - private static string ReadString(XmlReader reader) - { - if (reader.NodeType == XmlNodeType.Element) - { - return reader.ReadElementContentAsString(); - } - return reader.ReadContentAsString(); - } - - private static IXmlRpcValue ReadValue(XmlReader xmlReader, bool skipRead = false) - { - while (skipRead || xmlReader.Read()) - { - if (xmlReader.Name == "value" && xmlReader.IsStartElement()) - { - xmlReader.Read(); - if (xmlReader.Name == "string" && xmlReader.IsStartElement()) - { - return new XmlRpcValueBasic(ReadString(xmlReader), XmlRpcBasicValueType.String); - } - else if (xmlReader.Name == "int" && xmlReader.IsStartElement()) - { - return new XmlRpcValueBasic(int.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Int); - } - else if (xmlReader.Name == "boolean" && xmlReader.IsStartElement()) - { - return new XmlRpcValueBasic(ReadString(xmlReader) == "1", XmlRpcBasicValueType.Boolean); - } - else if (xmlReader.Name == "double" && xmlReader.IsStartElement()) - { - return new XmlRpcValueBasic(double.Parse(ReadString(xmlReader), UsCulture), XmlRpcBasicValueType.Double); - } - else if (xmlReader.Name == "dateTime.iso8601" && xmlReader.IsStartElement()) - { - string date = ReadString(xmlReader); - int year = int.Parse(date.Substring(0, 4), UsCulture); - int month = int.Parse(date.Substring(4, 2), UsCulture); - int day = int.Parse(date.Substring(6, 2), UsCulture); - int hour = int.Parse(date.Substring(9, 2), UsCulture); - int minute = int.Parse(date.Substring(12, 2), UsCulture);//19980717T14:08:55 - int sec = int.Parse(date.Substring(15, 2), UsCulture); - var time = new DateTime(year, month, day, hour, minute, sec); - return new XmlRpcValueBasic(time, XmlRpcBasicValueType.dateTime_iso8601); - } - else if (xmlReader.Name == "base64" && xmlReader.IsStartElement()) - { - return new XmlRpcValueBasic(BitConverter.ToInt64(Convert.FromBase64String(ReadString(xmlReader)), 0) - , XmlRpcBasicValueType.Double); - } - else if (xmlReader.Name == "struct" && xmlReader.IsStartElement()) - { - var strct = new XmlRpcValueStruct(new List()); - // Read members... - while (xmlReader.Read()) - { - if (xmlReader.Name == "member" && xmlReader.IsStartElement()) - { - var member = new XmlRpcStructMember("", null); - xmlReader.Read();// read name - member.Name = ReadString(xmlReader); - - IXmlRpcValue val = ReadValue(xmlReader, true); - if (val != null) - { - member.Data = val; - strct.Members.Add(member); - } - } - else if (xmlReader.Name == "struct" && !xmlReader.IsStartElement()) - { - return strct; - } - } - return strct; - } - else if (xmlReader.Name == "array" && xmlReader.IsStartElement()) - { - var array = new XmlRpcValueArray(); - // Read members... - while (xmlReader.Read()) - { - if (xmlReader.Name == "array" && !xmlReader.IsStartElement()) - { - return array; - } - else - { - IXmlRpcValue val = ReadValue(xmlReader); - if (val != null) - array.Values.Add(val); - } - } - return array; - } - } - else break; - - if (skipRead) - { - return null; - } - } - return null; - } - } -} From 3c4043199accbfe7995dd6060c89fc837300884a Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Tue, 12 Mar 2019 09:18:45 -0400 Subject: [PATCH 33/48] Implement review feedback --- Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs | 4 ++-- Emby.Server.Implementations/ApplicationHost.cs | 2 +- Jellyfin.Server/Program.cs | 2 +- Jellyfin.Server/StartupOptions.cs | 2 +- MediaBrowser.Common/Configuration/IApplicationPaths.cs | 4 ++-- MediaBrowser.Model/System/SystemInfo.cs | 4 ++-- MediaBrowser.WebDashboard/Api/DashboardService.cs | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs index fd9ce3a364..00cfa0c9a9 100644 --- a/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs +++ b/Emby.Server.Implementations/AppBase/BaseApplicationPaths.cs @@ -36,9 +36,9 @@ namespace Emby.Server.Implementations.AppBase public string ProgramDataPath { get; private set; } /// - /// Gets the path to the web resources folder + /// Gets the path to the web UI resources folder /// - /// The web resources path. + /// The web UI resources path. public string WebPath { get; set; } /// diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index f240ef871a..14c700cc5d 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -621,7 +621,7 @@ namespace Emby.Server.Implementations string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath; if (string.IsNullOrEmpty(contentRoot)) { - contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths.WebPath, "src"); + contentRoot = ServerConfigurationManager.ApplicationPaths.WebPath; } var host = new WebHostBuilder() diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 8f1498b13b..7534a6398f 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -277,7 +277,7 @@ namespace Jellyfin.Server if (string.IsNullOrEmpty(webDir)) { // Use default location under ResourcesPath - webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web"); + webDir = Path.Combine(AppContext.BaseDirectory, "jellyfin-web", "src"); } } diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index 2b01c7bbdf..345a8a731f 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -11,7 +11,7 @@ namespace Jellyfin.Server [Option('d', "datadir", Required = false, HelpText = "Path to use for the data folder (database files, etc.).")] public string DataDir { get; set; } - [Option('w', "webdir", Required = false, HelpText = "Path to the Jellyfin web resources.")] + [Option('w', "webdir", Required = false, HelpText = "Path to the Jellyfin web UI resources.")] public string WebDir { get; set; } [Option('C', "cachedir", Required = false, HelpText = "Path to use for caching.")] diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index 1f56c98fd8..fd11bf904f 100644 --- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -12,9 +12,9 @@ namespace MediaBrowser.Common.Configuration string ProgramDataPath { get; } /// - /// Gets the path to the web resources folder + /// Gets the path to the web UI resources folder /// - /// The web resources path. + /// The web UI resources path. string WebPath { get; } /// diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs index fa72624819..222c10798a 100644 --- a/MediaBrowser.Model/System/SystemInfo.cs +++ b/MediaBrowser.Model/System/SystemInfo.cs @@ -84,9 +84,9 @@ namespace MediaBrowser.Model.System public string ProgramDataPath { get; set; } /// - /// Gets or sets the web resources path. + /// Gets or sets the web UI resources path. /// - /// The web resources path. + /// The web UI resources path. public string WebPath { get; set; } /// diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index 05df54b115..01cbe2c314 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -149,7 +149,7 @@ namespace MediaBrowser.WebDashboard.Api return _serverConfigurationManager.Configuration.DashboardSourcePath; } - return Path.Combine(_serverConfigurationManager.ApplicationPaths.WebPath, "src"); + return _serverConfigurationManager.ApplicationPaths.WebPath; } } From afdef163ea53db1aa740cf4051322ff2fe190022 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 12 Mar 2019 20:49:29 +0100 Subject: [PATCH 34/48] Fix build by removing non existent namespace Looks like a wrong auto merge. (We really should fix CI) --- MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 3eb32fe16b..aee9921034 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -15,7 +15,6 @@ using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Providers; using MediaBrowser.Model.Serialization; -using MediaBrowser.Model.Xml; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; From b864e9da2a512250eff48baae28251db5a508f8f Mon Sep 17 00:00:00 2001 From: PloughPuff Date: Tue, 12 Mar 2019 22:09:18 +0000 Subject: [PATCH 35/48] Finalise removal of --ffprobe switch Removed --ffprobe from src files and server/docker scripts. --- Dockerfile | 3 +-- Dockerfile.arm | 3 +-- Dockerfile.arm64 | 3 +-- Emby.Server.Implementations/ApplicationHost.cs | 1 - Emby.Server.Implementations/IStartupOptions.cs | 5 ----- Jellyfin.Server/StartupOptions.cs | 3 --- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 9 --------- deployment/debian-package-x64/pkg-src/conf/jellyfin | 3 +-- deployment/debian-package-x64/pkg-src/jellyfin.service | 2 +- deployment/fedora-package-x64/pkg-src/jellyfin.env | 1 - deployment/fedora-package-x64/pkg-src/jellyfin.service | 2 +- 11 files changed, 6 insertions(+), 29 deletions(-) diff --git a/Dockerfile b/Dockerfile index 91a4f5a2d2..72c0cdbf3a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,5 +31,4 @@ VOLUME /cache /config /media ENTRYPOINT dotnet /jellyfin/jellyfin.dll \ --datadir /config \ --cachedir /cache \ - --ffmpeg /usr/local/bin/ffmpeg \ - --ffprobe /usr/local/bin/ffprobe + --ffmpeg /usr/local/bin/ffmpeg diff --git a/Dockerfile.arm b/Dockerfile.arm index 42f0354a32..238e90ccd8 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -39,5 +39,4 @@ VOLUME /cache /config /media ENTRYPOINT dotnet /jellyfin/jellyfin.dll \ --datadir /config \ --cachedir /cache \ - --ffmpeg /usr/bin/ffmpeg \ - --ffprobe /usr/bin/ffprobe + --ffmpeg /usr/bin/ffmpeg diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index d3103d3893..2927d4e658 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -40,5 +40,4 @@ VOLUME /cache /config /media ENTRYPOINT dotnet /jellyfin/jellyfin.dll \ --datadir /config \ --cachedir /cache \ - --ffmpeg /usr/bin/ffmpeg \ - --ffprobe /usr/bin/ffprobe + --ffmpeg /usr/bin/ffmpeg diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 98f6ab6bc7..1810064e69 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -837,7 +837,6 @@ namespace Emby.Server.Implementations LoggerFactory, JsonSerializer, StartupOptions.FFmpegPath, - StartupOptions.FFprobePath, ServerConfigurationManager, FileSystemManager, () => SubtitleEncoder, diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs index 24aaa76c02..6e915de3d1 100644 --- a/Emby.Server.Implementations/IStartupOptions.cs +++ b/Emby.Server.Implementations/IStartupOptions.cs @@ -7,11 +7,6 @@ namespace Emby.Server.Implementations /// string FFmpegPath { get; } - /// - /// --ffprobe - /// - string FFprobePath { get; } - /// /// --service /// diff --git a/Jellyfin.Server/StartupOptions.cs b/Jellyfin.Server/StartupOptions.cs index 345a8a731f..8296d414ef 100644 --- a/Jellyfin.Server/StartupOptions.cs +++ b/Jellyfin.Server/StartupOptions.cs @@ -26,9 +26,6 @@ namespace Jellyfin.Server [Option("ffmpeg", Required = false, HelpText = "Path to external FFmpeg executable to use in place of default found in PATH.")] public string FFmpegPath { get; set; } - [Option("ffprobe", Required = false, HelpText = "(deprecated) Option has no effect and shall be removed in next release.")] - public string FFprobePath { get; set; } - [Option("service", Required = false, HelpText = "Run as headless service.")] public bool IsService { get; set; } diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 94beda3dbb..f454c27235 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -51,7 +51,6 @@ namespace MediaBrowser.MediaEncoding.Encoder private readonly IProcessFactory _processFactory; private readonly int DefaultImageExtractionTimeoutMs; private readonly string StartupOptionFFmpegPath; - private readonly string StartupOptionFFprobePath; private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1); private readonly List _runningProcesses = new List(); @@ -60,7 +59,6 @@ namespace MediaBrowser.MediaEncoding.Encoder ILoggerFactory loggerFactory, IJsonSerializer jsonSerializer, string startupOptionsFFmpegPath, - string startupOptionsFFprobePath, IServerConfigurationManager configurationManager, IFileSystem fileSystem, Func subtitleEncoder, @@ -71,7 +69,6 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger = loggerFactory.CreateLogger(nameof(MediaEncoder)); _jsonSerializer = jsonSerializer; StartupOptionFFmpegPath = startupOptionsFFmpegPath; - StartupOptionFFprobePath = startupOptionsFFprobePath; ConfigurationManager = configurationManager; FileSystem = fileSystem; SubtitleEncoder = subtitleEncoder; @@ -86,12 +83,6 @@ namespace MediaBrowser.MediaEncoding.Encoder /// public void SetFFmpegPath() { - // ToDo - Finalise removal of the --ffprobe switch - if (!string.IsNullOrEmpty(StartupOptionFFprobePath)) - { - _logger.LogWarning("--ffprobe switch is deprecated and shall be removed in the next release"); - } - // 1) Custom path stored in config/encoding xml file under tag takes precedence if (!ValidatePath(ConfigurationManager.GetConfiguration("encoding").EncoderAppPath, FFmpegLocation.Custom)) { diff --git a/deployment/debian-package-x64/pkg-src/conf/jellyfin b/deployment/debian-package-x64/pkg-src/conf/jellyfin index 7db482d428..bc00c37e20 100644 --- a/deployment/debian-package-x64/pkg-src/conf/jellyfin +++ b/deployment/debian-package-x64/pkg-src/conf/jellyfin @@ -23,7 +23,6 @@ JELLYFIN_RESTART_OPT="--restartpath=/usr/lib/jellyfin/restart.sh" # ffmpeg binary paths, overriding the system values JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/share/jellyfin-ffmpeg/ffmpeg" -JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/share/jellyfin-ffmpeg/ffprobe" # [OPTIONAL] run Jellyfin as a headless service #JELLYFIN_SERVICE_OPT="--service" @@ -38,4 +37,4 @@ JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/share/jellyfin-ffmpeg/ffprobe" # Application username JELLYFIN_USER="jellyfin" # Full application command -JELLYFIN_ARGS="$JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_FFPROBE_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT" +JELLYFIN_ARGS="$JELLYFIN_RESTART_OPT $JELLYFIN_FFMPEG_OPT $JELLYFIN_SERVICE_OPT $JELLFIN_NOWEBAPP_OPT" diff --git a/deployment/debian-package-x64/pkg-src/jellyfin.service b/deployment/debian-package-x64/pkg-src/jellyfin.service index b4da3a945b..1305e238b0 100644 --- a/deployment/debian-package-x64/pkg-src/jellyfin.service +++ b/deployment/debian-package-x64/pkg-src/jellyfin.service @@ -6,7 +6,7 @@ After = network.target Type = simple EnvironmentFile = /etc/default/jellyfin User = jellyfin -ExecStart = /usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} +ExecStart = /usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} Restart = on-failure TimeoutSec = 15 diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.env b/deployment/fedora-package-x64/pkg-src/jellyfin.env index 143a317c43..de48f13af5 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.env +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.env @@ -25,7 +25,6 @@ JELLYFIN_RESTART_OPT="--restartpath=/usr/libexec/jellyfin/restart.sh" # [OPTIONAL] ffmpeg binary paths, overriding the UI-configured values #JELLYFIN_FFMPEG_OPT="--ffmpeg=/usr/bin/ffmpeg" -#JELLYFIN_FFPROBE_OPT="--ffprobe=/usr/bin/ffprobe" # [OPTIONAL] run Jellyfin as a headless service #JELLYFIN_SERVICE_OPT="--service" diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.service b/deployment/fedora-package-x64/pkg-src/jellyfin.service index 1f83d3d386..f3dc594b1c 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.service +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.service @@ -5,7 +5,7 @@ Description=Jellyfin is a free software media system that puts you in control of [Service] EnvironmentFile=/etc/sysconfig/jellyfin WorkingDirectory=/var/lib/jellyfin -ExecStart=/usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_FFPROBE_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} +ExecStart=/usr/bin/jellyfin ${JELLYFIN_RESTART_OPT} ${JELLYFIN_FFMPEG_OPT} ${JELLYFIN_SERVICE_OPT} ${JELLYFIN_NOWEBAPP_OPT} TimeoutSec=15 Restart=on-failure User=jellyfin From 4cc4d57a782441f02f8901af29634ffbfd4a2fc2 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Wed, 13 Mar 2019 20:37:08 +0100 Subject: [PATCH 36/48] Disable the Drone CI ABI check --- .drone.yml | 81 ------------------------------------------------------ 1 file changed, 81 deletions(-) diff --git a/.drone.yml b/.drone.yml index 7705f4f936..87c8e414e9 100644 --- a/.drone.yml +++ b/.drone.yml @@ -28,84 +28,3 @@ steps: commands: - dotnet publish "Jellyfin.Server" --configuration Release --output "../ci/ci-release" ---- - -kind: pipeline -name: check-abi - -steps: -- name: submodules - image: docker:git - commands: - - git submodule update --init --recursive - -- name: build - image: microsoft/dotnet:2-sdk - commands: - - dotnet publish "Jellyfin.Server" --configuration Release --output "../ci/ci-release" - -- name: clone-dotnet-compat - image: docker:git - commands: - - git clone --depth 1 https://github.com/EraYaN/dotnet-compatibility ci/dotnet-compatibility - -- name: build-dotnet-compat - image: microsoft/dotnet:2-sdk - commands: - - dotnet publish "ci/dotnet-compatibility/CompatibilityCheckerCoreCLI" --configuration Release --output "../../ci-tools" - -- name: download-last-nuget-release-common - image: plugins/download - settings: - source: https://www.nuget.org/api/v2/package/Jellyfin.Common - destination: ci/Jellyfin.Common.nupkg - -- name: download-last-nuget-release-model - image: plugins/download - settings: - source: https://www.nuget.org/api/v2/package/Jellyfin.Model - destination: ci/Jellyfin.Model.nupkg - -- name: download-last-nuget-release-controller - image: plugins/download - settings: - source: https://www.nuget.org/api/v2/package/Jellyfin.Controller - destination: ci/Jellyfin.Controller.nupkg - -- name: download-last-nuget-release-naming - image: plugins/download - settings: - source: https://www.nuget.org/api/v2/package/Jellyfin.Naming - destination: ci/Jellyfin.Naming.nupkg - -- name: extract-downloaded-nuget-packages - image: garthk/unzip - commands: - - unzip -j ci/Jellyfin.Common.nupkg "*.dll" -d ci/nuget-packages - - unzip -j ci/Jellyfin.Model.nupkg "*.dll" -d ci/nuget-packages - - unzip -j ci/Jellyfin.Controller.nupkg "*.dll" -d ci/nuget-packages - - unzip -j ci/Jellyfin.Naming.nupkg "*.dll" -d ci/nuget-packages - -- name: run-dotnet-compat-common - image: microsoft/dotnet:2-runtime - err_ignore: true - commands: - - dotnet ci/ci-tools/CompatibilityCheckerCoreCLI.dll ci/nuget-packages/MediaBrowser.Common.dll ci/ci-release/MediaBrowser.Common.dll - -- name: run-dotnet-compat-model - image: microsoft/dotnet:2-runtime - err_ignore: true - commands: - - dotnet ci/ci-tools/CompatibilityCheckerCoreCLI.dll ci/nuget-packages/MediaBrowser.Model.dll ci/ci-release/MediaBrowser.Model.dll - -- name: run-dotnet-compat-controller - image: microsoft/dotnet:2-runtime - err_ignore: true - commands: - - dotnet ci/ci-tools/CompatibilityCheckerCoreCLI.dll ci/nuget-packages/MediaBrowser.Controller.dll ci/ci-release/MediaBrowser.Controller.dll - -- name: run-dotnet-compat-naming - image: microsoft/dotnet:2-runtime - err_ignore: true - commands: - - dotnet ci/ci-tools/CompatibilityCheckerCoreCLI.dll ci/nuget-packages/Emby.Naming.dll ci/ci-release/Emby.Naming.dll From 1d443d2ff5ef9edaf7040633ec737d043afeafa6 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Wed, 13 Mar 2019 21:09:08 +0100 Subject: [PATCH 37/48] Do not use the nuget packages for comparison, but the last master build (#1091) * Do not use the nuget packages for comparison, but the last master build. * Only allow passing builds. --- .ci/azure-pipelines.yml | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 4cd19dc838..7a92d40889 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -11,9 +11,6 @@ pr: trigger: batch: true - branches: - include: - - master jobs: - job: main_build @@ -71,28 +68,28 @@ jobs: - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact Naming' - condition: eq(variables['BuildConfiguration'], 'Release') + condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded()) inputs: PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/Emby.Naming.dll' artifactName: 'Jellyfin.Naming' - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact Controller' - condition: eq(variables['BuildConfiguration'], 'Release') + condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded()) inputs: PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Controller.dll' artifactName: 'Jellyfin.Controller' - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact Model' - condition: eq(variables['BuildConfiguration'], 'Release') + condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded()) inputs: PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Model.dll' artifactName: 'Jellyfin.Model' - task: PublishBuildArtifacts@1 displayName: 'Publish Artifact Common' - condition: eq(variables['BuildConfiguration'], 'Release') + condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded()) inputs: PathtoPublish: '$(build.artifactstagingdirectory)/Jellyfin.Server/MediaBrowser.Common.dll' artifactName: 'Jellyfin.Common' @@ -102,7 +99,7 @@ jobs: pool: vmImage: ubuntu-16.04 dependsOn: main_build - condition: succeeded() + condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds) strategy: matrix: Naming: @@ -121,16 +118,28 @@ jobs: steps: - checkout: none - - task: NuGetCommand@2 - displayName: 'Download $(NugetPackageName)' + - task: DownloadBuildArtifacts@0 + displayName: Download the Reference Assembly Build Artifact inputs: - command: custom - arguments: 'install $(NugetPackageName) -OutputDirectory $(System.ArtifactsDirectory)/packages -ExcludeVersion -DirectDownload' + buildType: 'specific' # Options: current, specific + project: $(System.TeamProjectId) # Required when buildType == Specific + pipeline: $(System.DefinitionId) # Required when buildType == Specific, not sure if this will take a name too + #specificBuildWithTriggering: false # Optional + buildVersionToDownload: 'latestFromBranch' # Required when buildType == Specific# Options: latest, latestFromBranch, specific + allowPartiallySucceededBuilds: false # Optional + branchName: '$(System.PullRequest.TargetBranch)' # Required when buildType == Specific && BuildVersionToDownload == LatestFromBranch + #buildId: # Required when buildType == Specific && BuildVersionToDownload == Specific + #tags: # Optional + downloadType: 'single' # Options: single, specific + artifactName: '$(NugetPackageName)'# Required when downloadType == Single + #itemPattern: '**' # Optional + downloadPath: '$(System.ArtifactsDirectory)/current-artifacts' + #parallelizationLimit: '8' # Optional - task: CopyFiles@2 displayName: Copy Nuget Assembly to current-release folder inputs: - sourceFolder: $(System.ArtifactsDirectory)/packages/$(NugetPackageName) # Optional + sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional contents: '**/*.dll' targetFolder: $(System.ArtifactsDirectory)/current-release cleanTargetFolder: true # Optional @@ -138,7 +147,7 @@ jobs: flattenFolders: true # Optional - task: DownloadBuildArtifacts@0 - displayName: Download the Assembly Build Artifact + displayName: Download the New Assembly Build Artifact inputs: buildType: 'current' # Options: current, specific allowPartiallySucceededBuilds: false # Optional From e64aaebbacfa7a720c99ca2ab1aa11f7fcd63868 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Mar 2019 17:51:33 +0100 Subject: [PATCH 38/48] Improvements around streams * Use ArrayPool instead of allocating new buffers each time * Remove NetworkStream copy * Remove some dead code --- .../HttpServer/StreamWriter.cs | 1 - .../IO/StreamHelper.cs | 234 +++++++++++------- .../HdHomerun/HdHomerunUdpStream.cs | 3 +- .../LiveTv/TunerHosts/LiveStream.cs | 58 ++--- .../Net/DisposableManagedObjectBase.cs | 66 ----- .../Net/SocketFactory.cs | 134 +++------- Emby.Server.Implementations/Net/UdpSocket.cs | 74 +++--- MediaBrowser.Api/LiveTv/LiveTvService.cs | 32 ++- .../LiveTv/ProgressiveFileCopier.cs | 39 +-- MediaBrowser.Model/Net/HttpResponse.cs | 64 ----- MediaBrowser.Model/Net/IAcceptSocket.cs | 15 -- 11 files changed, 269 insertions(+), 451 deletions(-) delete mode 100644 Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs delete mode 100644 MediaBrowser.Model/Net/HttpResponse.cs delete mode 100644 MediaBrowser.Model/Net/IAcceptSocket.cs diff --git a/Emby.Server.Implementations/HttpServer/StreamWriter.cs b/Emby.Server.Implementations/HttpServer/StreamWriter.cs index 66a13e20df..cf30bbc326 100644 --- a/Emby.Server.Implementations/HttpServer/StreamWriter.cs +++ b/Emby.Server.Implementations/HttpServer/StreamWriter.cs @@ -5,7 +5,6 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Services; -using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; namespace Emby.Server.Implementations.HttpServer diff --git a/Emby.Server.Implementations/IO/StreamHelper.cs b/Emby.Server.Implementations/IO/StreamHelper.cs index 09cf4d4a3e..d02cd84a03 100644 --- a/Emby.Server.Implementations/IO/StreamHelper.cs +++ b/Emby.Server.Implementations/IO/StreamHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -8,168 +9,213 @@ namespace Emby.Server.Implementations.IO { public class StreamHelper : IStreamHelper { + private const int StreamCopyToBufferSize = 81920; + public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, Action onStarted, CancellationToken cancellationToken) { - byte[] buffer = new byte[bufferSize]; - int read; - while ((read = source.Read(buffer, 0, buffer.Length)) != 0) + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - cancellationToken.ThrowIfCancellationRequested(); - - await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false); - - if (onStarted != null) + int read; + while ((read = await source.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) != 0) { - onStarted(); - onStarted = null; + cancellationToken.ThrowIfCancellationRequested(); + + await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false); + + if (onStarted != null) + { + onStarted(); + onStarted = null; + } } } + finally + { + ArrayPool.Shared.Return(buffer); + } } public async Task CopyToAsync(Stream source, Stream destination, int bufferSize, int emptyReadLimit, CancellationToken cancellationToken) { - byte[] buffer = new byte[bufferSize]; - - if (emptyReadLimit <= 0) + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - int read; - while ((read = source.Read(buffer, 0, buffer.Length)) != 0) + if (emptyReadLimit <= 0) + { + int read; + while ((read = await source.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false)) != 0) + { + cancellationToken.ThrowIfCancellationRequested(); + + await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false); + } + + return; + } + + var eofCount = 0; + + while (eofCount < emptyReadLimit) { cancellationToken.ThrowIfCancellationRequested(); - await destination.WriteAsync(buffer, 0, read).ConfigureAwait(false); - } + var bytesRead = await source.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false); - return; + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(50, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + + await destination.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false); + } + } } - - var eofCount = 0; - - while (eofCount < emptyReadLimit) + finally { - cancellationToken.ThrowIfCancellationRequested(); - - var bytesRead = source.Read(buffer, 0, buffer.Length); - - if (bytesRead == 0) - { - eofCount++; - await Task.Delay(50, cancellationToken).ConfigureAwait(false); - } - else - { - eofCount = 0; - - await destination.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false); - } + ArrayPool.Shared.Return(buffer); } } - const int StreamCopyToBufferSize = 81920; public async Task CopyToAsync(Stream source, Stream destination, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - int totalBytesRead = 0; - - while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize); + try { - var bytesToWrite = bytesRead; + int totalBytesRead = 0; - if (bytesToWrite > 0) + int bytesRead; + while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + var bytesToWrite = bytesRead; - totalBytesRead += bytesRead; + if (bytesToWrite > 0) + { + await destination.WriteAsync(buffer, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + + totalBytesRead += bytesRead; + } } - } - return totalBytesRead; + return totalBytesRead; + } + finally + { + ArrayPool.Shared.Return(buffer); + } } public async Task CopyToAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - int totalBytesRead = 0; - - while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize); + try { - var bytesToWrite = bytesRead; + int bytesRead; + int totalBytesRead = 0; - if (bytesToWrite > 0) + while ((bytesRead = source.Read(buffer, 0, buffer.Length)) != 0) { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + var bytesToWrite = bytesRead; - totalBytesRead += bytesRead; + if (bytesToWrite > 0) + { + await destination.WriteAsync(buffer, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + + totalBytesRead += bytesRead; + } } - } - return totalBytesRead; + return totalBytesRead; + } + finally + { + ArrayPool.Shared.Return(buffer); + } } public async Task CopyToAsyncWithSyncRead(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - - while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize); + try { - var bytesToWrite = Math.Min(bytesRead, copyLength); + int bytesRead; - if (bytesToWrite > 0) + while ((bytesRead = source.Read(buffer, 0, buffer.Length)) != 0) { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - } + var bytesToWrite = Math.Min(bytesRead, copyLength); - copyLength -= bytesToWrite; + if (bytesToWrite > 0) + { + await destination.WriteAsync(buffer, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } - if (copyLength <= 0) - { - break; + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } } } + finally + { + ArrayPool.Shared.Return(buffer); + } } public async Task CopyToAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) { - var array = new byte[StreamCopyToBufferSize]; - int bytesRead; - - while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + byte[] buffer = ArrayPool.Shared.Rent(StreamCopyToBufferSize); + try { - var bytesToWrite = Math.Min(bytesRead, copyLength); + int bytesRead; - if (bytesToWrite > 0) + while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) { - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); - } + var bytesToWrite = Math.Min(bytesRead, copyLength); - copyLength -= bytesToWrite; + if (bytesToWrite > 0) + { + await destination.WriteAsync(buffer, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + } - if (copyLength <= 0) - { - break; + copyLength -= bytesToWrite; + + if (copyLength <= 0) + { + break; + } } } + finally + { + ArrayPool.Shared.Return(buffer); + } } public async Task CopyUntilCancelled(Stream source, Stream target, int bufferSize, CancellationToken cancellationToken) { - byte[] buffer = new byte[bufferSize]; - - while (!cancellationToken.IsCancellationRequested) + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try { - var bytesRead = await CopyToAsyncInternal(source, target, buffer, cancellationToken).ConfigureAwait(false); - - //var position = fs.Position; - //_logger.LogDebug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - - if (bytesRead == 0) + while (!cancellationToken.IsCancellationRequested) { - await Task.Delay(100).ConfigureAwait(false); + var bytesRead = await CopyToAsyncInternal(source, target, buffer, cancellationToken).ConfigureAwait(false); + + if (bytesRead == 0) + { + await Task.Delay(100).ConfigureAwait(false); + } } } + finally + { + ArrayPool.Shared.Return(buffer); + } } private static async Task CopyToAsyncInternal(Stream source, Stream destination, byte[] buffer, CancellationToken cancellationToken) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs index 8774371d52..7f426ea31f 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs @@ -151,7 +151,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun }); } - private static int RtpHeaderBytes = 12; + private const int RtpHeaderBytes = 12; + private async Task CopyTo(MediaBrowser.Model.Net.ISocket udpClient, string file, TaskCompletionSource openTaskCompletionSource, CancellationToken cancellationToken) { var bufferSize = 81920; diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs index 1f8ca276e7..ece2cbd547 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs @@ -22,7 +22,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts public string OriginalStreamId { get; set; } public bool EnableStreamSharing { get; set; } - public string UniqueId { get; private set; } + public string UniqueId { get; } protected readonly IFileSystem FileSystem; protected readonly IServerApplicationPaths AppPaths; @@ -31,12 +31,10 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts protected readonly ILogger Logger; protected readonly CancellationTokenSource LiveStreamCancellationTokenSource = new CancellationTokenSource(); - public string TunerHostId { get; private set; } + public string TunerHostId { get; } public DateTime DateOpened { get; protected set; } - public Func OnClose { get; set; } - public LiveStream(MediaSourceInfo mediaSource, TunerHostInfo tuner, IFileSystem fileSystem, ILogger logger, IServerApplicationPaths appPaths) { OriginalMediaSource = mediaSource; @@ -76,26 +74,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts LiveStreamCancellationTokenSource.Cancel(); - if (OnClose != null) - { - return CloseWithExternalFn(); - } - return Task.CompletedTask; } - private async Task CloseWithExternalFn() - { - try - { - await OnClose().ConfigureAwait(false); - } - catch (Exception ex) - { - Logger.LogError(ex, "Error closing live stream"); - } - } - protected Stream GetInputStream(string path, bool allowAsyncFileRead) { var fileOpenOptions = FileOpenOptions.SequentialScan; @@ -113,27 +94,26 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts return DeleteTempFiles(GetStreamFilePaths()); } - protected async Task DeleteTempFiles(List paths, int retryCount = 0) + protected async Task DeleteTempFiles(IEnumerable paths, int retryCount = 0) { if (retryCount == 0) { - Logger.LogInformation("Deleting temp files {0}", string.Join(", ", paths.ToArray())); + Logger.LogInformation("Deleting temp files {0}", paths); } var failedFiles = new List(); foreach (var path in paths) { + if (!File.Exists(path)) + { + continue; + } + try { FileSystem.DeleteFile(path); } - catch (DirectoryNotFoundException) - { - } - catch (FileNotFoundException) - { - } catch (Exception ex) { Logger.LogError(ex, "Error deleting file {path}", path); @@ -157,8 +137,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, LiveStreamCancellationTokenSource.Token).Token; - var allowAsync = false; - // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + // use non-async filestream on windows along with read due to https://github.com/dotnet/corefx/issues/6039 + var allowAsync = Environment.OSVersion.Platform != PlatformID.Win32NT; bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10; @@ -181,28 +161,24 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts Logger.LogInformation("Live Stream ended."); } - private Tuple GetNextFile(string currentFile) + private (string file, bool isLastFile) GetNextFile(string currentFile) { var files = GetStreamFilePaths(); - //logger.LogInformation("Live stream files: {0}", string.Join(", ", files.ToArray())); - if (string.IsNullOrEmpty(currentFile)) { - return new Tuple(files.Last(), true); + return (files.Last(), true); } var nextIndex = files.FindIndex(i => string.Equals(i, currentFile, StringComparison.OrdinalIgnoreCase)) + 1; var isLastFile = nextIndex == files.Count - 1; - return new Tuple(files.ElementAtOrDefault(nextIndex), isLastFile); + return (files.ElementAtOrDefault(nextIndex), isLastFile); } private async Task CopyFile(string path, bool seekFile, int emptyReadLimit, bool allowAsync, Stream stream, CancellationToken cancellationToken) { - //logger.LogInformation("Opening live stream file {0}. Empty read limit: {1}", path, emptyReadLimit); - using (var inputStream = (FileStream)GetInputStream(path, allowAsync)) { if (seekFile) @@ -218,7 +194,11 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts private void TrySeek(FileStream stream, long offset) { - //logger.LogInformation("TrySeek live stream"); + if (!stream.CanSeek) + { + return; + } + try { stream.Seek(offset, SeekOrigin.End); diff --git a/Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs b/Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs deleted file mode 100644 index 304b445651..0000000000 --- a/Emby.Server.Implementations/Net/DisposableManagedObjectBase.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; - -namespace Emby.Server.Implementations.Net -{ - /// - /// Correclty implements the interface and pattern for an object containing only managed resources, and adds a few common niceities not on the interface such as an property. - /// - public abstract class DisposableManagedObjectBase : IDisposable - { - - #region Public Methods - - /// - /// Override this method and dispose any objects you own the lifetime of if disposing is true; - /// - /// True if managed objects should be disposed, if false, only unmanaged resources should be released. - protected abstract void Dispose(bool disposing); - - - //TODO Remove and reimplement using the IsDisposed property directly. - /// - /// Throws an if the property is true. - /// - /// - /// Thrown if the property is true. - /// - protected virtual void ThrowIfDisposed() - { - if (IsDisposed) throw new ObjectDisposedException(GetType().Name); - } - - #endregion - - #region Public Properties - - /// - /// Sets or returns a boolean indicating whether or not this instance has been disposed. - /// - /// - public bool IsDisposed - { - get; - private set; - } - - #endregion - - #region IDisposable Members - - /// - /// Disposes this object instance and all internally managed resources. - /// - /// - /// Sets the property to true. Does not explicitly throw an exception if called multiple times, but makes no promises about behaviour of derived classes. - /// - /// - public void Dispose() - { - IsDisposed = true; - - Dispose(true); - } - - #endregion - } -} diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs index 6beb14f558..492f48abe8 100644 --- a/Emby.Server.Implementations/Net/SocketFactory.cs +++ b/Emby.Server.Implementations/Net/SocketFactory.cs @@ -4,7 +4,6 @@ using System.Net; using System.Net.Sockets; using Emby.Server.Implementations.Networking; using MediaBrowser.Model.Net; -using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Net { @@ -19,7 +18,10 @@ namespace Emby.Server.Implementations.Net public ISocket CreateTcpSocket(IpAddressInfo remoteAddress, int remotePort) { - if (remotePort < 0) throw new ArgumentException("remotePort cannot be less than zero.", nameof(remotePort)); + if (remotePort < 0) + { + throw new ArgumentException("remotePort cannot be less than zero.", nameof(remotePort)); + } var addressFamily = remoteAddress.AddressFamily == IpAddressFamily.InterNetwork ? AddressFamily.InterNetwork @@ -42,8 +44,7 @@ namespace Emby.Server.Implementations.Net } catch { - if (retVal != null) - retVal.Dispose(); + retVal?.Dispose(); throw; } @@ -55,7 +56,10 @@ namespace Emby.Server.Implementations.Net /// An integer specifying the local port to bind the acceptSocket to. public ISocket CreateUdpSocket(int localPort) { - if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + if (localPort < 0) + { + throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + } var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); try @@ -65,8 +69,7 @@ namespace Emby.Server.Implementations.Net } catch { - if (retVal != null) - retVal.Dispose(); + retVal?.Dispose(); throw; } @@ -74,7 +77,10 @@ namespace Emby.Server.Implementations.Net public ISocket CreateUdpBroadcastSocket(int localPort) { - if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + if (localPort < 0) + { + throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + } var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); try @@ -86,8 +92,7 @@ namespace Emby.Server.Implementations.Net } catch { - if (retVal != null) - retVal.Dispose(); + retVal?.Dispose(); throw; } @@ -99,7 +104,10 @@ namespace Emby.Server.Implementations.Net /// An implementation of the interface used by RSSDP components to perform acceptSocket operations. public ISocket CreateSsdpUdpSocket(IpAddressInfo localIpAddress, int localPort) { - if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + if (localPort < 0) + { + throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + } var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); try @@ -114,8 +122,7 @@ namespace Emby.Server.Implementations.Net } catch { - if (retVal != null) - retVal.Dispose(); + retVal?.Dispose(); throw; } @@ -130,10 +137,25 @@ namespace Emby.Server.Implementations.Net /// public ISocket CreateUdpMulticastSocket(string ipAddress, int multicastTimeToLive, int localPort) { - if (ipAddress == null) throw new ArgumentNullException(nameof(ipAddress)); - if (ipAddress.Length == 0) throw new ArgumentException("ipAddress cannot be an empty string.", nameof(ipAddress)); - if (multicastTimeToLive <= 0) throw new ArgumentException("multicastTimeToLive cannot be zero or less.", nameof(multicastTimeToLive)); - if (localPort < 0) throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + if (ipAddress == null) + { + throw new ArgumentNullException(nameof(ipAddress)); + } + + if (ipAddress.Length == 0) + { + throw new ArgumentException("ipAddress cannot be an empty string.", nameof(ipAddress)); + } + + if (multicastTimeToLive <= 0) + { + throw new ArgumentException("multicastTimeToLive cannot be zero or less.", nameof(multicastTimeToLive)); + } + + if (localPort < 0) + { + throw new ArgumentException("localPort cannot be less than zero.", nameof(localPort)); + } var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp); @@ -172,87 +194,13 @@ namespace Emby.Server.Implementations.Net } catch { - if (retVal != null) - retVal.Dispose(); + retVal?.Dispose(); throw; } } public Stream CreateNetworkStream(ISocket socket, bool ownsSocket) - { - var netSocket = (UdpSocket)socket; - - return new SocketStream(netSocket.Socket, ownsSocket); - } + => new NetworkStream(((UdpSocket)socket).Socket, ownsSocket); } - - public class SocketStream : Stream - { - private readonly Socket _socket; - - public SocketStream(Socket socket, bool ownsSocket) - { - _socket = socket; - } - - public override void Flush() - { - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => true; - - public override long Length => throw new NotImplementedException(); - - public override long Position - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - _socket.Send(buffer, offset, count, SocketFlags.None); - } - - public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - return _socket.BeginSend(buffer, offset, count, SocketFlags.None, callback, state); - } - - public override void EndWrite(IAsyncResult asyncResult) - { - _socket.EndSend(asyncResult); - } - - public override void SetLength(long value) - { - throw new NotImplementedException(); - } - - public override long Seek(long offset, SeekOrigin origin) - { - throw new NotImplementedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _socket.Receive(buffer, offset, count, SocketFlags.None); - } - - public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) - { - return _socket.BeginReceive(buffer, offset, count, SocketFlags.None, callback, state); - } - - public override int EndRead(IAsyncResult asyncResult) - { - return _socket.EndReceive(asyncResult); - } - } - } diff --git a/Emby.Server.Implementations/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs index d488554860..6c55085c83 100644 --- a/Emby.Server.Implementations/Net/UdpSocket.cs +++ b/Emby.Server.Implementations/Net/UdpSocket.cs @@ -11,12 +11,15 @@ namespace Emby.Server.Implementations.Net // THIS IS A LINKED FILE - SHARED AMONGST MULTIPLE PLATFORMS // Be careful to check any changes compile and work for all platform projects it is shared in. - public sealed class UdpSocket : DisposableManagedObjectBase, ISocket + public sealed class UdpSocket : ISocket, IDisposable { - private Socket _Socket; - private int _LocalPort; + private Socket _socket; + private int _localPort; + private bool _disposed = false; - public Socket Socket => _Socket; + public Socket Socket => _socket; + + public IpAddressInfo LocalIPAddress { get; } private readonly SocketAsyncEventArgs _receiveSocketAsyncEventArgs = new SocketAsyncEventArgs() { @@ -35,11 +38,11 @@ namespace Emby.Server.Implementations.Net { if (socket == null) throw new ArgumentNullException(nameof(socket)); - _Socket = socket; - _LocalPort = localPort; + _socket = socket; + _localPort = localPort; LocalIPAddress = NetworkManager.ToIpAddressInfo(ip); - _Socket.Bind(new IPEndPoint(ip, _LocalPort)); + _socket.Bind(new IPEndPoint(ip, _localPort)); InitReceiveSocketAsyncEventArgs(); } @@ -101,32 +104,26 @@ namespace Emby.Server.Implementations.Net { if (socket == null) throw new ArgumentNullException(nameof(socket)); - _Socket = socket; - _Socket.Connect(NetworkManager.ToIPEndPoint(endPoint)); + _socket = socket; + _socket.Connect(NetworkManager.ToIPEndPoint(endPoint)); InitReceiveSocketAsyncEventArgs(); } - public IpAddressInfo LocalIPAddress - { - get; - private set; - } - public IAsyncResult BeginReceive(byte[] buffer, int offset, int count, AsyncCallback callback) { ThrowIfDisposed(); EndPoint receivedFromEndPoint = new IPEndPoint(IPAddress.Any, 0); - return _Socket.BeginReceiveFrom(buffer, offset, count, SocketFlags.None, ref receivedFromEndPoint, callback, buffer); + return _socket.BeginReceiveFrom(buffer, offset, count, SocketFlags.None, ref receivedFromEndPoint, callback, buffer); } public int Receive(byte[] buffer, int offset, int count) { ThrowIfDisposed(); - return _Socket.Receive(buffer, 0, buffer.Length, SocketFlags.None); + return _socket.Receive(buffer, 0, buffer.Length, SocketFlags.None); } public SocketReceiveResult EndReceive(IAsyncResult result) @@ -136,7 +133,7 @@ namespace Emby.Server.Implementations.Net var sender = new IPEndPoint(IPAddress.Any, 0); var remoteEndPoint = (EndPoint)sender; - var receivedBytes = _Socket.EndReceiveFrom(result, ref remoteEndPoint); + var receivedBytes = _socket.EndReceiveFrom(result, ref remoteEndPoint); var buffer = (byte[])result.AsyncState; @@ -236,37 +233,42 @@ namespace Emby.Server.Implementations.Net var ipEndPoint = NetworkManager.ToIPEndPoint(endPoint); - return _Socket.BeginSendTo(buffer, offset, size, SocketFlags.None, ipEndPoint, callback, state); + return _socket.BeginSendTo(buffer, offset, size, SocketFlags.None, ipEndPoint, callback, state); } public int EndSendTo(IAsyncResult result) { ThrowIfDisposed(); - return _Socket.EndSendTo(result); + return _socket.EndSendTo(result); } - protected override void Dispose(bool disposing) + private void ThrowIfDisposed() { - if (disposing) + if (_disposed) { - var socket = _Socket; - if (socket != null) - socket.Dispose(); - - var tcs = _currentReceiveTaskCompletionSource; - if (tcs != null) - { - tcs.TrySetCanceled(); - } - var sendTcs = _currentSendTaskCompletionSource; - if (sendTcs != null) - { - sendTcs.TrySetCanceled(); - } + throw new ObjectDisposedException(nameof(UdpSocket)); } } + public void Dispose() + { + if (_disposed) + { + return; + } + + _socket?.Dispose(); + _currentReceiveTaskCompletionSource?.TrySetCanceled(); + _currentSendTaskCompletionSource?.TrySetCanceled(); + + _socket = null; + _currentReceiveTaskCompletionSource = null; + _currentSendTaskCompletionSource = null; + + _disposed = true; + } + private static IpEndPointInfo ToIpEndPointInfo(IPEndPoint endpoint) { if (endpoint == null) diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index 486d5e8a71..e41ad540ad 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -23,7 +23,6 @@ using MediaBrowser.Model.IO; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Querying; using MediaBrowser.Model.Services; -using MediaBrowser.Model.System; using Microsoft.Net.Http.Headers; namespace MediaBrowser.Api.LiveTv @@ -695,27 +694,36 @@ namespace MediaBrowser.Api.LiveTv private readonly IHttpClient _httpClient; private readonly ILibraryManager _libraryManager; private readonly IDtoService _dtoService; - private readonly IFileSystem _fileSystem; private readonly IAuthorizationContext _authContext; private readonly ISessionContext _sessionContext; - private ICryptoProvider _cryptographyProvider; - private IStreamHelper _streamHelper; - private IMediaSourceManager _mediaSourceManager; + private readonly ICryptoProvider _cryptographyProvider; + private readonly IStreamHelper _streamHelper; + private readonly IMediaSourceManager _mediaSourceManager; - public LiveTvService(ICryptoProvider crypto, IMediaSourceManager mediaSourceManager, IStreamHelper streamHelper, ILiveTvManager liveTvManager, IUserManager userManager, IServerConfigurationManager config, IHttpClient httpClient, ILibraryManager libraryManager, IDtoService dtoService, IFileSystem fileSystem, IAuthorizationContext authContext, ISessionContext sessionContext) + public LiveTvService( + ICryptoProvider crypto, + IMediaSourceManager mediaSourceManager, + IStreamHelper streamHelper, + ILiveTvManager liveTvManager, + IUserManager userManager, + IServerConfigurationManager config, + IHttpClient httpClient, + ILibraryManager libraryManager, + IDtoService dtoService, + IAuthorizationContext authContext, + ISessionContext sessionContext) { + _cryptographyProvider = crypto; + _mediaSourceManager = mediaSourceManager; + _streamHelper = streamHelper; _liveTvManager = liveTvManager; _userManager = userManager; _config = config; _httpClient = httpClient; _libraryManager = libraryManager; _dtoService = dtoService; - _fileSystem = fileSystem; _authContext = authContext; _sessionContext = sessionContext; - _cryptographyProvider = crypto; - _streamHelper = streamHelper; - _mediaSourceManager = mediaSourceManager; } public object Get(GetTunerHostTypes request) @@ -729,7 +737,7 @@ namespace MediaBrowser.Api.LiveTv var user = request.UserId.Equals(Guid.Empty) ? null : _userManager.GetUserById(request.UserId); var folders = _liveTvManager.GetRecordingFolders(user); - var returnArray = _dtoService.GetBaseItemDtos(folders.ToArray(), new DtoOptions(), user); + var returnArray = _dtoService.GetBaseItemDtos(folders, new DtoOptions(), user); var result = new QueryResult { @@ -754,7 +762,7 @@ namespace MediaBrowser.Api.LiveTv [HeaderNames.ContentType] = Model.Net.MimeTypes.GetMimeType(path) }; - return new ProgressiveFileCopier(_fileSystem, _streamHelper, path, outputHeaders, Logger) + return new ProgressiveFileCopier(_streamHelper, path, outputHeaders, Logger) { AllowEndOfFile = false }; diff --git a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs index 51552d928b..4c608d9a33 100644 --- a/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs +++ b/MediaBrowser.Api/LiveTv/ProgressiveFileCopier.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Threading; @@ -11,22 +12,17 @@ namespace MediaBrowser.Api.LiveTv { public class ProgressiveFileCopier : IAsyncStreamWriter, IHasHeaders { - private readonly IFileSystem _fileSystem; private readonly ILogger _logger; private readonly string _path; private readonly Dictionary _outputHeaders; - const int StreamCopyToBufferSize = 81920; - - public long StartPosition { get; set; } public bool AllowEndOfFile = true; private readonly IDirectStreamProvider _directStreamProvider; private IStreamHelper _streamHelper; - public ProgressiveFileCopier(IFileSystem fileSystem, IStreamHelper streamHelper, string path, Dictionary outputHeaders, ILogger logger) + public ProgressiveFileCopier(IStreamHelper streamHelper, string path, Dictionary outputHeaders, ILogger logger) { - _fileSystem = fileSystem; _path = path; _outputHeaders = outputHeaders; _logger = logger; @@ -43,18 +39,6 @@ namespace MediaBrowser.Api.LiveTv public IDictionary Headers => _outputHeaders; - private Stream GetInputStream(bool allowAsyncFileRead) - { - var fileOpenOptions = FileOpenOptions.SequentialScan; - - if (allowAsyncFileRead) - { - fileOpenOptions |= FileOpenOptions.Asynchronous; - } - - return _fileSystem.GetFileStream(_path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); - } - public async Task WriteToAsync(Stream outputStream, CancellationToken cancellationToken) { if (_directStreamProvider != null) @@ -63,28 +47,23 @@ namespace MediaBrowser.Api.LiveTv return; } - var eofCount = 0; + var fileOptions = FileOptions.SequentialScan; // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 - var allowAsyncFileRead = true; - - using (var inputStream = GetInputStream(allowAsyncFileRead)) + if (Environment.OSVersion.Platform != PlatformID.Win32NT) { - if (StartPosition > 0) - { - inputStream.Position = StartPosition; - } + fileOptions |= FileOptions.Asynchronous; + } + using (var inputStream = new FileStream(_path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, fileOptions)) + { var emptyReadLimit = AllowEndOfFile ? 20 : 100; - + var eofCount = 0; while (eofCount < emptyReadLimit) { int bytesRead; bytesRead = await _streamHelper.CopyToAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); - //var position = fs.Position; - //_logger.LogDebug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); - if (bytesRead == 0) { eofCount++; diff --git a/MediaBrowser.Model/Net/HttpResponse.cs b/MediaBrowser.Model/Net/HttpResponse.cs deleted file mode 100644 index 286b1c0afd..0000000000 --- a/MediaBrowser.Model/Net/HttpResponse.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Net; - -namespace MediaBrowser.Model.Net -{ - public class HttpResponse : IDisposable - { - /// - /// Gets or sets the type of the content. - /// - /// The type of the content. - public string ContentType { get; set; } - - /// - /// Gets or sets the response URL. - /// - /// The response URL. - public string ResponseUrl { get; set; } - - /// - /// Gets or sets the content. - /// - /// The content. - public Stream Content { get; set; } - - /// - /// Gets or sets the status code. - /// - /// The status code. - public HttpStatusCode StatusCode { get; set; } - - /// - /// Gets or sets the length of the content. - /// - /// The length of the content. - public long? ContentLength { get; set; } - - /// - /// Gets or sets the headers. - /// - /// The headers. - public Dictionary Headers { get; set; } - - private readonly IDisposable _disposable; - - public HttpResponse(IDisposable disposable) - { - _disposable = disposable; - } - public HttpResponse() - { - } - - public void Dispose() - { - if (_disposable != null) - { - _disposable.Dispose(); - } - } - } -} diff --git a/MediaBrowser.Model/Net/IAcceptSocket.cs b/MediaBrowser.Model/Net/IAcceptSocket.cs deleted file mode 100644 index 2b21d3e660..0000000000 --- a/MediaBrowser.Model/Net/IAcceptSocket.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace MediaBrowser.Model.Net -{ - public class SocketCreateException : Exception - { - public SocketCreateException(string errorCode, Exception originalException) - : base(errorCode, originalException) - { - ErrorCode = errorCode; - } - - public string ErrorCode { get; private set; } - } -} From bf43dc00bb193fb4c7aca882aadbe086ed5a1815 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 13 Mar 2019 22:32:52 +0100 Subject: [PATCH 39/48] More warning fixes --- .../ApplicationHost.cs | 207 ++++++------ .../Diagnostics/CommonProcess.cs | 72 ++-- .../Library/LibraryManager.cs | 319 +++++++++--------- .../Localization/LocalizationManager.cs | 37 +- .../Session/SessionManager.cs | 242 +++++++------ .../Sorting/AlbumArtistComparer.cs | 2 +- .../Sorting/SeriesSortNameComparer.cs | 14 +- MediaBrowser.Api/BaseApiService.cs | 35 +- .../UserLibrary/ArtistsService.cs | 10 - .../Manager/ProviderManager.cs | 39 +-- .../Music/MusicBrainzAlbumProvider.cs | 24 +- .../Music/MusicBrainzArtistProvider.cs | 18 +- 12 files changed, 532 insertions(+), 487 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 1810064e69..94eaffa479 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, + 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)) + 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 2c4ef170dc..175a8f3ce4 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 6591d54c56..1673e37776 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(); - foreach (var item in items) + ItemRepository.SaveItems(itemsList, cancellationToken); + + 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 762649b716..8c49b64055 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 03e7b26545..985748caf2 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 + 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); + }, + _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 535f123f90..0804b01fca 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 46e0dd9186..504b6d2838 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 69673a49c1..49f8c6ace0 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) + if (type.Equals("Person", StringComparison.OrdinalIgnoreCase)) { - item = GetPerson(name, libraryManager, dtoOptions); + return GetPerson(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Artist", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Artist", StringComparison.OrdinalIgnoreCase)) { - item = GetArtist(name, libraryManager, dtoOptions); + return GetArtist(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Genre", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Genre", StringComparison.OrdinalIgnoreCase)) { - item = GetGenre(name, libraryManager, dtoOptions); + return GetGenre(name, libraryManager, dtoOptions); } - else if (type.IndexOf("MusicGenre", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("MusicGenre", StringComparison.OrdinalIgnoreCase)) { - item = GetMusicGenre(name, libraryManager, dtoOptions); + return GetMusicGenre(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Studio", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Studio", StringComparison.OrdinalIgnoreCase)) { - item = GetStudio(name, libraryManager, dtoOptions); + return GetStudio(name, libraryManager, dtoOptions); } - else if (type.IndexOf("Year", StringComparison.OrdinalIgnoreCase) == 0) + else if (type.Equals("Year", StringComparison.OrdinalIgnoreCase)) { - item = libraryManager.GetYear(int.Parse(name)); - } - else - { - 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 7a8455ff26..a30f8adfed 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 f26087fda3..860ea13cf6 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 aee9921034..f86cdeab9f 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 924b712507..55aab7778a 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); } From 6d3e6d800fd8c6d5cb22271e2177946ab286855f Mon Sep 17 00:00:00 2001 From: PloughPuff Date: Wed, 13 Mar 2019 20:31:21 +0000 Subject: [PATCH 40/48] Only delay making request if necessary When requesting data from MusicBrainz, only delay the request if previous request was less than rate limit ago, instead of always delaying for one second at start. --- .../Music/MusicBrainzAlbumProvider.cs | 62 +++++++------------ .../Music/MusicBrainzArtistProvider.cs | 6 +- 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index f86cdeab9f..8a3860d74e 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -28,6 +29,7 @@ namespace MediaBrowser.Providers.Music private readonly IApplicationHost _appHost; private readonly ILogger _logger; private readonly IJsonSerializer _json; + private Stopwatch _stopWatchMusicBrainz = new Stopwatch(); public readonly string MusicBrainzBaseUrl; @@ -45,6 +47,9 @@ namespace MediaBrowser.Providers.Music MusicBrainzBaseUrl = configuration["MusicBrainz:BaseUrl"]; + // Use a stopwatch to ensure we don't exceed the MusicBrainz rate limit + _stopWatchMusicBrainz.Start(); + Current = this; } @@ -54,8 +59,6 @@ namespace MediaBrowser.Providers.Music var releaseGroupId = searchInfo.GetReleaseGroupId(); string url; - var isNameSearch = false; - bool forceMusicBrainzProper = false; if (!string.IsNullOrEmpty(releaseId)) { @@ -64,7 +67,6 @@ namespace MediaBrowser.Providers.Music else if (!string.IsNullOrEmpty(releaseGroupId)) { url = string.Format("/ws/2/release?release-group={0}", releaseGroupId); - forceMusicBrainzProper = true; } else { @@ -78,8 +80,6 @@ namespace MediaBrowser.Providers.Music } else { - isNameSearch = true; - // I'm sure there is a better way but for now it resolves search for 12" Mixes var queryName = searchInfo.Name.Replace("\"", string.Empty); @@ -91,7 +91,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(url)) { - using (var response = await GetMusicBrainzResponse(url, isNameSearch, forceMusicBrainzProper, cancellationToken).ConfigureAwait(false)) + using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) { using (var stream = response.Content) { @@ -247,7 +247,7 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), artistId); - using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) using (var stream = response.Content) using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -272,7 +272,7 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(albumName), WebUtility.UrlEncode(artistName)); - using (var response = await GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) using (var stream = response.Content) using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -589,7 +589,7 @@ namespace MediaBrowser.Providers.Music { var url = string.Format("/ws/2/release?release-group={0}", releaseGroupId); - using (var response = await GetMusicBrainzResponse(url, true, true, cancellationToken).ConfigureAwait(false)) + using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) using (var stream = response.Content) using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -625,7 +625,7 @@ namespace MediaBrowser.Providers.Music { var url = string.Format("/ws/2/release-group/?query=reid:{0}", releaseEntryId); - using (var response = await GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false)) + using (var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) using (var stream = response.Content) using (var oReader = new StreamReader(stream, Encoding.UTF8)) { @@ -710,34 +710,32 @@ namespace MediaBrowser.Providers.Music return null; } - internal Task GetMusicBrainzResponse(string url, bool isSearch, CancellationToken cancellationToken) - { - return GetMusicBrainzResponse(url, isSearch, false, cancellationToken); - } - /// - /// Gets the music brainz response. + /// Makes request to MusicBrainz server and awaits a response. /// - internal async Task GetMusicBrainzResponse(string url, bool isSearch, bool forceMusicBrainzProper, CancellationToken cancellationToken) + internal async Task GetMusicBrainzResponse(string url, CancellationToken cancellationToken) { - var urlInfo = new MbzUrl(MusicBrainzBaseUrl, 1000); - var throttleMs = urlInfo.throttleMs; + // The Jellyfin user-agent is unrestricted but source IP must not exceed + // one request per second, therefore we rate limit to avoid throttling + // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting + const long QueryIntervalMs = 1000u; - if (throttleMs > 0) + // Only delay if necessary + if (_stopWatchMusicBrainz.ElapsedMilliseconds < QueryIntervalMs) { - // MusicBrainz is extremely adamant about limiting to one request per second - _logger.LogDebug("Throttling MusicBrainz by {0}ms", throttleMs.ToString(CultureInfo.InvariantCulture)); - await Task.Delay(throttleMs, cancellationToken).ConfigureAwait(false); + var delayMs = QueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds; + await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false); } - url = urlInfo.url.TrimEnd('/') + url; + _logger.LogDebug("MusicBrainz time since previous request: {0}ms", _stopWatchMusicBrainz.ElapsedMilliseconds); + _stopWatchMusicBrainz.Restart(); var options = new HttpRequestOptions { - Url = url, + Url = MusicBrainzBaseUrl.TrimEnd('/') + url, CancellationToken = cancellationToken, UserAgent = _appHost.ApplicationUserAgent, - BufferContent = throttleMs > 0 + BufferContent = false }; return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false); @@ -749,17 +747,5 @@ namespace MediaBrowser.Providers.Music { throw new NotImplementedException(); } - - internal class MbzUrl - { - internal MbzUrl(string url, int throttleMs) - { - this.url = url; - this.throttleMs = throttleMs; - } - - public string url { get; set; } - public int throttleMs { get; set; } - } } } diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs index 55aab7778a..59280df897 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs @@ -31,7 +31,7 @@ namespace MediaBrowser.Providers.Music { var url = string.Format("/ws/2/artist/?query=arid:{0}", musicBrainzId); - using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, false, cancellationToken).ConfigureAwait(false)) + using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) { using (var stream = response.Content) { @@ -46,7 +46,7 @@ namespace MediaBrowser.Providers.Music var url = string.Format("/ws/2/artist/?query=\"{0}\"&dismax=true", UrlEncode(nameToSearch)); - using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) { using (var stream = response.Content) { @@ -64,7 +64,7 @@ namespace MediaBrowser.Providers.Music // Try again using the search with accent characters url url = string.Format("/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); - using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, true, cancellationToken).ConfigureAwait(false)) + using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) { using (var stream = response.Content) { From f8bb7a7ff4d87d19a43f97fed557aa92a657a50f Mon Sep 17 00:00:00 2001 From: PloughPuff Date: Thu, 14 Mar 2019 00:43:41 +0000 Subject: [PATCH 41/48] Increased interval to 1050ms and moved to class scope Review comments from JustAMan. --- .../Music/MusicBrainzAlbumProvider.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index 8a3860d74e..a1366e0fde 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -33,6 +33,12 @@ namespace MediaBrowser.Providers.Music public readonly string MusicBrainzBaseUrl; + // The Jellyfin user-agent is unrestricted but source IP must not exceed + // one request per second, therefore we rate limit to avoid throttling. + // Be prudent, use a value slightly above the minimun required. + // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting + private const long MusicBrainzQueryIntervalMs = 1050u; + public MusicBrainzAlbumProvider( IHttpClient httpClient, IApplicationHost appHost, @@ -715,15 +721,10 @@ namespace MediaBrowser.Providers.Music /// internal async Task GetMusicBrainzResponse(string url, CancellationToken cancellationToken) { - // The Jellyfin user-agent is unrestricted but source IP must not exceed - // one request per second, therefore we rate limit to avoid throttling - // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting - const long QueryIntervalMs = 1000u; - - // Only delay if necessary - if (_stopWatchMusicBrainz.ElapsedMilliseconds < QueryIntervalMs) + if (_stopWatchMusicBrainz.ElapsedMilliseconds < MusicBrainzQueryIntervalMs) { - var delayMs = QueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds; + // MusicBrainz is extremely adamant about limiting to one request per second + var delayMs = MusicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds; await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false); } From ee7bf86e0f76cdd655f9f9766a4b99f5210ce985 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Thu, 14 Mar 2019 22:05:33 +0100 Subject: [PATCH 42/48] Adjusted the Product Name so the User Agent is correct/better. --- BDInfo/Properties/AssemblyInfo.cs | 2 +- DvdLib/Properties/AssemblyInfo.cs | 2 +- Emby.Dlna/Properties/AssemblyInfo.cs | 2 +- Emby.Drawing/Properties/AssemblyInfo.cs | 2 +- Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs | 2 +- Emby.Naming/Properties/AssemblyInfo.cs | 2 +- Emby.Notifications/Properties/AssemblyInfo.cs | 2 +- Emby.Photos/Properties/AssemblyInfo.cs | 2 +- Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs | 2 +- Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs | 2 +- Jellyfin.Server/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Api/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Common/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Controller/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Model/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Providers/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Tests/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs | 2 +- Mono.Nat/Properties/AssemblyInfo.cs | 2 +- RSSDP/Properties/AssemblyInfo.cs | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/BDInfo/Properties/AssemblyInfo.cs b/BDInfo/Properties/AssemblyInfo.cs index 788cf73666..482cd376a1 100644 --- a/BDInfo/Properties/AssemblyInfo.cs +++ b/BDInfo/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/DvdLib/Properties/AssemblyInfo.cs b/DvdLib/Properties/AssemblyInfo.cs index 5fc055d1f0..09d1a3801a 100644 --- a/DvdLib/Properties/AssemblyInfo.cs +++ b/DvdLib/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.Dlna/Properties/AssemblyInfo.cs b/Emby.Dlna/Properties/AssemblyInfo.cs index 9d3a22c970..0e3b03a322 100644 --- a/Emby.Dlna/Properties/AssemblyInfo.cs +++ b/Emby.Dlna/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ using System.Resources; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.Drawing/Properties/AssemblyInfo.cs b/Emby.Drawing/Properties/AssemblyInfo.cs index 8dfefe0af8..4429839606 100644 --- a/Emby.Drawing/Properties/AssemblyInfo.cs +++ b/Emby.Drawing/Properties/AssemblyInfo.cs @@ -8,7 +8,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs b/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs index d60eccc2ee..702aed3b5a 100644 --- a/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs +++ b/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.Naming/Properties/AssemblyInfo.cs b/Emby.Naming/Properties/AssemblyInfo.cs index 15311570b8..9295a1ec75 100644 --- a/Emby.Naming/Properties/AssemblyInfo.cs +++ b/Emby.Naming/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.Notifications/Properties/AssemblyInfo.cs b/Emby.Notifications/Properties/AssemblyInfo.cs index fd70375515..53b80e3dc1 100644 --- a/Emby.Notifications/Properties/AssemblyInfo.cs +++ b/Emby.Notifications/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.Photos/Properties/AssemblyInfo.cs b/Emby.Photos/Properties/AssemblyInfo.cs index 262125d388..c3ebc4e08e 100644 --- a/Emby.Photos/Properties/AssemblyInfo.cs +++ b/Emby.Photos/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs b/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs index ff2efb0781..69a532c357 100644 --- a/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs +++ b/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs index ea1c457f6c..9fdb9529f5 100644 --- a/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs +++ b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Jellyfin.Server/Properties/AssemblyInfo.cs b/Jellyfin.Server/Properties/AssemblyInfo.cs index 2959cdf1fe..1add32c8c1 100644 --- a/Jellyfin.Server/Properties/AssemblyInfo.cs +++ b/Jellyfin.Server/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Api/Properties/AssemblyInfo.cs b/MediaBrowser.Api/Properties/AssemblyInfo.cs index f867230311..fb7d43f456 100644 --- a/MediaBrowser.Api/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Api/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Common/Properties/AssemblyInfo.cs b/MediaBrowser.Common/Properties/AssemblyInfo.cs index 1a8fdb618d..d428cea2fd 100644 --- a/MediaBrowser.Common/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Common/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Controller/Properties/AssemblyInfo.cs b/MediaBrowser.Controller/Properties/AssemblyInfo.cs index 007a1d739b..0841e84f24 100644 --- a/MediaBrowser.Controller/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Controller/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs index 3eac837081..4d09084d20 100644 --- a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs index 6ecdf89bc1..8851ec5277 100644 --- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs +++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Model/Properties/AssemblyInfo.cs b/MediaBrowser.Model/Properties/AssemblyInfo.cs index e78719e35f..f118294817 100644 --- a/MediaBrowser.Model/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Model/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Providers/Properties/AssemblyInfo.cs b/MediaBrowser.Providers/Properties/AssemblyInfo.cs index d2b13fc89d..eb2599e35a 100644 --- a/MediaBrowser.Providers/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Providers/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.Tests/Properties/AssemblyInfo.cs b/MediaBrowser.Tests/Properties/AssemblyInfo.cs index 9bc2a19f21..1bd3ef5d64 100644 --- a/MediaBrowser.Tests/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Tests/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin System")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs b/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs index 416ce4826a..346853f588 100644 --- a/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs +++ b/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs index 11e513f1be..343befb7e2 100644 --- a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Mono.Nat/Properties/AssemblyInfo.cs b/Mono.Nat/Properties/AssemblyInfo.cs index ea1c9dee6d..c24a4fc6c2 100644 --- a/Mono.Nat/Properties/AssemblyInfo.cs +++ b/Mono.Nat/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2006 Alan McGovern. Copyright © 2007 Ben Motmans. Code releases unde the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/RSSDP/Properties/AssemblyInfo.cs b/RSSDP/Properties/AssemblyInfo.cs index d2bb7c6f31..690ddb807c 100644 --- a/RSSDP/Properties/AssemblyInfo.cs +++ b/RSSDP/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin: The Free Software Media System")] +[assembly: AssemblyProduct("Jellyfin Server")] [assembly: AssemblyCopyright("Copyright © 2015 Troy Willmot. Code released under the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] From 21cc38fcf426f5ecaedbe8a94007a89663de749c Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Thu, 14 Mar 2019 22:17:56 +0100 Subject: [PATCH 43/48] Adjusted AssemblyCopyright attribute values. --- BDInfo/Properties/AssemblyInfo.cs | 2 +- DvdLib/Properties/AssemblyInfo.cs | 2 +- Emby.Dlna/Properties/AssemblyInfo.cs | 2 +- Emby.Drawing/Properties/AssemblyInfo.cs | 2 +- Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs | 2 +- Emby.Naming/Properties/AssemblyInfo.cs | 2 +- Emby.Notifications/Properties/AssemblyInfo.cs | 2 +- Emby.Photos/Properties/AssemblyInfo.cs | 2 +- Emby.Server.Implementations/Properties/AssemblyInfo.cs | 2 +- Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs | 2 +- Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs | 2 +- Jellyfin.Server/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Api/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Common/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Controller/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Model/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.Providers/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs | 2 +- MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs | 2 +- Mono.Nat/Properties/AssemblyInfo.cs | 2 +- RSSDP/Properties/AssemblyInfo.cs | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/BDInfo/Properties/AssemblyInfo.cs b/BDInfo/Properties/AssemblyInfo.cs index 482cd376a1..f65c7036a4 100644 --- a/BDInfo/Properties/AssemblyInfo.cs +++ b/BDInfo/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/DvdLib/Properties/AssemblyInfo.cs b/DvdLib/Properties/AssemblyInfo.cs index 09d1a3801a..6acd571d68 100644 --- a/DvdLib/Properties/AssemblyInfo.cs +++ b/DvdLib/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Dlna/Properties/AssemblyInfo.cs b/Emby.Dlna/Properties/AssemblyInfo.cs index 0e3b03a322..a2c1e0db8b 100644 --- a/Emby.Dlna/Properties/AssemblyInfo.cs +++ b/Emby.Dlna/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Resources; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Drawing/Properties/AssemblyInfo.cs b/Emby.Drawing/Properties/AssemblyInfo.cs index 4429839606..281008e370 100644 --- a/Emby.Drawing/Properties/AssemblyInfo.cs +++ b/Emby.Drawing/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs b/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs index 702aed3b5a..5956fc3b31 100644 --- a/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs +++ b/Emby.IsoMounting/IsoMounter/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Naming/Properties/AssemblyInfo.cs b/Emby.Naming/Properties/AssemblyInfo.cs index 9295a1ec75..f26e0ba794 100644 --- a/Emby.Naming/Properties/AssemblyInfo.cs +++ b/Emby.Naming/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Notifications/Properties/AssemblyInfo.cs b/Emby.Notifications/Properties/AssemblyInfo.cs index 53b80e3dc1..5c82c90c47 100644 --- a/Emby.Notifications/Properties/AssemblyInfo.cs +++ b/Emby.Notifications/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Photos/Properties/AssemblyInfo.cs b/Emby.Photos/Properties/AssemblyInfo.cs index c3ebc4e08e..a3bb4362a9 100644 --- a/Emby.Photos/Properties/AssemblyInfo.cs +++ b/Emby.Photos/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.Server.Implementations/Properties/AssemblyInfo.cs b/Emby.Server.Implementations/Properties/AssemblyInfo.cs index 79ba9374ce..a1933f66ef 100644 --- a/Emby.Server.Implementations/Properties/AssemblyInfo.cs +++ b/Emby.Server.Implementations/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs b/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs index 69a532c357..7beec09cbd 100644 --- a/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs +++ b/Emby.XmlTv/Emby.XmlTv/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs index 9fdb9529f5..e7db09449d 100644 --- a/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs +++ b/Jellyfin.Drawing.Skia/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Jellyfin.Server/Properties/AssemblyInfo.cs b/Jellyfin.Server/Properties/AssemblyInfo.cs index 1add32c8c1..5de1e653d9 100644 --- a/Jellyfin.Server/Properties/AssemblyInfo.cs +++ b/Jellyfin.Server/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.Api/Properties/AssemblyInfo.cs b/MediaBrowser.Api/Properties/AssemblyInfo.cs index fb7d43f456..35bcbea5cd 100644 --- a/MediaBrowser.Api/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Api/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.Common/Properties/AssemblyInfo.cs b/MediaBrowser.Common/Properties/AssemblyInfo.cs index d428cea2fd..538e89fd1c 100644 --- a/MediaBrowser.Common/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Common/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.Controller/Properties/AssemblyInfo.cs b/MediaBrowser.Controller/Properties/AssemblyInfo.cs index 0841e84f24..60e7923091 100644 --- a/MediaBrowser.Controller/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Controller/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs index 4d09084d20..580cef9da6 100644 --- a/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.LocalMetadata/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs index 8851ec5277..a9491374bd 100644 --- a/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs +++ b/MediaBrowser.MediaEncoding/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.Model/Properties/AssemblyInfo.cs b/MediaBrowser.Model/Properties/AssemblyInfo.cs index f118294817..f99e9ece96 100644 --- a/MediaBrowser.Model/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Model/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.Providers/Properties/AssemblyInfo.cs b/MediaBrowser.Providers/Properties/AssemblyInfo.cs index eb2599e35a..f1c46899ce 100644 --- a/MediaBrowser.Providers/Properties/AssemblyInfo.cs +++ b/MediaBrowser.Providers/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs b/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs index 346853f588..584d490216 100644 --- a/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs +++ b/MediaBrowser.WebDashboard/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs index 343befb7e2..b3e2f27179 100644 --- a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs +++ b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Mono.Nat/Properties/AssemblyInfo.cs b/Mono.Nat/Properties/AssemblyInfo.cs index c24a4fc6c2..dc47f2ffeb 100644 --- a/Mono.Nat/Properties/AssemblyInfo.cs +++ b/Mono.Nat/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2006 Alan McGovern. Copyright © 2007 Ben Motmans. Code releases unde the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2006 Alan McGovern. Copyright © 2007 Ben Motmans. Code releases under the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] diff --git a/RSSDP/Properties/AssemblyInfo.cs b/RSSDP/Properties/AssemblyInfo.cs index 690ddb807c..55f7b6a834 100644 --- a/RSSDP/Properties/AssemblyInfo.cs +++ b/RSSDP/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jellyfin Project")] [assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2015 Troy Willmot. Code released under the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License Version 2")] +[assembly: AssemblyCopyright("Copyright © 2015 Troy Willmot. Code released under the MIT license. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("en")] From d125fbc43d453be7de08375dede1748d4c19a8cf Mon Sep 17 00:00:00 2001 From: PloughPuff Date: Thu, 14 Mar 2019 21:32:27 +0000 Subject: [PATCH 44/48] Added contact email to user agent MusicBrainz request a contact email address is supplied in comment section of user agent field. --- Emby.Server.Implementations/ApplicationHost.cs | 6 ++++++ MediaBrowser.Common/IApplicationHost.cs | 6 ++++++ MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs | 5 +++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 94eaffa479..eaea8844d4 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -428,6 +428,12 @@ namespace Emby.Server.Implementations /// The application user agent. public string ApplicationUserAgent => Name.Replace(' ','-') + "/" + ApplicationVersion; + /// + /// Gets the email address for use within a comment section of a user agent field. + /// Presently used to provide contact information to MusicBrainz service. + /// + public string ApplicationUserAgentAddress { get; } = "team@jellyfin.org"; + private string _productName; /// diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 966448d630..2925a3efd9 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -71,6 +71,12 @@ namespace MediaBrowser.Common /// The application user agent. string ApplicationUserAgent { get; } + /// + /// Gets the email address for use within a comment section of a user agent field. + /// Presently used to provide contact information to MusicBrainz service. + /// + string ApplicationUserAgentAddress { get; } + /// /// Gets the exports. /// diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index a1366e0fde..b716f40f04 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -735,7 +734,9 @@ namespace MediaBrowser.Providers.Music { Url = MusicBrainzBaseUrl.TrimEnd('/') + url, CancellationToken = cancellationToken, - UserAgent = _appHost.ApplicationUserAgent, + // MusicBrainz request a contact email address is supplied, as comment, in user agent field: + // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent + UserAgent = string.Format("{0} ( {1} )", _appHost.ApplicationUserAgent, _appHost.ApplicationUserAgentAddress), BufferContent = false }; From dd929d796f10d06f5874909d7572fa49e750fb6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 15 Mar 2019 14:30:15 +0100 Subject: [PATCH 45/48] Only remove /var/lib/apt/lists/* --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 72c0cdbf3a..5794bdde1e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,7 @@ RUN apt-get update \ libfontconfig1 \ && apt-get clean autoclean \ && apt-get autoremove \ - && rm -rf /var/lib/{apt,dpkg,cache,log} \ + && rm -rf /var/lib/apt/lists/* \ && mkdir -p /cache /config /media \ && chmod 777 /cache /config /media COPY --from=ffmpeg / / From 31305af7ffafabaf88911b67665751f74903199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Fri, 15 Mar 2019 14:37:11 +0100 Subject: [PATCH 46/48] Clean apt lists in arm Dockerfiles --- Dockerfile.arm | 1 + Dockerfile.arm64 | 1 + 2 files changed, 2 insertions(+) diff --git a/Dockerfile.arm b/Dockerfile.arm index 238e90ccd8..1497da0ef7 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -25,6 +25,7 @@ FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm32v7 COPY --from=qemu_extract qemu-arm-static /usr/bin RUN apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \ + && rm -rf /var/lib/apt/lists/* \ && mkdir -p /cache /config /media \ && chmod 777 /cache /config /media COPY --from=builder /jellyfin /jellyfin diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 2927d4e658..f4658a055c 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -26,6 +26,7 @@ FROM microsoft/dotnet:${DOTNET_VERSION}-runtime-stretch-slim-arm64v8 COPY --from=qemu_extract qemu-aarch64-static /usr/bin RUN apt-get update \ && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \ + && rm -rf /var/lib/apt/lists/* \ && mkdir -p /cache /config /media \ && chmod 777 /cache /config /media COPY --from=builder /jellyfin /jellyfin From 764c901cd7adc5ae95d2657822d2910e0c2e8468 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 15 Mar 2019 17:34:15 +0100 Subject: [PATCH 47/48] Fix exception caused by #1096 ```cs MediaBrowser.Common.Extensions.ResourceNotFoundException: Configuration with key subtitles not found. at Emby.Server.Implementations.AppBase.BaseConfigurationManager.<>c__DisplayClass42_0.b__0(String k) in /home/pi/dev/jellyfin/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs:line 247 at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) at Emby.Server.Implementations.AppBase.BaseConfigurationManager.GetConfiguration(String key) in /home/pi/dev/jellyfin/Emby.Server.Implementations/AppBase/BaseConfigurationManager.cs:line 238 at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.AddExternalSubtitles(Video video, List`1 currentStreams, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 486 at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.Fetch(Video video, CancellationToken cancellationToken, MediaInfo mediaInfo, BlurayDiscInfo blurayInfo, MetadataRefreshOptions options) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 204 at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 119 at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 806 ``` --- .../Providers/SubtitleConfigurationFactory.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs diff --git a/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs b/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs new file mode 100644 index 0000000000..09d974db6c --- /dev/null +++ b/MediaBrowser.Common/Providers/SubtitleConfigurationFactory.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Model.Providers; + +namespace MediaBrowser.Common.Providers +{ + public class SubtitleConfigurationFactory : IConfigurationFactory + { + public IEnumerable GetConfigurations() + { + yield return new ConfigurationStore() + { + Key = "subtitles", + ConfigurationType = typeof(SubtitleOptions) + }; + } + } +} From d2e408539ea32eaad573ff1deb6f77a2d80a70d3 Mon Sep 17 00:00:00 2001 From: PloughPuff Date: Fri, 15 Mar 2019 19:29:04 +0000 Subject: [PATCH 48/48] MusicBrainz 503 Retry Strategy Upon receiving back a 503 Service Unavailable from MusicBrainz (indicating throttling), retry the same request a number of times before giving up. --- .../Music/MusicBrainzAlbumProvider.cs | 63 ++++++++++++++----- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index b716f40f04..3797f9039a 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -32,12 +32,21 @@ namespace MediaBrowser.Providers.Music public readonly string MusicBrainzBaseUrl; - // The Jellyfin user-agent is unrestricted but source IP must not exceed - // one request per second, therefore we rate limit to avoid throttling. - // Be prudent, use a value slightly above the minimun required. - // https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting + /// + /// The Jellyfin user-agent is unrestricted but source IP must not exceed + /// one request per second, therefore we rate limit to avoid throttling. + /// Be prudent, use a value slightly above the minimun required. + /// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting + /// private const long MusicBrainzQueryIntervalMs = 1050u; + /// + /// For each single MB lookup/search, this is the maximum number of + /// attempts that shall be made whilst receiving a 503 Server + /// Unavailable (indicating throttled) response. + /// + private const uint MusicBrainzQueryAttempts = 5u; + public MusicBrainzAlbumProvider( IHttpClient httpClient, IApplicationHost appHost, @@ -717,19 +726,12 @@ namespace MediaBrowser.Providers.Music /// /// Makes request to MusicBrainz server and awaits a response. + /// A 503 Service Unavailable response indicates throttling to maintain a rate limit. + /// A number of retries shall be made in order to try and satisfy the request before + /// giving up and returning null. /// internal async Task GetMusicBrainzResponse(string url, CancellationToken cancellationToken) { - if (_stopWatchMusicBrainz.ElapsedMilliseconds < MusicBrainzQueryIntervalMs) - { - // MusicBrainz is extremely adamant about limiting to one request per second - var delayMs = MusicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds; - await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false); - } - - _logger.LogDebug("MusicBrainz time since previous request: {0}ms", _stopWatchMusicBrainz.ElapsedMilliseconds); - _stopWatchMusicBrainz.Restart(); - var options = new HttpRequestOptions { Url = MusicBrainzBaseUrl.TrimEnd('/') + url, @@ -740,7 +742,38 @@ namespace MediaBrowser.Providers.Music BufferContent = false }; - return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false); + HttpResponseInfo response; + var attempts = 0u; + + do + { + attempts++; + + if (_stopWatchMusicBrainz.ElapsedMilliseconds < MusicBrainzQueryIntervalMs) + { + // MusicBrainz is extremely adamant about limiting to one request per second + var delayMs = MusicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds; + await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false); + } + + // Write time since last request to debug log as evidence we're meeting rate limit + // requirement, before resetting stopwatch back to zero. + _logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds); + _stopWatchMusicBrainz.Restart(); + + response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false); + + // We retry a finite number of times, and only whilst MB is indcating 503 (throttling) + } + while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable); + + // Log error if unable to query MB database due to throttling + if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable ) + { + _logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, options.Url); + } + + return response; } public int Order => 0;