From 8a15ad160b30769305b5cf03e16b3cec742156de Mon Sep 17 00:00:00 2001 From: Patrick Barron Date: Sat, 5 Sep 2020 18:58:16 -0400 Subject: Fix plugin events not being called and clean up InstallationManager.cs --- .../Updates/InstallationManager.cs | 66 +++++++--------------- 1 file changed, 19 insertions(+), 47 deletions(-) (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index f121a3493..ac3caf83e 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -10,12 +10,15 @@ using System.Runtime.Serialization; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Data.Events; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Configuration; +using MediaBrowser.Controller.Events; +using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -34,6 +37,7 @@ namespace Emby.Server.Implementations.Updates /// private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; + private readonly IEventManager _eventManager; private readonly IHttpClientFactory _httpClientFactory; private readonly IJsonSerializer _jsonSerializer; private readonly IServerConfigurationManager _config; @@ -63,23 +67,20 @@ namespace Emby.Server.Implementations.Updates ILogger logger, IApplicationHost appHost, IApplicationPaths appPaths, + IEventManager eventManager, IHttpClientFactory httpClientFactory, IJsonSerializer jsonSerializer, IServerConfigurationManager config, IFileSystem fileSystem, IZipClient zipClient) { - if (logger == null) - { - throw new ArgumentNullException(nameof(logger)); - } - _currentInstallations = new List<(InstallationInfo, CancellationTokenSource)>(); _completedInstallationsInternal = new ConcurrentBag(); _logger = logger; _applicationHost = appHost; _appPaths = appPaths; + _eventManager = eventManager; _httpClientFactory = httpClientFactory; _jsonSerializer = jsonSerializer; _config = config; @@ -87,27 +88,6 @@ namespace Emby.Server.Implementations.Updates _zipClient = zipClient; } - /// - public event EventHandler PackageInstalling; - - /// - public event EventHandler PackageInstallationCompleted; - - /// - public event EventHandler PackageInstallationFailed; - - /// - public event EventHandler PackageInstallationCancelled; - - /// - public event EventHandler PluginUninstalled; - - /// - public event EventHandler PluginUpdated; - - /// - public event EventHandler PluginInstalled; - /// public IEnumerable CompletedInstallations => _completedInstallationsInternal; @@ -256,11 +236,11 @@ namespace Emby.Server.Implementations.Updates var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; - PackageInstalling?.Invoke(this, package); + await _eventManager.PublishAsync(new PluginInstallingEventArgs(package)).ConfigureAwait(false); try { - await InstallPackageInternal(package, linkedToken).ConfigureAwait(false); + var isUpdate = await InstallPackageInternal(package, linkedToken).ConfigureAwait(false); lock (_currentInstallationsLock) { @@ -268,8 +248,11 @@ namespace Emby.Server.Implementations.Updates } _completedInstallationsInternal.Add(package); + await _eventManager.PublishAsync(isUpdate + ? (GenericEventArgs)new PluginUpdatedEventArgs(package) + : new PluginInstalledEventArgs(package)).ConfigureAwait(false); - PackageInstallationCompleted?.Invoke(this, package); + _applicationHost.NotifyPendingRestart(); } catch (OperationCanceledException) { @@ -280,7 +263,7 @@ namespace Emby.Server.Implementations.Updates _logger.LogInformation("Package installation cancelled: {0} {1}", package.Name, package.Version); - PackageInstallationCancelled?.Invoke(this, package); + await _eventManager.PublishAsync(new PluginInstallationCancelledEventArgs(package)).ConfigureAwait(false); throw; } @@ -293,11 +276,11 @@ namespace Emby.Server.Implementations.Updates _currentInstallations.Remove(tuple); } - PackageInstallationFailed?.Invoke(this, new InstallationFailedEventArgs + await _eventManager.PublishAsync(new InstallationFailedEventArgs { InstallationInfo = package, Exception = ex - }); + }).ConfigureAwait(false); throw; } @@ -314,7 +297,7 @@ namespace Emby.Server.Implementations.Updates /// The package. /// The cancellation token. /// . - private async Task InstallPackageInternal(InstallationInfo package, CancellationToken cancellationToken) + private async Task InstallPackageInternal(InstallationInfo package, CancellationToken cancellationToken) { // Set last update time if we were installed before IPlugin plugin = _applicationHost.Plugins.FirstOrDefault(p => p.Id == package.Guid) @@ -324,20 +307,9 @@ namespace Emby.Server.Implementations.Updates await PerformPackageInstallation(package, cancellationToken).ConfigureAwait(false); // Do plugin-specific processing - if (plugin == null) - { - _logger.LogInformation("New plugin installed: {0} {1}", package.Name, package.Version); - - PluginInstalled?.Invoke(this, package); - } - else - { - _logger.LogInformation("Plugin updated: {0} {1}", package.Name, package.Version); + _logger.LogInformation(plugin == null ? "New plugin installed: {0} {1}" : "Plugin updated: {0} {1}", package.Name, package.Version); - PluginUpdated?.Invoke(this, package); - } - - _applicationHost.NotifyPendingRestart(); + return plugin != null; } private async Task PerformPackageInstallation(InstallationInfo package, CancellationToken cancellationToken) @@ -438,7 +410,7 @@ namespace Emby.Server.Implementations.Updates _config.SaveConfiguration(); } - PluginUninstalled?.Invoke(this, plugin); + _eventManager.Publish(new PluginUninstalledEventArgs(plugin)); _applicationHost.NotifyPendingRestart(); } -- cgit v1.2.3 From 53d8023defe19ef943f72964d93dbed40b6f1180 Mon Sep 17 00:00:00 2001 From: crobibero Date: Wed, 30 Sep 2020 17:37:30 -0600 Subject: Update all on-disk plugins --- Emby.Server.Implementations/ApplicationHost.cs | 94 +++++++---------- .../Updates/InstallationManager.cs | 10 +- MediaBrowser.Common/Plugins/LocalPlugin.cs | 113 +++++++++++++++++++++ MediaBrowser.Controller/IServerApplicationHost.cs | 10 +- 4 files changed, 162 insertions(+), 65 deletions(-) create mode 100644 MediaBrowser.Common/Plugins/LocalPlugin.cs (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7a46fdf2e..984ab41f0 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Net; @@ -30,7 +29,6 @@ using Emby.Server.Implementations.Cryptography; using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Devices; using Emby.Server.Implementations.Dto; -using Emby.Server.Implementations.HttpServer; using Emby.Server.Implementations.HttpServer.Security; using Emby.Server.Implementations.IO; using Emby.Server.Implementations.Library; @@ -258,8 +256,8 @@ namespace Emby.Server.Implementations IServiceCollection serviceCollection) { _xmlSerializer = new MyXmlSerializer(); - _jsonSerializer = new JsonSerializer(); - + _jsonSerializer = new JsonSerializer(); + ServiceCollection = serviceCollection; _networkManager = networkManager; @@ -1026,80 +1024,54 @@ namespace Emby.Server.Implementations protected abstract void RestartInternal(); - /// - /// Comparison function used in . - /// - /// Item to compare. - /// Item to compare with. - /// Boolean result of the operation. - private static int VersionCompare( - (Version PluginVersion, string Name, string Path) a, - (Version PluginVersion, string Name, string Path) b) - { - int compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture); - - if (compare == 0) - { - return a.PluginVersion.CompareTo(b.PluginVersion); - } - - return compare; - } - - /// - /// Returns a list of plugins to install. - /// - /// Path to check. - /// True if an attempt should be made to delete old plugs. - /// Enumerable list of dlls to load. - private IEnumerable GetPlugins(string path, bool cleanup = true) + /// + public IEnumerable GetLocalPlugins(string path, bool cleanup = true) { - var dllList = new List(); - var versions = new List<(Version PluginVersion, string Name, string Path)>(); + var minimumVersion = new Version(0, 0, 0, 1); + var versions = new List(); var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly); - string metafile; foreach (var dir in directories) { try { - metafile = Path.Combine(dir, "meta.json"); + var metafile = Path.Combine(dir, "meta.json"); if (File.Exists(metafile)) { var manifest = _jsonSerializer.DeserializeFromFile(metafile); if (!Version.TryParse(manifest.TargetAbi, out var targetAbi)) { - targetAbi = new Version(0, 0, 0, 1); + targetAbi = minimumVersion; } if (!Version.TryParse(manifest.Version, out var version)) { - version = new Version(0, 0, 0, 1); + version = minimumVersion; } if (ApplicationVersion >= targetAbi) { // Only load Plugins if the plugin is built for this version or below. - versions.Add((version, manifest.Name, dir)); + versions.Add(new LocalPlugin(manifest.Guid, manifest.Name, version, dir)); } } else { // No metafile, so lets see if the folder is versioned. metafile = dir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)[^1]; - + int versionIndex = dir.LastIndexOf('_'); - if (versionIndex != -1 && Version.TryParse(dir.Substring(versionIndex + 1), out Version ver)) + if (versionIndex != -1 && Version.TryParse(dir.Substring(versionIndex + 1), out Version parsedVersion)) { // Versioned folder. - versions.Add((ver, metafile, dir)); + versions.Add(new LocalPlugin(Guid.Empty, metafile, parsedVersion, dir)); } else { - // Un-versioned folder - Add it under the path name and version 0.0.0.1. - versions.Add((new Version(0, 0, 0, 1), metafile, dir)); - } + // Un-versioned folder - Add it under the path name and version 0.0.0.1. + versions.Add(new LocalPlugin(Guid.Empty, metafile, minimumVersion, dir)); + } } } catch @@ -1109,14 +1081,14 @@ namespace Emby.Server.Implementations } string lastName = string.Empty; - versions.Sort(VersionCompare); + versions.Sort(LocalPlugin.Compare); // Traverse backwards through the list. // The first item will be the latest version. for (int x = versions.Count - 1; x >= 0; x--) { if (!string.Equals(lastName, versions[x].Name, StringComparison.OrdinalIgnoreCase)) { - dllList.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories)); + versions[x].DllFiles.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories)); lastName = versions[x].Name; continue; } @@ -1124,6 +1096,7 @@ namespace Emby.Server.Implementations if (!string.IsNullOrEmpty(lastName) && cleanup) { // Attempt a cleanup of old folders. + versions.RemoveAt(x); try { Logger.LogDebug("Deleting {Path}", versions[x].Path); @@ -1136,7 +1109,7 @@ namespace Emby.Server.Implementations } } - return dllList; + return versions; } /// @@ -1147,21 +1120,24 @@ namespace Emby.Server.Implementations { if (Directory.Exists(ApplicationPaths.PluginsPath)) { - foreach (var file in GetPlugins(ApplicationPaths.PluginsPath)) + foreach (var plugin in GetLocalPlugins(ApplicationPaths.PluginsPath)) { - Assembly plugAss; - try + foreach (var file in plugin.DllFiles) { - plugAss = Assembly.LoadFrom(file); - } - catch (FileLoadException ex) - { - Logger.LogError(ex, "Failed to load assembly {Path}", file); - continue; - } + Assembly plugAss; + try + { + plugAss = Assembly.LoadFrom(file); + } + catch (FileLoadException ex) + { + Logger.LogError(ex, "Failed to load assembly {Path}", file); + continue; + } - Logger.LogInformation("Loaded assembly {Assembly} from {Path}", plugAss.FullName, file); - yield return plugAss; + Logger.LogInformation("Loaded assembly {Assembly} from {Path}", plugAss.FullName, file); + yield return plugAss; + } } } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 003cf3c74..365d89065 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -15,14 +15,13 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; -using MediaBrowser.Common.System; +using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.IO; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Updates; using Microsoft.Extensions.Logging; -using MediaBrowser.Model.System; namespace Emby.Server.Implementations.Updates { @@ -45,7 +44,7 @@ namespace Emby.Server.Implementations.Updates /// Gets the application host. /// /// The application host. - private readonly IApplicationHost _applicationHost; + private readonly IServerApplicationHost _applicationHost; private readonly IZipClient _zipClient; @@ -63,7 +62,7 @@ namespace Emby.Server.Implementations.Updates public InstallationManager( ILogger logger, - IApplicationHost appHost, + IServerApplicationHost appHost, IApplicationPaths appPaths, IHttpClientFactory httpClientFactory, IJsonSerializer jsonSerializer, @@ -237,7 +236,8 @@ namespace Emby.Server.Implementations.Updates private IEnumerable GetAvailablePluginUpdates(IReadOnlyList pluginCatalog) { - foreach (var plugin in _applicationHost.Plugins) + var plugins = _applicationHost.GetLocalPlugins(_appPaths.PluginsPath); + foreach (var plugin in plugins) { var compatibleVersions = GetCompatibleVersions(pluginCatalog, plugin.Name, plugin.Id, minVersion: plugin.Version); var version = compatibleVersions.FirstOrDefault(y => y.Version > plugin.Version); diff --git a/MediaBrowser.Common/Plugins/LocalPlugin.cs b/MediaBrowser.Common/Plugins/LocalPlugin.cs new file mode 100644 index 000000000..e26631615 --- /dev/null +++ b/MediaBrowser.Common/Plugins/LocalPlugin.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Globalization; + +namespace MediaBrowser.Common.Plugins +{ + /// + /// Local plugin struct. + /// + public readonly struct LocalPlugin : IEquatable + { + /// + /// Initializes a new instance of the struct. + /// + /// The plugin id. + /// The plugin name. + /// The plugin version. + /// The plugin path. + public LocalPlugin(Guid id, string name, Version version, string path) + { + Id = id; + Name = name; + Version = version; + Path = path; + DllFiles = new List(); + } + + /// + /// Gets the plugin id. + /// + public Guid Id { get; } + + /// + /// Gets the plugin name. + /// + public string Name { get; } + + /// + /// Gets the plugin version. + /// + public Version Version { get; } + + /// + /// Gets the plugin path. + /// + public string Path { get; } + + /// + /// Gets the list of dll files for this plugin. + /// + public List DllFiles { get; } + + /// + /// == operator. + /// + /// Left item. + /// Right item. + /// Comparison result. + public static bool operator ==(LocalPlugin left, LocalPlugin right) + { + return left.Equals(right); + } + + /// + /// != operator. + /// + /// Left item. + /// Right item. + /// Comparison result. + public static bool operator !=(LocalPlugin left, LocalPlugin right) + { + return !(left == right); + } + + /// + /// Compare two . + /// + /// The first item. + /// The second item. + /// Comparison result. + public static int Compare(LocalPlugin a, LocalPlugin b) + { + var compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture); + + // Id is not equal but name is. + if (a.Id != b.Id && compare == 0) + { + compare = a.Id.CompareTo(b.Id); + } + + return compare == 0 ? a.Version.CompareTo(b.Version) : compare; + } + + /// + public override bool Equals(object obj) + { + return obj is LocalPlugin other && this.Equals(other); + } + + /// + public override int GetHashCode() + { + return Name.GetHashCode(StringComparison.OrdinalIgnoreCase); + } + + /// + public bool Equals(LocalPlugin other) + { + return Name.Equals(other.Name, StringComparison.OrdinalIgnoreCase) + && Id.Equals(other.Id); + } + } +} diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index cfad17fb7..8a55437c5 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -6,8 +6,8 @@ using System.Net; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; +using MediaBrowser.Common.Plugins; using MediaBrowser.Model.System; -using Microsoft.AspNetCore.Http; namespace MediaBrowser.Controller { @@ -119,5 +119,13 @@ namespace MediaBrowser.Controller string ExpandVirtualPath(string path); string ReverseVirtualPath(string path); + + /// + /// Gets the list of local plugins. + /// + /// Plugin base directory. + /// Cleanup old plugins. + /// Enumerable of local plugins. + IEnumerable GetLocalPlugins(string path, bool cleanup = true); } } -- cgit v1.2.3 From 95a2de757f8142fed4ef19b71ac2d483fa152674 Mon Sep 17 00:00:00 2001 From: crobibero Date: Sat, 14 Nov 2020 14:30:34 -0700 Subject: remove custom HttpException --- .../Library/LibraryManager.cs | 3 +- .../LiveTv/Listings/SchedulesDirect.cs | 6 ++-- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 4 +-- .../ScheduledTasks/Tasks/PluginUpdateTask.cs | 3 +- .../Updates/InstallationManager.cs | 5 --- MediaBrowser.Model/Net/HttpException.cs | 42 ---------------------- .../Manager/ItemImageProvider.cs | 5 +-- MediaBrowser.Providers/Manager/ProviderManager.cs | 10 ++---- 8 files changed, 14 insertions(+), 64 deletions(-) delete mode 100644 MediaBrowser.Model/Net/HttpException.cs (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index f16eda1ec..e7cf05496 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Emby.Naming.Audio; @@ -2907,7 +2908,7 @@ namespace Emby.Server.Implementations.Library return item.GetImageInfo(image.Type, imageIndex); } - catch (HttpException ex) + catch (HttpRequestException ex) { if (ex.StatusCode.HasValue && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden)) diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index aacadde50..43128c60d 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -591,7 +591,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings savedToken.Value = DateTime.UtcNow.Ticks.ToString(CultureInfo.InvariantCulture); return result; } - catch (HttpException ex) + catch (HttpRequestException ex) { if (ex.StatusCode.HasValue) { @@ -621,7 +621,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { return await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, completionOption, cancellationToken).ConfigureAwait(false); } - catch (HttpException ex) + catch (HttpRequestException ex) { _tokens.Clear(); @@ -711,7 +711,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase)); } - catch (HttpException ex) + catch (HttpRequestException ex) { // Apparently we're supposed to swallow this if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.BadRequest) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 2f4c60117..9fdbad63c 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun return discoverResponse; } - catch (HttpException ex) + catch (HttpRequestException ex) { if (!throwAllExceptions && ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound) { @@ -663,7 +663,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var modelInfo = await GetModelInfo(info, true, CancellationToken.None).ConfigureAwait(false); info.DeviceId = modelInfo.DeviceID; } - catch (HttpException ex) + catch (HttpRequestException ex) { if (ex.StatusCode.HasValue && ex.StatusCode.Value == System.Net.HttpStatusCode.NotFound) { diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs index c5af68bce..161fa0580 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Updates; @@ -101,7 +102,7 @@ namespace Emby.Server.Implementations.ScheduledTasks throw; } } - catch (HttpException ex) + catch (HttpRequestException ex) { _logger.LogError(ex, "Error downloading {0}", package.Name); } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index fd1f43e62..6b6b8c4fe 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -116,11 +116,6 @@ namespace Emby.Server.Implementations.Updates _logger.LogError(ex, "The URL configured for the plugin repository manifest URL is not valid: {Manifest}", manifest); return Array.Empty(); } - catch (HttpException ex) - { - _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest); - return Array.Empty(); - } catch (HttpRequestException ex) { _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest); diff --git a/MediaBrowser.Model/Net/HttpException.cs b/MediaBrowser.Model/Net/HttpException.cs deleted file mode 100644 index 48ff5d51c..000000000 --- a/MediaBrowser.Model/Net/HttpException.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Net; - -namespace MediaBrowser.Model.Net -{ - /// - /// Class HttpException. - /// - public class HttpException : Exception - { - /// - /// Gets or sets the status code. - /// - /// The status code. - public HttpStatusCode? StatusCode { get; set; } - - /// - /// Gets or sets a value indicating whether this instance is timed out. - /// - /// true if this instance is timed out; otherwise, false. - public bool IsTimedOut { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The message. - /// The inner exception. - public HttpException(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message. - public HttpException(string message) - : base(message) - { - } - } -} diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index a57a85376..39748171a 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; @@ -481,7 +482,7 @@ namespace MediaBrowser.Providers.Manager result.UpdateType |= ItemUpdateType.ImageUpdate; return true; } - catch (HttpException ex) + catch (HttpRequestException ex) { // Sometimes providers send back bad url's. Just move to the next image if (ex.StatusCode.HasValue @@ -595,7 +596,7 @@ namespace MediaBrowser.Providers.Manager cancellationToken).ConfigureAwait(false); result.UpdateType = result.UpdateType | ItemUpdateType.ImageUpdate; } - catch (HttpException ex) + catch (HttpRequestException ex) { // Sometimes providers send back bad urls. Just move onto the next image if (ex.StatusCode.HasValue diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index a0c7d4ad0..7a1b7bb2c 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -160,10 +160,7 @@ namespace MediaBrowser.Providers.Manager if (response.StatusCode != HttpStatusCode.OK) { - throw new HttpException("Invalid image received.") - { - StatusCode = response.StatusCode - }; + throw new HttpRequestException("Invalid image received.", null, response.StatusCode); } var contentType = response.Content.Headers.ContentType.MediaType; @@ -181,10 +178,7 @@ namespace MediaBrowser.Providers.Manager // thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons... if (contentType.Equals(MediaTypeNames.Text.Html, StringComparison.OrdinalIgnoreCase)) { - throw new HttpException("Invalid image received.") - { - StatusCode = HttpStatusCode.NotFound - }; + throw new HttpRequestException("Invalid image received.", null, HttpStatusCode.NotFound); } await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); -- cgit v1.2.3 From 4b1c9dc9eaa120a30a7820257a83dd5aa3ecd9f4 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 17 Nov 2020 19:43:00 +0100 Subject: Pass cancellation where possible --- Emby.Dlna/PlayTo/SsdpHttpClient.cs | 4 ++-- Emby.Server.Implementations/ApplicationHost.cs | 2 +- Emby.Server.Implementations/Data/SqliteExtensions.cs | 14 -------------- .../LiveTv/EmbyTV/DirectRecorder.cs | 7 ++++--- .../LiveTv/Listings/SchedulesDirect.cs | 18 +++++++++--------- .../LiveTv/Listings/XmlTvListingsProvider.cs | 2 +- .../LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs | 6 +++--- .../LiveTv/TunerHosts/M3uParser.cs | 2 +- .../LiveTv/TunerHosts/SharedHttpStream.cs | 2 +- .../Updates/InstallationManager.cs | 7 ++++--- Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs | 6 ++++-- .../Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Providers/Manager/ItemImageProvider.cs | 4 ++-- MediaBrowser.Providers/Manager/ProviderManager.cs | 2 +- .../Plugins/AudioDb/AlbumProvider.cs | 2 +- .../Plugins/AudioDb/ArtistProvider.cs | 2 +- .../Plugins/MusicBrainz/ArtistProvider.cs | 6 +++--- .../Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs | 10 +++++----- .../Plugins/Omdb/OmdbItemProvider.cs | 2 +- MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs | 4 ++-- 20 files changed, 47 insertions(+), 57 deletions(-) (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Dlna/PlayTo/SsdpHttpClient.cs b/Emby.Dlna/PlayTo/SsdpHttpClient.cs index c8c36fc97..f4d793790 100644 --- a/Emby.Dlna/PlayTo/SsdpHttpClient.cs +++ b/Emby.Dlna/PlayTo/SsdpHttpClient.cs @@ -45,7 +45,7 @@ namespace Emby.Dlna.PlayTo header, cancellationToken) .ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var reader = new StreamReader(stream, Encoding.UTF8); return XDocument.Parse( await reader.ReadToEndAsync().ConfigureAwait(false), @@ -94,7 +94,7 @@ namespace Emby.Dlna.PlayTo options.Headers.UserAgent.ParseAdd(USERAGENT); options.Headers.TryAddWithoutValidation("FriendlyName.DLNA.ORG", FriendlyName); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var reader = new StreamReader(stream, Encoding.UTF8); return XDocument.Parse( await reader.ReadToEndAsync().ConfigureAwait(false), diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ad3c19618..17b99c858 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -1378,7 +1378,7 @@ namespace Emby.Server.Implementations using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var result = await System.Text.Json.JsonSerializer.DeserializeAsync(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false); var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase); diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs index 70a6df977..1af301ceb 100644 --- a/Emby.Server.Implementations/Data/SqliteExtensions.cs +++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs @@ -107,20 +107,6 @@ namespace Emby.Server.Implementations.Data return null; } - public static void Attach(SQLiteDatabaseConnection db, string path, string alias) - { - var commandText = string.Format( - CultureInfo.InvariantCulture, - "attach @path as {0};", - alias); - - using (var statement = db.PrepareStatement(commandText)) - { - statement.TryBind("@path", path); - statement.MoveNext(); - } - } - public static bool IsDBNull(this IReadOnlyList result, int index) { return result[index].SQLiteType == SQLiteType.Null; diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 44560d1e2..341194f23 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -77,11 +77,12 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV _logger.LogInformation("Copying recording stream to file {0}", targetFile); // The media source if infinite so we need to handle stopping ourselves - var durationToken = new CancellationTokenSource(duration); - cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token).Token; + using var durationToken = new CancellationTokenSource(duration); + using var linkedCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, durationToken.Token); + cancellationToken = linkedCancellationToken.Token; await _streamHelper.CopyUntilCancelled( - await response.Content.ReadAsStreamAsync().ConfigureAwait(false), + await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), output, IODefaults.CopyToBufferSize, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 43128c60d..91f7c7931 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Content = new StringContent(requestString, Encoding.UTF8, MediaTypeNames.Application.Json); options.Headers.TryAddWithoutValidation("token", token); using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false); - await using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var dailySchedules = await _jsonSerializer.DeserializeFromStreamAsync>(responseStream).ConfigureAwait(false); _logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId); @@ -123,7 +123,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings programRequestOptions.Content = new StringContent("[\"" + string.Join("\", \"", programsID) + "\"]", Encoding.UTF8, MediaTypeNames.Application.Json); using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false); - await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var programDetails = await _jsonSerializer.DeserializeFromStreamAsync>(innerResponseStream).ConfigureAwait(false); var programDict = programDetails.ToDictionary(p => p.programID, y => y); @@ -480,9 +480,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings try { using var innerResponse2 = await Send(message, true, info, cancellationToken).ConfigureAwait(false); - await using var response = await innerResponse2.Content.ReadAsStreamAsync().ConfigureAwait(false); - return await _jsonSerializer.DeserializeFromStreamAsync>( - response).ConfigureAwait(false); + await using var response = await innerResponse2.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); + return await _jsonSerializer.DeserializeFromStreamAsync>(response).ConfigureAwait(false); } catch (Exception ex) { @@ -509,7 +508,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings try { using var httpResponse = await Send(options, false, info, cancellationToken).ConfigureAwait(false); - await using var response = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var response = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync>(response).ConfigureAwait(false); @@ -542,6 +541,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary(); private DateTime _lastErrorResponse; + private async Task GetToken(ListingsProviderInfo info, CancellationToken cancellationToken) { var username = info.Username; @@ -651,7 +651,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + hashedPassword + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); if (root.message == "OK") { @@ -705,7 +705,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings try { using var httpResponse = await Send(options, false, null, cancellationToken).ConfigureAwait(false); - await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var response = httpResponse.Content; var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); @@ -780,7 +780,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings var list = new List(); using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false); - await using var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var root = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); _logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count); _logger.LogInformation("Mapping Stations to Channel"); diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 2d6f453bd..76c875737 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -79,7 +79,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings Directory.CreateDirectory(Path.GetDirectoryName(cacheFile)); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(path, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using (var fileStream = new FileStream(cacheFile, FileMode.CreateNew)) { await stream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs index 9fdbad63c..c0a4d1228 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs @@ -72,7 +72,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun var model = await GetModelInfo(info, false, cancellationToken).ConfigureAwait(false); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(model.LineupURL, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var lineup = await JsonSerializer.DeserializeAsync>(stream, cancellationToken: cancellationToken) .ConfigureAwait(false) ?? new List(); @@ -129,7 +129,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/discover.json", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken) .ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var discoverResponse = await JsonSerializer.DeserializeAsync(stream, cancellationToken: cancellationToken) .ConfigureAwait(false); @@ -175,7 +175,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(string.Format(CultureInfo.InvariantCulture, "{0}/tuners.html", GetApiUrl(info)), HttpCompletionOption.ResponseHeadersRead, cancellationToken) .ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var sr = new StreamReader(stream, System.Text.Encoding.UTF8); var tuners = new List(); while (!sr.EndOfStream) diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs index 7c13d45e9..6ea1e1dd7 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs @@ -63,7 +63,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts .SendAsync(requestMessage, cancellationToken) .ConfigureAwait(false); response.EnsureSuccessStatusCode(); - return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); } return File.OpenRead(info.Url); diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 2e1b89509..2de447ad9 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -135,7 +135,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts { Logger.LogInformation("Beginning {0} stream to {1}", GetType().Name, TempFilePath); using var message = response; - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using var fileStream = new FileStream(TempFilePath, FileMode.Create, FileAccess.Write, FileShare.Read); await StreamHelper.CopyToAsync( stream, diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 6b6b8c4fe..851e7bd68 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -99,7 +99,7 @@ namespace Emby.Server.Implementations.Updates { using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(manifest, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); try { @@ -241,7 +241,8 @@ namespace Emby.Server.Implementations.Updates _currentInstallations.Add(tuple); } - var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; + using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token); + var linkedToken = linkedTokenSource.Token; await _eventManager.PublishAsync(new PluginInstallingEventArgs(package)).ConfigureAwait(false); @@ -333,7 +334,7 @@ namespace Emby.Server.Implementations.Updates using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(package.SourceUrl, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // CA5351: Do Not Use Broken Cryptographic Algorithms #pragma warning disable CA5351 diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs index 20c94cdda..cfa2c1229 100644 --- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs +++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs @@ -24,12 +24,14 @@ namespace Jellyfin.Api.Helpers /// Whether the current request is a HTTP HEAD request so only the headers get returned. /// The making the remote request. /// The current http context. + /// A cancellation token that can be used to cancel the operation. /// A containing the API response. public static async Task GetStaticRemoteStreamResult( StreamState state, bool isHeadRequest, HttpClient httpClient, - HttpContext httpContext) + HttpContext httpContext, + CancellationToken cancellationToken = default) { if (state.RemoteHttpHeaders.TryGetValue(HeaderNames.UserAgent, out var useragent)) { @@ -47,7 +49,7 @@ namespace Jellyfin.Api.Helpers return new FileContentResult(Array.Empty(), contentType); } - return new FileStreamResult(await response.Content.ReadAsStreamAsync().ConfigureAwait(false), contentType); + return new FileStreamResult(await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false), contentType); } /// diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 8b3c6b2e6..b61b8a0e0 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -760,7 +760,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles using var response = await _httpClientFactory.CreateClient(NamedClient.Default) .GetAsync(new Uri(path), cancellationToken) .ConfigureAwait(false); - return await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); } case MediaProtocol.File: diff --git a/MediaBrowser.Providers/Manager/ItemImageProvider.cs b/MediaBrowser.Providers/Manager/ItemImageProvider.cs index 39748171a..ffc6889fa 100644 --- a/MediaBrowser.Providers/Manager/ItemImageProvider.cs +++ b/MediaBrowser.Providers/Manager/ItemImageProvider.cs @@ -469,7 +469,7 @@ namespace MediaBrowser.Providers.Manager try { using var response = await provider.GetImageResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage( item, @@ -586,7 +586,7 @@ namespace MediaBrowser.Providers.Manager } } - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await _providerManager.SaveImage( item, stream, diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 7a1b7bb2c..58ca88a5b 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -181,7 +181,7 @@ namespace MediaBrowser.Providers.Manager throw new HttpRequestException("Invalid image received.", null, HttpStatusCode.NotFound); } - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await SaveImage( item, stream, diff --git a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs index e6d89e688..6536b303f 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/AlbumProvider.cs @@ -175,7 +175,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb Directory.CreateDirectory(Path.GetDirectoryName(path)); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); await using var xmlFileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, IODefaults.FileStreamBufferSize, true); await stream.CopyToAsync(xmlFileStream, cancellationToken).ConfigureAwait(false); } diff --git a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs index 72dad8a25..85c92fa7b 100644 --- a/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/AudioDb/ArtistProvider.cs @@ -156,7 +156,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb var path = GetArtistInfoPath(_config.ApplicationPaths, musicBrainzId); using var response = await _httpClientFactory.CreateClient(NamedClient.Default).GetAsync(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs index f27da7ce6..dc755b600 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.Music var url = "/ws/2/artist/?query=arid:{0}" + musicBrainzId.ToString(CultureInfo.InvariantCulture); using var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); return GetResultsFromResponse(stream); } else @@ -49,7 +49,7 @@ namespace MediaBrowser.Providers.Music var url = string.Format(CultureInfo.InvariantCulture, "/ws/2/artist/?query=\"{0}\"&dismax=true", UrlEncode(nameToSearch)); using (var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false)) - await using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + await using (var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false)) { var results = GetResultsFromResponse(stream).ToList(); @@ -65,7 +65,7 @@ namespace MediaBrowser.Providers.Music url = string.Format(CultureInfo.InvariantCulture, "/ws/2/artist/?query=artistaccent:\"{0}\"", UrlEncode(nameToSearch)); using var response = await MusicBrainzAlbumProvider.Current.GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); return GetResultsFromResponse(stream); } } diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs index 31f0123dc..93178d64a 100644 --- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs @@ -125,7 +125,7 @@ namespace MediaBrowser.Providers.Music if (!string.IsNullOrWhiteSpace(url)) { using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); return GetResultsFromResponse(stream); } @@ -284,7 +284,7 @@ namespace MediaBrowser.Providers.Music artistId); using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var oReader = new StreamReader(stream, Encoding.UTF8); var settings = new XmlReaderSettings { @@ -307,7 +307,7 @@ namespace MediaBrowser.Providers.Music WebUtility.UrlEncode(artistName)); using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var oReader = new StreamReader(stream, Encoding.UTF8); var settings = new XmlReaderSettings() { @@ -622,7 +622,7 @@ namespace MediaBrowser.Providers.Music var url = "/ws/2/release?release-group=" + releaseGroupId.ToString(CultureInfo.InvariantCulture); using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var oReader = new StreamReader(stream, Encoding.UTF8); var settings = new XmlReaderSettings { @@ -649,7 +649,7 @@ namespace MediaBrowser.Providers.Music var url = "/ws/2/release-group/?query=reid:" + releaseEntryId.ToString(CultureInfo.InvariantCulture); using var response = await GetMusicBrainzResponse(url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); using var oReader = new StreamReader(stream, Encoding.UTF8); var settings = new XmlReaderSettings { diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs index 705359d2c..43d8af75f 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbItemProvider.cs @@ -133,7 +133,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb var url = OmdbProvider.GetOmdbUrl(urlQuery); using var response = await OmdbProvider.GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var resultList = new List(); if (isSearch) diff --git a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs index 9eed6172d..6af52b591 100644 --- a/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs +++ b/MediaBrowser.Providers/Plugins/Omdb/OmdbProvider.cs @@ -298,7 +298,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb imdbParam)); using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var rootObject = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); @@ -336,7 +336,7 @@ namespace MediaBrowser.Providers.Plugins.Omdb seasonId)); using var response = await GetOmdbResponse(_httpClientFactory.CreateClient(NamedClient.Default), url, cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); + await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); var rootObject = await _jsonSerializer.DeserializeFromStreamAsync(stream).ConfigureAwait(false); Directory.CreateDirectory(Path.GetDirectoryName(path)); _jsonSerializer.SerializeToFile(rootObject, path); -- cgit v1.2.3 From 18855a7884ee5f33b124347425886cc974b424e8 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 13:34:09 +0000 Subject: Initialial upload --- .../Plugins/PluginManifest.cs | 5 ++ .../Updates/InstallationManager.cs | 98 ++++++++++++++++++---- Jellyfin.Api/Controllers/PackageController.cs | 2 +- .../Routines/ReaddDefaultPluginRepository.cs | 6 +- .../Updates/IInstallationManager.cs | 7 +- MediaBrowser.Model/Updates/PackageInfo.cs | 12 +-- MediaBrowser.Model/Updates/RepositoryInfo.cs | 6 ++ MediaBrowser.Model/Updates/VersionInfo.cs | 30 ++++++- 8 files changed, 134 insertions(+), 32 deletions(-) (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/Plugins/PluginManifest.cs b/Emby.Server.Implementations/Plugins/PluginManifest.cs index 33762791b..63cad8271 100644 --- a/Emby.Server.Implementations/Plugins/PluginManifest.cs +++ b/Emby.Server.Implementations/Plugins/PluginManifest.cs @@ -56,5 +56,10 @@ namespace Emby.Server.Implementations.Plugins /// Gets or sets the Version number of the plugin. /// public string Version { get; set; } + + /// + /// Gets or sets the Repository where the plugin originated. + /// + public string Repository { get; set; } } } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 851e7bd68..e23e0790b 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -93,17 +93,29 @@ namespace Emby.Server.Implementations.Updates public IEnumerable CompletedInstallations => _completedInstallationsInternal; /// - public async Task> GetPackages(string manifest, CancellationToken cancellationToken = default) + public async Task> GetPackages(string manifestName, string manifest, CancellationToken cancellationToken = default) { try { using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(manifest, cancellationToken).ConfigureAwait(false); + .GetAsync(new Uri(manifest), cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); try { - return await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + var package = await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + + // Store the repository and repository url with each version, as they may be spread apart. + foreach (var entry in package) + { + foreach (var ver in entry.versions) + { + ver.repositoryName = manifestName; + ver.repositoryUrl = manifest; + } + } + + return package; } catch (SerializationException ex) { @@ -123,17 +135,69 @@ namespace Emby.Server.Implementations.Updates } } + private static void MergeSort(IList source, IList dest) + { + int sLength = source.Count - 1; + int dLength = dest.Count; + int s = 0, d = 0; + var sourceVersion = source[0].VersionNumber; + var destVersion = dest[0].VersionNumber; + + while (d < dLength) + { + if (sourceVersion.CompareTo(destVersion) >= 0) + { + if (s < sLength) + { + sourceVersion = source[++s].VersionNumber; + } + else + { + // Append all of destination to the end of source. + while (d < dLength) + { + source.Add(dest[d++]); + } + + break; + } + } + else + { + source.Insert(s++, dest[d++]); + if (d >= dLength) + { + break; + } + + sLength++; + destVersion = dest[d].VersionNumber; + } + } + } + /// public async Task> GetAvailablePackages(CancellationToken cancellationToken = default) { var result = new List(); foreach (RepositoryInfo repository in _config.Configuration.PluginRepositories) { - foreach (var package in await GetPackages(repository.Url, cancellationToken).ConfigureAwait(true)) + if (repository.Enabled) { - package.repositoryName = repository.Name; - package.repositoryUrl = repository.Url; - result.Add(package); + // Where repositories have the same content, the details of the first is taken. + foreach (var package in await GetPackages(repository.Name, repository.Url, cancellationToken).ConfigureAwait(true)) + { + var existing = FilterPackages(result, package.name, Guid.Parse(package.guid)).FirstOrDefault(); + if (existing != null) + { + // Assumption is both lists are ordered, so slot these into the correct place. + MergeSort(existing.versions, package.versions); + } + else + { + result.Add(package); + } + } } } @@ -144,7 +208,8 @@ namespace Emby.Server.Implementations.Updates public IEnumerable FilterPackages( IEnumerable availablePackages, string name = null, - Guid guid = default) + Guid guid = default, + Version specificVersion = null) { if (name != null) { @@ -156,6 +221,11 @@ namespace Emby.Server.Implementations.Updates availablePackages = availablePackages.Where(x => Guid.Parse(x.guid) == guid); } + if (specificVersion != null) + { + availablePackages = availablePackages.Where(x => x.versions.Where(y => y.VersionNumber.Equals(specificVersion)).Any()); + } + return availablePackages; } @@ -167,7 +237,7 @@ namespace Emby.Server.Implementations.Updates Version minVersion = null, Version specificVersion = null) { - var package = FilterPackages(availablePackages, name, guid).FirstOrDefault(); + var package = FilterPackages(availablePackages, name, guid, specificVersion).FirstOrDefault(); // Package not found in repository if (package == null) @@ -181,21 +251,21 @@ namespace Emby.Server.Implementations.Updates if (specificVersion != null) { - availableVersions = availableVersions.Where(x => new Version(x.version) == specificVersion); + availableVersions = availableVersions.Where(x => x.VersionNumber.Equals(specificVersion)); } else if (minVersion != null) { - availableVersions = availableVersions.Where(x => new Version(x.version) >= minVersion); + availableVersions = availableVersions.Where(x => x.VersionNumber >= minVersion); } - foreach (var v in availableVersions.OrderByDescending(x => x.version)) + foreach (var v in availableVersions.OrderByDescending(x => x.VersionNumber)) { yield return new InstallationInfo { Changelog = v.changelog, Guid = new Guid(package.guid), Name = package.name, - Version = new Version(v.version), + Version = v.VersionNumber, SourceUrl = v.sourceUrl, Checksum = v.checksum }; @@ -322,7 +392,7 @@ namespace Emby.Server.Implementations.Updates private async Task PerformPackageInstallation(InstallationInfo package, CancellationToken cancellationToken) { - var extension = Path.GetExtension(package.SourceUrl); + var extension = Path.GetExtension(package.SourceUrl.ToString()); if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase)) { _logger.LogError("Only zip packages are supported. {SourceUrl} is not a zip archive.", package.SourceUrl); diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index 1f797d6bc..83b359766 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Api.Controllers var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); if (!string.IsNullOrEmpty(repositoryUrl)) { - packages = packages.Where(p => p.repositoryUrl.Equals(repositoryUrl, StringComparison.OrdinalIgnoreCase)) + packages = packages.Where(p => p.versions.Where(q => q.repositoryUrl.Equals(repositoryUrl, StringComparison.OrdinalIgnoreCase)).Any()) .ToList(); } diff --git a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs index b281b5cc0..db605c54e 100644 --- a/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs +++ b/Jellyfin.Server/Migrations/Routines/ReaddDefaultPluginRepository.cs @@ -1,4 +1,4 @@ -using System; +using System; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Updates; @@ -14,7 +14,7 @@ namespace Jellyfin.Server.Migrations.Routines private readonly RepositoryInfo _defaultRepositoryInfo = new RepositoryInfo { Name = "Jellyfin Stable", - Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" + Url = "https://repo.jellyfin.org/releases/plugin/manifest-stable.json", }; /// @@ -46,4 +46,4 @@ namespace Jellyfin.Server.Migrations.Routines } } } -} \ No newline at end of file +} diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index 6aa16fea7..585b1ee19 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -19,10 +19,11 @@ namespace MediaBrowser.Common.Updates /// /// Parses a plugin manifest at the supplied URL. /// + /// Name of the repository. /// The URL to query. /// The cancellation token. /// Task{IReadOnlyList{PackageInfo}}. - Task> GetPackages(string manifest, CancellationToken cancellationToken = default); + Task> GetPackages(string manifestName, string manifest, CancellationToken cancellationToken = default); /// /// Gets all available packages. @@ -37,11 +38,13 @@ namespace MediaBrowser.Common.Updates /// The available packages. /// The name of the plugin. /// The id of the plugin. + /// The version of the plugin. /// All plugins matching the requirements. IEnumerable FilterPackages( IEnumerable availablePackages, string name = null, - Guid guid = default); + Guid guid = default, + Version specificVersion = null); /// /// Returns all compatible versions ordered from newest to oldest. diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs index 98b151d55..5e9304363 100644 --- a/MediaBrowser.Model/Updates/PackageInfo.cs +++ b/MediaBrowser.Model/Updates/PackageInfo.cs @@ -50,17 +50,7 @@ namespace MediaBrowser.Model.Updates /// Gets or sets the versions. /// /// The versions. - public IReadOnlyList versions { get; set; } - - /// - /// Gets or sets the repository name. - /// - public string repositoryName { get; set; } - - /// - /// Gets or sets the repository url. - /// - public string repositoryUrl { get; set; } + public IList versions { get; set; } /// /// Initializes a new instance of the class. diff --git a/MediaBrowser.Model/Updates/RepositoryInfo.cs b/MediaBrowser.Model/Updates/RepositoryInfo.cs index bd42e77f0..705d3b33c 100644 --- a/MediaBrowser.Model/Updates/RepositoryInfo.cs +++ b/MediaBrowser.Model/Updates/RepositoryInfo.cs @@ -16,5 +16,11 @@ namespace MediaBrowser.Model.Updates /// /// The URL. public string? Url { get; set; } + + /// + /// Gets or sets a value indicating whether the repository is enabled. + /// + /// true if enabled. + public bool Enabled { get; set; } = true; } } diff --git a/MediaBrowser.Model/Updates/VersionInfo.cs b/MediaBrowser.Model/Updates/VersionInfo.cs index a4aa0e75f..844170999 100644 --- a/MediaBrowser.Model/Updates/VersionInfo.cs +++ b/MediaBrowser.Model/Updates/VersionInfo.cs @@ -9,11 +9,29 @@ namespace MediaBrowser.Model.Updates /// public class VersionInfo { + private Version _version; + /// /// Gets or sets the version. /// /// The version. - public string version { get; set; } + public string version + { + get + { + return _version == null ? string.Empty : _version.ToString(); + } + + set + { + _version = Version.Parse(value); + } + } + + /// + /// Gets the version as a . + /// + public Version VersionNumber => _version; /// /// Gets or sets the changelog for this version. @@ -44,5 +62,15 @@ namespace MediaBrowser.Model.Updates /// /// The timestamp. public string timestamp { get; set; } + + /// + /// Gets or sets the repository name. + /// + public string repositoryName { get; set; } + + /// + /// Gets or sets the repository url. + /// + public string repositoryUrl { get; set; } } } -- cgit v1.2.3 From 1df58fbaa0b002a75c3b0d9f21b51461a2d9cd69 Mon Sep 17 00:00:00 2001 From: Greenback Date: Thu, 19 Nov 2020 14:12:33 +0000 Subject: updated --- Emby.Server.Implementations/Updates/InstallationManager.cs | 4 ++-- Jellyfin.Api/Controllers/PluginsController.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index e23e0790b..7a071c071 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -392,7 +392,7 @@ namespace Emby.Server.Implementations.Updates private async Task PerformPackageInstallation(InstallationInfo package, CancellationToken cancellationToken) { - var extension = Path.GetExtension(package.SourceUrl.ToString()); + var extension = Path.GetExtension(package.SourceUrl); if (!string.Equals(extension, ".zip", StringComparison.OrdinalIgnoreCase)) { _logger.LogError("Only zip packages are supported. {SourceUrl} is not a zip archive.", package.SourceUrl); @@ -403,7 +403,7 @@ namespace Emby.Server.Implementations.Updates string targetDir = Path.Combine(_appPaths.PluginsPath, package.Name); using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(package.SourceUrl, cancellationToken).ConfigureAwait(false); + .GetAsync(new Uri(package.SourceUrl), cancellationToken).ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); // CA5351: Do Not Use Broken Cryptographic Algorithms diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index 0f8ceba29..98f1bc2d2 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; -- cgit v1.2.3 From c5f5633ec6b5a18ae5d7bd30a8dd27671b83b92a Mon Sep 17 00:00:00 2001 From: crobibero Date: Sun, 22 Nov 2020 12:35:45 -0700 Subject: Handle invalid plugins --- .../Updates/InstallationManager.cs | 57 ++++++++++++---------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 7a071c071..f2c096b8a 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -6,13 +6,15 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; -using System.Runtime.Serialization; +using System.Net.Http.Json; using System.Security.Cryptography; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; using Jellyfin.Data.Events; using MediaBrowser.Common; using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Json; using MediaBrowser.Common.Net; using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Updates; @@ -21,8 +23,6 @@ using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events.Updates; using MediaBrowser.Model.IO; -using MediaBrowser.Model.Net; -using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Updates; using Microsoft.Extensions.Logging; @@ -40,9 +40,9 @@ namespace Emby.Server.Implementations.Updates private readonly IApplicationPaths _appPaths; private readonly IEventManager _eventManager; private readonly IHttpClientFactory _httpClientFactory; - private readonly IJsonSerializer _jsonSerializer; private readonly IServerConfigurationManager _config; private readonly IFileSystem _fileSystem; + private readonly JsonSerializerOptions _jsonSerializerOptions; /// /// Gets the application host. @@ -70,7 +70,6 @@ namespace Emby.Server.Implementations.Updates IApplicationPaths appPaths, IEventManager eventManager, IHttpClientFactory httpClientFactory, - IJsonSerializer jsonSerializer, IServerConfigurationManager config, IFileSystem fileSystem, IZipClient zipClient) @@ -83,10 +82,10 @@ namespace Emby.Server.Implementations.Updates _appPaths = appPaths; _eventManager = eventManager; _httpClientFactory = httpClientFactory; - _jsonSerializer = jsonSerializer; _config = config; _fileSystem = fileSystem; _zipClient = zipClient; + _jsonSerializerOptions = JsonDefaults.GetOptions(); } /// @@ -97,31 +96,29 @@ namespace Emby.Server.Implementations.Updates { try { - using var response = await _httpClientFactory.CreateClient(NamedClient.Default) - .GetAsync(new Uri(manifest), cancellationToken).ConfigureAwait(false); - await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); - - try + var packages = await _httpClientFactory.CreateClient(NamedClient.Default) + .GetFromJsonAsync>(new Uri(manifest), _jsonSerializerOptions, cancellationToken).ConfigureAwait(false); + if (packages == null) { - var package = await _jsonSerializer.DeserializeFromStreamAsync>(stream).ConfigureAwait(false); + return Array.Empty(); + } - // Store the repository and repository url with each version, as they may be spread apart. - foreach (var entry in package) + // Store the repository and repository url with each version, as they may be spread apart. + foreach (var entry in packages) + { + foreach (var ver in entry.versions) { - foreach (var ver in entry.versions) - { - ver.repositoryName = manifestName; - ver.repositoryUrl = manifest; - } + ver.repositoryName = manifestName; + ver.repositoryUrl = manifest; } - - return package; - } - catch (SerializationException ex) - { - _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest); - return Array.Empty(); } + + return packages; + } + catch (JsonException ex) + { + _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest); + return Array.Empty(); } catch (UriFormatException ex) { @@ -187,7 +184,13 @@ namespace Emby.Server.Implementations.Updates // Where repositories have the same content, the details of the first is taken. foreach (var package in await GetPackages(repository.Name, repository.Url, cancellationToken).ConfigureAwait(true)) { - var existing = FilterPackages(result, package.name, Guid.Parse(package.guid)).FirstOrDefault(); + if (!Guid.TryParse(package.guid, out var packageGuid)) + { + // Package doesn't have a valid GUID, skip. + continue; + } + + var existing = FilterPackages(result, package.name, packageGuid).FirstOrDefault(); if (existing != null) { // Assumption is both lists are ordered, so slot these into the correct place. -- cgit v1.2.3 From 8c8a71692e2f42e30f95e9ff38cc5442a0d56978 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 25 Nov 2020 23:40:31 +0100 Subject: Remove Hex class as the BCL has one now --- .../LiveTv/Listings/SchedulesDirect.cs | 2 +- .../QuickConnect/QuickConnectManager.cs | 2 +- .../Updates/InstallationManager.cs | 2 +- Jellyfin.Api/Controllers/LiveTvController.cs | 5 +- MediaBrowser.Common/Cryptography/PasswordHash.cs | 10 +-- MediaBrowser.Common/Hex.cs | 94 ---------------------- .../Jellyfin.Common.Benches/HexDecodeBenches.cs | 45 ----------- .../Jellyfin.Common.Benches/HexEncodeBenches.cs | 32 -------- .../Jellyfin.Common.Benches.csproj | 16 ---- benches/Jellyfin.Common.Benches/Program.cs | 14 ---- tests/Jellyfin.Common.Tests/HexTests.cs | 19 ----- tests/Jellyfin.Common.Tests/PasswordHashTests.cs | 5 +- 12 files changed, 13 insertions(+), 233 deletions(-) delete mode 100644 MediaBrowser.Common/Hex.cs delete mode 100644 benches/Jellyfin.Common.Benches/HexDecodeBenches.cs delete mode 100644 benches/Jellyfin.Common.Benches/HexEncodeBenches.cs delete mode 100644 benches/Jellyfin.Common.Benches/Jellyfin.Common.Benches.csproj delete mode 100644 benches/Jellyfin.Common.Benches/Program.cs delete mode 100644 tests/Jellyfin.Common.Tests/HexTests.cs (limited to 'Emby.Server.Implementations/Updates/InstallationManager.cs') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 5d17ba1de..8c44b244c 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -647,7 +647,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings { using var options = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/token"); var hashedPasswordBytes = _cryptoProvider.ComputeHash("SHA1", Encoding.ASCII.GetBytes(password), Array.Empty()); - string hashedPassword = Hex.Encode(hashedPasswordBytes); + string hashedPassword = Convert.ToHexString(hashedPasswordBytes); options.Content = new StringContent("{\"username\":\"" + username + "\",\"password\":\"" + hashedPassword + "\"}", Encoding.UTF8, MediaTypeNames.Application.Json); using var response = await Send(options, false, null, cancellationToken).ConfigureAwait(false); diff --git a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs index 140a67541..7bed06de3 100644 --- a/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs +++ b/Emby.Server.Implementations/QuickConnect/QuickConnectManager.cs @@ -243,7 +243,7 @@ namespace Emby.Server.Implementations.QuickConnect Span bytes = stackalloc byte[length]; _rng.GetBytes(bytes); - return Hex.Encode(bytes); + return Convert.ToHexString(bytes); } /// diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index f2c096b8a..ef346dd5d 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -414,7 +414,7 @@ namespace Emby.Server.Implementations.Updates using var md5 = MD5.Create(); cancellationToken.ThrowIfCancellationRequested(); - var hash = Hex.Encode(md5.ComputeHash(stream)); + var hash = Convert.ToHexString(md5.ComputeHash(stream)); if (!string.Equals(package.Checksum, hash, StringComparison.OrdinalIgnoreCase)) { _logger.LogError( diff --git a/Jellyfin.Api/Controllers/LiveTvController.cs b/Jellyfin.Api/Controllers/LiveTvController.cs index 410f3a340..2c27601e9 100644 --- a/Jellyfin.Api/Controllers/LiveTvController.cs +++ b/Jellyfin.Api/Controllers/LiveTvController.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; @@ -17,7 +17,6 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LiveTvDtos; using Jellyfin.Data.Enums; -using MediaBrowser.Common; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Net; using MediaBrowser.Controller.Dto; @@ -1015,7 +1014,7 @@ namespace Jellyfin.Api.Controllers if (!string.IsNullOrEmpty(pw)) { using var sha = SHA1.Create(); - listingsProviderInfo.Password = Hex.Encode(sha.ComputeHash(Encoding.UTF8.GetBytes(pw))); + listingsProviderInfo.Password = Convert.ToHexString(sha.ComputeHash(Encoding.UTF8.GetBytes(pw))); } return await _liveTvManager.SaveListingProvider(listingsProviderInfo, validateLogin, validateListings).ConfigureAwait(false); diff --git a/MediaBrowser.Common/Cryptography/PasswordHash.cs b/MediaBrowser.Common/Cryptography/PasswordHash.cs index 3e12536ec..3e2eae1c8 100644 --- a/MediaBrowser.Common/Cryptography/PasswordHash.cs +++ b/MediaBrowser.Common/Cryptography/PasswordHash.cs @@ -101,13 +101,13 @@ namespace MediaBrowser.Common.Cryptography // Check if the string also contains a salt if (splitted.Length - index == 2) { - salt = Hex.Decode(splitted[index++]); - hash = Hex.Decode(splitted[index++]); + salt = Convert.FromHexString(splitted[index++]); + hash = Convert.FromHexString(splitted[index++]); } else { salt = Array.Empty(); - hash = Hex.Decode(splitted[index++]); + hash = Convert.FromHexString(splitted[index++]); } return new PasswordHash(id, hash, salt, parameters); @@ -144,11 +144,11 @@ namespace MediaBrowser.Common.Cryptography if (_salt.Length != 0) { str.Append('$') - .Append(Hex.Encode(_salt, false)); + .Append(Convert.ToHexString(_salt)); } return str.Append('$') - .Append(Hex.Encode(_hash, false)).ToString(); + .Append(Convert.ToHexString(_hash)).ToString(); } } } diff --git a/MediaBrowser.Common/Hex.cs b/MediaBrowser.Common/Hex.cs deleted file mode 100644 index 559109f74..000000000 --- a/MediaBrowser.Common/Hex.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; - -namespace MediaBrowser.Common -{ - /// - /// Encoding and decoding hex strings. - /// - public static class Hex - { - internal const string HexCharsLower = "0123456789abcdef"; - internal const string HexCharsUpper = "0123456789ABCDEF"; - - internal const int LastHexSymbol = 0x66; // 102: f - - /// - /// Gets a map from an ASCII char to its hex value shifted, - /// e.g. b -> 11. 0xFF means it's not a hex symbol. - /// - internal static ReadOnlySpan HexLookup => new byte[] - { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - - /// - /// Encodes each element of the specified bytes as its hexadecimal string representation. - /// - /// An array of bytes. - /// true to use lowercase hexadecimal characters; otherwise false. - /// bytes as a hex string. - public static string Encode(ReadOnlySpan bytes, bool lowercase = true) - { - var hexChars = lowercase ? HexCharsLower : HexCharsUpper; - - // TODO: use string.Create when it's supports spans - // Ref: https://github.com/dotnet/corefx/issues/29120 - char[] s = new char[bytes.Length * 2]; - int j = 0; - for (int i = 0; i < bytes.Length; i++) - { - s[j++] = hexChars[bytes[i] >> 4]; - s[j++] = hexChars[bytes[i] & 0x0f]; - } - - return new string(s); - } - - /// - /// Decodes a hex string into bytes. - /// - /// The . - /// The decoded bytes. - public static byte[] Decode(ReadOnlySpan str) - { - if (str.Length == 0) - { - return Array.Empty(); - } - - var unHex = HexLookup; - - int byteLen = str.Length / 2; - byte[] bytes = new byte[byteLen]; - int i = 0; - for (int j = 0; j < byteLen; j++) - { - byte a; - byte b; - if (str[i] > LastHexSymbol - || (a = unHex[str[i++]]) == 0xFF - || str[i] > LastHexSymbol - || (b = unHex[str[i++]]) == 0xFF) - { - ThrowArgumentException(nameof(str)); - break; // Unreachable - } - - bytes[j] = (byte)((a * 16) | b); - } - - return bytes; - } - - [DoesNotReturn] - private static void ThrowArgumentException(string paramName) - => throw new ArgumentException("Character is not a hex symbol.", paramName); - } -} diff --git a/benches/Jellyfin.Common.Benches/HexDecodeBenches.cs b/benches/Jellyfin.Common.Benches/HexDecodeBenches.cs deleted file mode 100644 index d9a107b69..000000000 --- a/benches/Jellyfin.Common.Benches/HexDecodeBenches.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Globalization; -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using MediaBrowser.Common; - -namespace Jellyfin.Common.Benches -{ - [MemoryDiagnoser] - public class HexDecodeBenches - { - private string _data; - - [Params(0, 10, 100, 1000, 10000, 1000000)] - public int N { get; set; } - - [GlobalSetup] - public void GlobalSetup() - { - var bytes = new byte[N]; - new Random(42).NextBytes(bytes); - _data = Hex.Encode(bytes); - } - - [Benchmark] - public byte[] Decode() => Hex.Decode(_data); - - [Benchmark] - public byte[] DecodeSubString() => DecodeSubString(_data); - - private static byte[] DecodeSubString(string str) - { - byte[] bytes = new byte[str.Length / 2]; - for (int i = 0; i < str.Length; i += 2) - { - bytes[i / 2] = byte.Parse( - str.Substring(i, 2), - NumberStyles.HexNumber, - CultureInfo.InvariantCulture); - } - - return bytes; - } - } -} diff --git a/benches/Jellyfin.Common.Benches/HexEncodeBenches.cs b/benches/Jellyfin.Common.Benches/HexEncodeBenches.cs deleted file mode 100644 index 7abf93c51..000000000 --- a/benches/Jellyfin.Common.Benches/HexEncodeBenches.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; -using MediaBrowser.Common; - -namespace Jellyfin.Common.Benches -{ - [MemoryDiagnoser] - public class HexEncodeBenches - { - private byte[] _data; - - [Params(0, 10, 100, 1000, 10000, 1000000)] - public int N { get; set; } - - [GlobalSetup] - public void GlobalSetup() - { - _data = new byte[N]; - new Random(42).NextBytes(_data); - } - - [Benchmark] - public string HexEncode() => Hex.Encode(_data); - - [Benchmark] - public string BitConverterToString() => BitConverter.ToString(_data); - - [Benchmark] - public string BitConverterToStringWithReplace() => BitConverter.ToString(_data).Replace("-", ""); - } -} diff --git a/benches/Jellyfin.Common.Benches/Jellyfin.Common.Benches.csproj b/benches/Jellyfin.Common.Benches/Jellyfin.Common.Benches.csproj deleted file mode 100644 index c564e86e9..000000000 --- a/benches/Jellyfin.Common.Benches/Jellyfin.Common.Benches.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net5.0 - - - - - - - - - - - diff --git a/benches/Jellyfin.Common.Benches/Program.cs b/benches/Jellyfin.Common.Benches/Program.cs deleted file mode 100644 index b218b0dc1..000000000 --- a/benches/Jellyfin.Common.Benches/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using BenchmarkDotNet.Running; - -namespace Jellyfin.Common.Benches -{ - public static class Program - { - public static void Main(string[] args) - { - _ = BenchmarkRunner.Run(); - _ = BenchmarkRunner.Run(); - } - } -} diff --git a/tests/Jellyfin.Common.Tests/HexTests.cs b/tests/Jellyfin.Common.Tests/HexTests.cs deleted file mode 100644 index 5b578d38c..000000000 --- a/tests/Jellyfin.Common.Tests/HexTests.cs +++ /dev/null @@ -1,19 +0,0 @@ -using MediaBrowser.Common; -using Xunit; - -namespace Jellyfin.Common.Tests -{ - public class HexTests - { - [Theory] - [InlineData("")] - [InlineData("00")] - [InlineData("01")] - [InlineData("000102030405060708090a0b0c0d0e0f")] - [InlineData("0123456789abcdef")] - public void RoundTripTest(string data) - { - Assert.Equal(data, Hex.Encode(Hex.Decode(data))); - } - } -} diff --git a/tests/Jellyfin.Common.Tests/PasswordHashTests.cs b/tests/Jellyfin.Common.Tests/PasswordHashTests.cs index 46926f4f8..c4422bd10 100644 --- a/tests/Jellyfin.Common.Tests/PasswordHashTests.cs +++ b/tests/Jellyfin.Common.Tests/PasswordHashTests.cs @@ -1,3 +1,4 @@ +using System; using MediaBrowser.Common; using MediaBrowser.Common.Cryptography; using Xunit; @@ -16,8 +17,8 @@ namespace Jellyfin.Common.Tests { var pass = PasswordHash.Parse(passwordHash); Assert.Equal(id, pass.Id); - Assert.Equal(salt, Hex.Encode(pass.Salt, false)); - Assert.Equal(hash, Hex.Encode(pass.Hash, false)); + Assert.Equal(salt, Convert.ToHexString(pass.Salt)); + Assert.Equal(hash, Convert.ToHexString(pass.Hash)); } [Theory] -- cgit v1.2.3