diff options
Diffstat (limited to 'Emby.Server.Implementations')
10 files changed, 198 insertions, 167 deletions
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs index dea9b6682..ff7ee085f 100644 --- a/Emby.Server.Implementations/ConfigurationOptions.cs +++ b/Emby.Server.Implementations/ConfigurationOptions.cs @@ -17,7 +17,6 @@ namespace Emby.Server.Implementations { { HostWebClientKey, bool.TrueString }, { HttpListenerHost.DefaultRedirectKey, "web/index.html" }, - { InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" }, { FfmpegProbeSizeKey, "1G" }, { FfmpegAnalyzeDurationKey, "200M" }, { PlaylistsAllowDuplicatesKey, bool.TrueString } diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs index 7b7da703b..970f5119c 100644 --- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs +++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs @@ -585,7 +585,7 @@ namespace Emby.Server.Implementations.HttpServer if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue) { - var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest, _logger) + var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest) { OnComplete = options.OnComplete }; @@ -622,8 +622,11 @@ namespace Emby.Server.Implementations.HttpServer /// <summary> /// Adds the caching responseHeaders. /// </summary> - private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration, - bool noCache, DateTime? lastModifiedDate) + private void AddCachingHeaders( + IDictionary<string, string> responseHeaders, + TimeSpan? cacheDuration, + bool noCache, + DateTime? lastModifiedDate) { if (noCache) { diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs index 540340272..980c2cd3a 100644 --- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs +++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs @@ -1,6 +1,7 @@ #pragma warning disable CS1591 using System; +using System.Buffers; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -8,52 +9,17 @@ using System.Net; 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 { public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult { - /// <summary> - /// Gets or sets the source stream. - /// </summary> - /// <value>The source stream.</value> - private Stream SourceStream { get; set; } - - private string RangeHeader { get; set; } - - private bool IsHeadRequest { get; set; } - - private long RangeStart { get; set; } - - private long RangeEnd { get; set; } - - private long RangeLength { get; set; } - - private long TotalContentLength { get; set; } - - public Action OnComplete { get; set; } - - private readonly ILogger _logger; - private const int BufferSize = 81920; - /// <summary> - /// The _options. - /// </summary> private readonly Dictionary<string, string> _options = new Dictionary<string, string>(); - /// <summary> - /// The us culture. - /// </summary> - private static readonly CultureInfo UsCulture = new CultureInfo("en-US"); - - /// <summary> - /// Additional HTTP Headers. - /// </summary> - /// <value>The headers.</value> - public IDictionary<string, string> Headers => _options; + private List<KeyValuePair<long, long?>> _requestedRanges; /// <summary> /// Initializes a new instance of the <see cref="RangeRequestWriter" /> class. @@ -63,8 +29,7 @@ namespace Emby.Server.Implementations.HttpServer /// <param name="source">The source.</param> /// <param name="contentType">Type of the content.</param> /// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param> - /// <param name="logger">The logger instance.</param> - public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest, ILogger logger) + public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest) { if (string.IsNullOrEmpty(contentType)) { @@ -74,7 +39,6 @@ namespace Emby.Server.Implementations.HttpServer RangeHeader = rangeHeader; SourceStream = source; IsHeadRequest = isHeadRequest; - this._logger = logger; ContentType = contentType; Headers[HeaderNames.ContentType] = contentType; @@ -85,40 +49,26 @@ namespace Emby.Server.Implementations.HttpServer } /// <summary> - /// Sets the range values. + /// Gets or sets the source stream. /// </summary> - private void SetRangeValues(long contentLength) - { - var requestedRange = RequestedRanges[0]; - - TotalContentLength = contentLength; - - // If the requested range is "0-", we can optimize by just doing a stream copy - if (!requestedRange.Value.HasValue) - { - RangeEnd = TotalContentLength - 1; - } - else - { - RangeEnd = requestedRange.Value.Value; - } - - RangeStart = requestedRange.Key; - RangeLength = 1 + RangeEnd - RangeStart; + /// <value>The source stream.</value> + private Stream SourceStream { get; set; } + private string RangeHeader { get; set; } + private bool IsHeadRequest { get; set; } - Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture); - Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; + private long RangeStart { get; set; } + private long RangeEnd { get; set; } + private long RangeLength { get; set; } + private long TotalContentLength { get; set; } - if (RangeStart > 0 && SourceStream.CanSeek) - { - SourceStream.Position = RangeStart; - } - } + public Action OnComplete { get; set; } /// <summary> - /// The _requested ranges. + /// Additional HTTP Headers /// </summary> - private List<KeyValuePair<long, long?>> _requestedRanges; + /// <value>The headers.</value> + public IDictionary<string, string> Headers => _options; + /// <summary> /// Gets the requested ranges. /// </summary> @@ -143,12 +93,12 @@ namespace Emby.Server.Implementations.HttpServer if (!string.IsNullOrEmpty(vals[0])) { - start = long.Parse(vals[0], UsCulture); + start = long.Parse(vals[0], CultureInfo.InvariantCulture); } if (!string.IsNullOrEmpty(vals[1])) { - end = long.Parse(vals[1], UsCulture); + end = long.Parse(vals[1], CultureInfo.InvariantCulture); } _requestedRanges.Add(new KeyValuePair<long, long?>(start, end)); @@ -159,6 +109,51 @@ namespace Emby.Server.Implementations.HttpServer } } + public string ContentType { get; set; } + + public IRequest RequestContext { get; set; } + + public object Response { get; set; } + + public int Status { get; set; } + + public HttpStatusCode StatusCode + { + get => (HttpStatusCode)Status; + set => Status = (int)value; + } + + /// <summary> + /// Sets the range values. + /// </summary> + private void SetRangeValues(long contentLength) + { + var requestedRange = RequestedRanges[0]; + + TotalContentLength = contentLength; + + // If the requested range is "0-", we can optimize by just doing a stream copy + if (!requestedRange.Value.HasValue) + { + RangeEnd = TotalContentLength - 1; + } + else + { + RangeEnd = requestedRange.Value.Value; + } + + RangeStart = requestedRange.Key; + RangeLength = 1 + RangeEnd - RangeStart; + + Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture); + Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}"; + + if (RangeStart > 0 && SourceStream.CanSeek) + { + SourceStream.Position = RangeStart; + } + } + public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken) { try @@ -174,59 +169,44 @@ namespace Emby.Server.Implementations.HttpServer // If the requested range is "0-", we can optimize by just doing a stream copy if (RangeEnd >= TotalContentLength - 1) { - await source.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false); + await source.CopyToAsync(responseStream, BufferSize, cancellationToken).ConfigureAwait(false); } else { - await CopyToInternalAsync(source, responseStream, RangeLength).ConfigureAwait(false); + await CopyToInternalAsync(source, responseStream, RangeLength, cancellationToken).ConfigureAwait(false); } } } finally { - if (OnComplete != null) - { - OnComplete(); - } + OnComplete?.Invoke(); } } - private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength) + private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken) { - var array = new byte[BufferSize]; - int bytesRead; - while ((bytesRead = await source.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0) + var array = ArrayPool<byte>.Shared.Rent(BufferSize); + try { - if (bytesRead == 0) + int bytesRead; + while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) { - break; - } + var bytesToCopy = Math.Min(bytesRead, copyLength); - var bytesToCopy = Math.Min(bytesRead, copyLength); + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy), cancellationToken).ConfigureAwait(false); - await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy)).ConfigureAwait(false); + copyLength -= bytesToCopy; - copyLength -= bytesToCopy; - - if (copyLength <= 0) - { - break; + if (copyLength <= 0) + { + break; + } } } - } - - public string ContentType { get; set; } - - public IRequest RequestContext { get; set; } - - public object Response { get; set; } - - public int Status { get; set; } - - public HttpStatusCode StatusCode - { - get => (HttpStatusCode)Status; - set => Status = (int)value; + finally + { + ArrayPool<byte>.Shared.Return(array); + } } } } diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs index 0b9f80538..e7e72c686 100644 --- a/Emby.Server.Implementations/IStartupOptions.cs +++ b/Emby.Server.Implementations/IStartupOptions.cs @@ -37,11 +37,6 @@ namespace Emby.Server.Implementations string RestartArgs { get; } /// <summary> - /// Gets the value of the --plugin-manifest-url command line option. - /// </summary> - string PluginManifestUrl { get; } - - /// <summary> /// Gets the value of the --published-server-url command line option. /// </summary> Uri PublishedServerUrl { get; } diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 9b8091aa7..77d44e131 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -1893,9 +1893,19 @@ namespace Emby.Server.Implementations.Library } } - ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); - image.Width = size.Width; - image.Height = size.Height; + try + { + ImageDimensions size = _imageProcessor.GetImageDimensions(item, image); + image.Width = size.Width; + image.Height = size.Height; + } + catch (Exception ex) + { + _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path); + image.Width = 0; + image.Height = 0; + continue; + } try { @@ -2896,7 +2906,8 @@ namespace Emby.Server.Implementations.Library } catch (HttpException ex) { - if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) + if (ex.StatusCode.HasValue + && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) { continue; } diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json index fc9a10f27..ac96c788c 100644 --- a/Emby.Server.Implementations/Localization/Core/es-AR.json +++ b/Emby.Server.Implementations/Localization/Core/es-AR.json @@ -20,7 +20,7 @@ "HeaderContinueWatching": "Seguir viendo", "HeaderFavoriteAlbums": "Álbumes favoritos", "HeaderFavoriteArtists": "Artistas favoritos", - "HeaderFavoriteEpisodes": "Episodios favoritos", + "HeaderFavoriteEpisodes": "Capítulos favoritos", "HeaderFavoriteShows": "Programas favoritos", "HeaderFavoriteSongs": "Canciones favoritas", "HeaderLiveTV": "TV en vivo", diff --git a/Emby.Server.Implementations/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json index c169a35e7..97c77017b 100644 --- a/Emby.Server.Implementations/Localization/Core/hr.json +++ b/Emby.Server.Implementations/Localization/Core/hr.json @@ -5,23 +5,23 @@ "Artists": "Izvođači", "AuthenticationSucceededWithUserName": "{0} uspješno ovjerena", "Books": "Knjige", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", + "CameraImageUploadedFrom": "Nova fotografija sa kamere je uploadana iz {0}", "Channels": "Kanali", "ChapterNameValue": "Poglavlje {0}", "Collections": "Kolekcije", "DeviceOfflineWithName": "{0} se odspojilo", "DeviceOnlineWithName": "{0} je spojeno", "FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave za {0}", - "Favorites": "Omiljeni", + "Favorites": "Favoriti", "Folders": "Mape", "Genres": "Žanrovi", - "HeaderAlbumArtists": "Izvođači albuma", - "HeaderCameraUploads": "Camera Uploads", - "HeaderContinueWatching": "Continue Watching", + "HeaderAlbumArtists": "Izvođači na albumu", + "HeaderCameraUploads": "Uvoz sa kamere", + "HeaderContinueWatching": "Nastavi gledati", "HeaderFavoriteAlbums": "Omiljeni albumi", "HeaderFavoriteArtists": "Omiljeni izvođači", "HeaderFavoriteEpisodes": "Omiljene epizode", - "HeaderFavoriteShows": "Omiljene emisije", + "HeaderFavoriteShows": "Omiljene serije", "HeaderFavoriteSongs": "Omiljene pjesme", "HeaderLiveTV": "TV uživo", "HeaderNextUp": "Sljedeće je", @@ -34,23 +34,23 @@ "LabelRunningTimeValue": "Vrijeme rada: {0}", "Latest": "Najnovije", "MessageApplicationUpdated": "Jellyfin Server je ažuriran", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", + "MessageApplicationUpdatedTo": "Jellyfin Server je ažuriran na {0}", "MessageNamedServerConfigurationUpdatedWithValue": "Odjeljak postavka servera {0} je ažuriran", "MessageServerConfigurationUpdated": "Postavke servera su ažurirane", "MixedContent": "Miješani sadržaj", "Movies": "Filmovi", "Music": "Glazba", "MusicVideos": "Glazbeni spotovi", - "NameInstallFailed": "{0} installation failed", + "NameInstallFailed": "{0} neuspješnih instalacija", "NameSeasonNumber": "Sezona {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", + "NameSeasonUnknown": "Nepoznata sezona", + "NewVersionIsAvailable": "Nova verzija Jellyfin servera je dostupna za preuzimanje.", "NotificationOptionApplicationUpdateAvailable": "Dostupno ažuriranje aplikacije", "NotificationOptionApplicationUpdateInstalled": "Instalirano ažuriranje aplikacije", "NotificationOptionAudioPlayback": "Reprodukcija glazbe započeta", "NotificationOptionAudioPlaybackStopped": "Reprodukcija audiozapisa je zaustavljena", "NotificationOptionCameraImageUploaded": "Slike kamere preuzete", - "NotificationOptionInstallationFailed": "Instalacija nije izvršena", + "NotificationOptionInstallationFailed": "Instalacija neuspješna", "NotificationOptionNewLibraryContent": "Novi sadržaj je dodan", "NotificationOptionPluginError": "Dodatak otkazao", "NotificationOptionPluginInstalled": "Dodatak instaliran", @@ -62,7 +62,7 @@ "NotificationOptionVideoPlayback": "Reprodukcija videa započeta", "NotificationOptionVideoPlaybackStopped": "Reprodukcija videozapisa je zaustavljena", "Photos": "Slike", - "Playlists": "Popisi", + "Playlists": "Popis za reprodukciju", "Plugin": "Dodatak", "PluginInstalledWithName": "{0} je instalirano", "PluginUninstalledWithName": "{0} je deinstalirano", @@ -70,15 +70,15 @@ "ProviderValue": "Pružitelj: {0}", "ScheduledTaskFailedWithName": "{0} neuspjelo", "ScheduledTaskStartedWithName": "{0} pokrenuto", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", - "Shows": "Shows", + "ServerNameNeedsToBeRestarted": "{0} treba biti ponovno pokrenuto", + "Shows": "Serije", "Songs": "Pjesme", "StartupEmbyServerIsLoading": "Jellyfin Server se učitava. Pokušajte ponovo kasnije.", "SubtitleDownloadFailureForItem": "Titlovi prijevoda nisu preuzeti za {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", + "SubtitleDownloadFailureFromForItem": "Prijevodi nisu uspješno preuzeti {0} od {1}", "Sync": "Sink.", "System": "Sistem", - "TvShows": "TV Shows", + "TvShows": "Serije", "User": "Korisnik", "UserCreatedWithName": "Korisnik {0} je stvoren", "UserDeletedWithName": "Korisnik {0} je obrisan", @@ -87,10 +87,10 @@ "UserOfflineFromDevice": "{0} se odspojilo od {1}", "UserOnlineFromDevice": "{0} je online od {1}", "UserPasswordChangedWithName": "Lozinka je promijenjena za korisnika {0}", - "UserPolicyUpdatedWithName": "User policy has been updated for {0}", + "UserPolicyUpdatedWithName": "Pravila za korisnika su ažurirana za {0}", "UserStartedPlayingItemWithValues": "{0} je pokrenuo {1}", "UserStoppedPlayingItemWithValues": "{0} je zaustavio {1}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "ValueHasBeenAddedToLibrary": "{0} je dodano u medijsku biblioteku", "ValueSpecialEpisodeName": "Specijal - {0}", "VersionNumber": "Verzija {0}", "TaskRefreshLibraryDescription": "Skenira vašu medijsku knjižnicu sa novim datotekama i osvježuje metapodatke.", @@ -100,5 +100,19 @@ "TaskCleanCacheDescription": "Briše priručne datoteke nepotrebne za sistem.", "TaskCleanCache": "Očisti priručnu memoriju", "TasksApplicationCategory": "Aplikacija", - "TasksMaintenanceCategory": "Održavanje" + "TasksMaintenanceCategory": "Održavanje", + "TaskDownloadMissingSubtitlesDescription": "Pretraživanje interneta za prijevodima koji nedostaju bazirano na konfiguraciji meta podataka.", + "TaskDownloadMissingSubtitles": "Preuzimanje prijevoda koji nedostaju", + "TaskRefreshChannelsDescription": "Osvježava informacije o internet kanalima.", + "TaskRefreshChannels": "Osvježi kanale", + "TaskCleanTranscodeDescription": "Briše transkodirane fajlove starije od jednog dana.", + "TaskCleanTranscode": "Očisti direktorij za transkodiranje", + "TaskUpdatePluginsDescription": "Preuzima i instalira ažuriranja za dodatke koji su podešeni da se ažuriraju automatski.", + "TaskUpdatePlugins": "Ažuriraj dodatke", + "TaskRefreshPeopleDescription": "Ažurira meta podatke za glumce i redatelje u vašoj medijskoj biblioteci.", + "TaskRefreshPeople": "Osvježi ljude", + "TaskCleanLogsDescription": "Briši logove koji su stariji od {0} dana.", + "TaskCleanLogs": "Očisti direktorij sa logovima", + "TasksChannelsCategory": "Internet kanali", + "TasksLibraryCategory": "Biblioteka" } diff --git a/Emby.Server.Implementations/Localization/Core/ne.json b/Emby.Server.Implementations/Localization/Core/ne.json index 73fae3931..38c073709 100644 --- a/Emby.Server.Implementations/Localization/Core/ne.json +++ b/Emby.Server.Implementations/Localization/Core/ne.json @@ -58,5 +58,29 @@ "Books": "पुस्तकहरु", "Artists": "कलाकारहरू", "Application": "अनुप्रयोगहरू", - "Albums": "एल्बमहरू" + "Albums": "एल्बमहरू", + "TasksLibraryCategory": "पुस्तकालय", + "TasksApplicationCategory": "अनुप्रयोग", + "TasksMaintenanceCategory": "मर्मत", + "UserPolicyUpdatedWithName": "प्रयोगकर्ता नीति को लागी अद्यावधिक गरिएको छ {0}", + "UserPasswordChangedWithName": "पासवर्ड प्रयोगकर्ताका लागि परिवर्तन गरिएको छ {0}", + "UserOnlineFromDevice": "{0} बाट अनलाइन छ {1}", + "UserOfflineFromDevice": "{0} बाट विच्छेदन भएको छ {1}", + "UserLockedOutWithName": "प्रयोगकर्ता {0} लक गरिएको छ", + "UserDeletedWithName": "प्रयोगकर्ता {0} हटाइएको छ", + "UserCreatedWithName": "प्रयोगकर्ता {0} सिर्जना गरिएको छ", + "User": "प्रयोगकर्ता", + "PluginInstalledWithName": "", + "StartupEmbyServerIsLoading": "Jellyfin सर्भर लोड हुँदैछ। कृपया छिट्टै फेरि प्रयास गर्नुहोस्।", + "Songs": "गीतहरू", + "Shows": "शोहरू", + "ServerNameNeedsToBeRestarted": "{0} लाई पुन: सुरु गर्नु पर्छ", + "ScheduledTaskStartedWithName": "{0} सुरु भयो", + "ScheduledTaskFailedWithName": "{0} असफल", + "ProviderValue": "प्रदायक: {0}", + "Plugin": "प्लगइनहरू", + "Playlists": "प्लेलिस्टहरू", + "Photos": "तस्बिरहरु", + "NotificationOptionVideoPlaybackStopped": "भिडियो प्लेब्याक रोकियो", + "NotificationOptionVideoPlayback": "भिडियो प्लेब्याक सुरु भयो" } diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json index 25c5b9053..5365fff23 100644 --- a/Emby.Server.Implementations/Localization/Core/pt.json +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -101,7 +101,8 @@ "TaskCleanLogsDescription": "Deletar arquivos de log que existe a mais de {0} dias.", "TaskCleanLogs": "Limpar diretório de log", "TaskRefreshLibrary": "Escanear biblioteca de mídias", - "TaskRefreshChapterImagesDescription": "Criar miniaturas para videos que tem capítulos.", - "TaskCleanCacheDescription": "Deletar arquivos de cache que não são mais usados pelo sistema.", - "TasksChannelsCategory": "Canais de Internet" + "TaskRefreshChapterImagesDescription": "Cria miniaturas para vídeos que têm capítulos.", + "TaskCleanCacheDescription": "Apaga ficheiros em cache que já não são usados pelo sistema.", + "TasksChannelsCategory": "Canais de Internet", + "TaskRefreshChapterImages": "Extrair Imagens do Capítulo" } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 80326fddf..146ebaf25 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 using System; -using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; @@ -17,11 +16,10 @@ using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Model.Events; using MediaBrowser.Model.IO; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Updates; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Updates @@ -32,11 +30,6 @@ namespace Emby.Server.Implementations.Updates public class InstallationManager : IInstallationManager { /// <summary> - /// The key for a setting that specifies a URL for the plugin repository JSON manifest. - /// </summary> - public const string PluginManifestUrlKey = "InstallationManager:PluginManifestUrl"; - - /// <summary> /// The logger. /// </summary> private readonly ILogger<InstallationManager> _logger; @@ -53,7 +46,6 @@ namespace Emby.Server.Implementations.Updates private readonly IApplicationHost _applicationHost; private readonly IZipClient _zipClient; - private readonly IConfiguration _appConfig; private readonly object _currentInstallationsLock = new object(); @@ -75,8 +67,7 @@ namespace Emby.Server.Implementations.Updates IJsonSerializer jsonSerializer, IServerConfigurationManager config, IFileSystem fileSystem, - IZipClient zipClient, - IConfiguration appConfig) + IZipClient zipClient) { if (logger == null) { @@ -94,7 +85,6 @@ namespace Emby.Server.Implementations.Updates _config = config; _fileSystem = fileSystem; _zipClient = zipClient; - _appConfig = appConfig; } /// <inheritdoc /> @@ -122,16 +112,14 @@ namespace Emby.Server.Implementations.Updates public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal; /// <inheritdoc /> - public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default) + public async Task<IReadOnlyList<PackageInfo>> GetPackages(string manifest, CancellationToken cancellationToken = default) { - var manifestUrl = _appConfig.GetValue<string>(PluginManifestUrlKey); - try { using (var response = await _httpClient.SendAsync( new HttpRequestOptions { - Url = manifestUrl, + Url = manifest, CancellationToken = cancellationToken, CacheMode = CacheMode.Unconditional, CacheLength = TimeSpan.FromMinutes(3) @@ -145,23 +133,33 @@ namespace Emby.Server.Implementations.Updates } catch (SerializationException ex) { - const string LogTemplate = - "Failed to deserialize the plugin manifest retrieved from {PluginManifestUrl}. If you " + - "have specified a custom plugin repository manifest URL with --plugin-manifest-url or " + - PluginManifestUrlKey + ", please ensure that it is correct."; - _logger.LogError(ex, LogTemplate, manifestUrl); - throw; + _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest); + return Array.Empty<PackageInfo>(); } } } catch (UriFormatException ex) { - const string LogTemplate = - "The URL configured for the plugin repository manifest URL is not valid: {PluginManifestUrl}. " + - "Please check the URL configured by --plugin-manifest-url or " + PluginManifestUrlKey; - _logger.LogError(ex, LogTemplate, manifestUrl); - throw; + _logger.LogError(ex, "The URL configured for the plugin repository manifest URL is not valid: {Manifest}", manifest); + return Array.Empty<PackageInfo>(); + } + catch (HttpException ex) + { + _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest); + return Array.Empty<PackageInfo>(); + } + } + + /// <inheritdoc /> + public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default) + { + var result = new List<PackageInfo>(); + foreach (RepositoryInfo repository in _config.Configuration.PluginRepositories) + { + result.AddRange(await GetPackages(repository.Url, cancellationToken).ConfigureAwait(true)); } + + return result; } /// <inheritdoc /> @@ -402,6 +400,12 @@ namespace Emby.Server.Implementations.Updates /// <param name="plugin">The plugin.</param> public void UninstallPlugin(IPlugin plugin) { + if (!plugin.CanUninstall) + { + _logger.LogWarning("Attempt to delete non removable plugin {0}, ignoring request", plugin.Name); + return; + } + plugin.OnUninstalling(); // Remove it the quick way for now |
