diff options
23 files changed, 255 insertions, 308 deletions
diff --git a/Dockerfile b/Dockerfile index c24c32181..2a60bf184 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,7 +42,7 @@ ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 EXPOSE 8096 VOLUME /cache /config /media -ENTRYPOINT ./jellyfin/jellyfin \ - --datadir /config \ - --cachedir /cache \ - --ffmpeg /usr/local/bin/ffmpeg +ENTRYPOINT ["./jellyfin/jellyfin", \ + "--datadir", "/config", \ + "--cachedir", "/cache", \ + "--ffmpeg", "/usr/local/bin/ffmpeg"] diff --git a/Dockerfile.arm b/Dockerfile.arm index f8c8511ae..fd3d1e070 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -38,7 +38,7 @@ ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 EXPOSE 8096 VOLUME /cache /config /media -ENTRYPOINT ./jellyfin/jellyfin \ - --datadir /config \ - --cachedir /cache \ - --ffmpeg /usr/bin/ffmpeg +ENTRYPOINT ["./jellyfin/jellyfin", \ + "--datadir", "/config", \ + "--cachedir", "/cache", \ + "--ffmpeg", "/usr/bin/ffmpeg"] diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 9b343659f..3c1b2e3ea 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -38,7 +38,7 @@ ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 EXPOSE 8096 VOLUME /cache /config /media -ENTRYPOINT ./jellyfin/jellyfin \ - --datadir /config \ - --cachedir /cache \ - --ffmpeg /usr/bin/ffmpeg +ENTRYPOINT ["./jellyfin/jellyfin", \ + "--datadir", "/config", \ + "--cachedir", "/cache", \ + "--ffmpeg", "/usr/bin/ffmpeg"] diff --git a/Emby.Dlna/Api/DlnaServerService.cs b/Emby.Dlna/Api/DlnaServerService.cs index 8bf3797f8..1f137e620 100644 --- a/Emby.Dlna/Api/DlnaServerService.cs +++ b/Emby.Dlna/Api/DlnaServerService.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using Emby.Dlna.Main; using MediaBrowser.Common.Extensions; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; @@ -108,12 +109,13 @@ namespace Emby.Dlna.Api public class DlnaServerService : IService, IRequiresRequest { - private readonly IDlnaManager _dlnaManager; - private const string XMLContentType = "text/xml; charset=UTF-8"; + private readonly IDlnaManager _dlnaManager; + private readonly IHttpResultFactory _resultFactory; + private readonly IServerConfigurationManager _configurationManager; + public IRequest Request { get; set; } - private IHttpResultFactory _resultFactory; private IContentDirectory ContentDirectory => DlnaEntryPoint.Current.ContentDirectory; @@ -121,10 +123,14 @@ namespace Emby.Dlna.Api private IMediaReceiverRegistrar MediaReceiverRegistrar => DlnaEntryPoint.Current.MediaReceiverRegistrar; - public DlnaServerService(IDlnaManager dlnaManager, IHttpResultFactory httpResultFactory) + public DlnaServerService( + IDlnaManager dlnaManager, + IHttpResultFactory httpResultFactory, + IServerConfigurationManager configurationManager) { _dlnaManager = dlnaManager; _resultFactory = httpResultFactory; + _configurationManager = configurationManager; } private string GetHeader(string name) @@ -205,14 +211,25 @@ namespace Emby.Dlna.Api var pathInfo = Parse(Request.PathInfo); var first = pathInfo[0]; + string baseUrl = _configurationManager.Configuration.BaseUrl; + // backwards compatibility - // TODO: Work out what this is doing. - if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) || - string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase) || - string.Equals(first, "jellyfin", StringComparison.OrdinalIgnoreCase)) + if (baseUrl.Length == 0 + && (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) + || string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))) { index++; } + else if (string.Equals(first, baseUrl.Remove(0, 1))) + { + index++; + var second = pathInfo[1]; + if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase) + || string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase)) + { + index++; + } + } return pathInfo[index]; } diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index a3a013096..2ca44b7ea 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -160,7 +160,7 @@ namespace Emby.Dlna.PlayTo uuid = location.GetMD5().ToString("N", CultureInfo.InvariantCulture); } - var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersion, uuid, null, uri.OriginalString, null); + var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null); var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault(); diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 9cf430daf..d37be0e63 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -311,6 +311,14 @@ namespace Emby.Naming.Common } }, + // This isn't a Kodi naming rule, but the expression below causes false positives, + // so we make sure this one gets tested first. + // "Foo Bar 889" + new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>(\w+\s*?)*)\s(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$") + { + IsNamed = true + }, + new EpisodeExpression("[\\\\/\\._ \\[\\(-]([0-9]+)x([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)([^\\\\/]*)$") { SupportsAbsoluteEpisodeNumbers = true @@ -328,9 +336,10 @@ namespace Emby.Naming.Common // *** End Kodi Standard Naming - // [bar] Foo - 1 [baz] - new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>(\w+\s)+?)[-\s_]+(?<epnumber>\d+).*$"){ - IsNamed=false, + // [bar] Foo - 1 [baz] + new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>(\w+\s*?)+?)[-\s_]+(?<epnumber>\d+).*$") + { + IsNamed = true }, new EpisodeExpression(@".*(\\|\/)[sS]?(?<seasonnumber>\d+)[xX](?<epnumber>\d+)[^\\\/]*$") { diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index a23fa3df7..fd0773df5 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -23,10 +23,10 @@ <!-- Code analysers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" /> - <PackageReference Include="SerilogAnalyzer" Version="0.15.0" /> - <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" /> - <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" /> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.4" PrivateAssets="All" /> + <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" /> + <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" /> + <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7cb7aa748..fef461b9a 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -410,13 +410,17 @@ namespace Emby.Server.Implementations _validAddressResults.Clear(); } - public string ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3); + /// <inheritdoc /> + public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version; + + /// <inheritdoc /> + public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3); /// <summary> /// Gets the current application user agent. /// </summary> /// <value>The application user agent.</value> - public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersion; + public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString; /// <summary> /// Gets the email address for use within a comment section of a user agent field. @@ -1424,7 +1428,7 @@ namespace Emby.Server.Implementations { HasPendingRestart = HasPendingRestart, IsShuttingDown = IsShuttingDown, - Version = ApplicationVersion, + Version = ApplicationVersionString, WebSocketPortNumber = HttpPort, CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(), Id = SystemId, @@ -1464,7 +1468,7 @@ namespace Emby.Server.Implementations return new PublicSystemInfo { - Version = ApplicationVersion, + Version = ApplicationVersionString, ProductName = ApplicationProductName, Id = SystemId, OperatingSystem = OperatingSystem.Id.ToString(), diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs index cd2a7dcf0..dc1a56e27 100644 --- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs +++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs @@ -7,7 +7,6 @@ using System.Net.Sockets; using System.Reflection; using System.Threading; using System.Threading.Tasks; -using Emby.Server.Implementations.Configuration; using Emby.Server.Implementations.Net; using Emby.Server.Implementations.Services; using MediaBrowser.Common.Extensions; @@ -16,7 +15,6 @@ using MediaBrowser.Controller; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Events; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Services; using Microsoft.AspNetCore.Http; diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs index 7afeba9dd..fe8deae59 100644 --- a/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs +++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/PluginUpdateTask.cs @@ -1,24 +1,23 @@ -using MediaBrowser.Common.Updates; -using MediaBrowser.Model.Net; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Progress; +using MediaBrowser.Common.Updates; +using MediaBrowser.Model.Net; using MediaBrowser.Model.Tasks; using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.ScheduledTasks { /// <summary> - /// Plugin Update Task + /// Plugin Update Task. /// </summary> public class PluginUpdateTask : IScheduledTask, IConfigurableScheduledTask { /// <summary> - /// The _logger + /// The _logger. /// </summary> private readonly ILogger _logger; @@ -31,7 +30,7 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// <summary> - /// Creates the triggers that define when the task will run + /// Creates the triggers that define when the task will run. /// </summary> /// <returns>IEnumerable{BaseTaskTrigger}.</returns> public IEnumerable<TaskTriggerInfo> GetDefaultTriggers() @@ -44,16 +43,16 @@ namespace Emby.Server.Implementations.ScheduledTasks } /// <summary> - /// Update installed plugins + /// Update installed plugins. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> - /// <returns>Task.</returns> + /// <returns><see cref="Task" />.</returns> public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { progress.Report(0); - var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(typeof(PluginUpdateTask).Assembly.GetName().Version, true, cancellationToken).ConfigureAwait(false)).ToList(); + var packagesToInstall = (await _installationManager.GetAvailablePluginUpdates(cancellationToken).ConfigureAwait(false)).ToList(); progress.Report(10); @@ -94,18 +93,25 @@ namespace Emby.Server.Implementations.ScheduledTasks progress.Report(100); } + /// <inheritdoc /> public string Name => "Check for plugin updates"; + /// <inheritdoc /> public string Description => "Downloads and installs updates for plugins that are configured to update automatically."; + /// <inheritdoc /> public string Category => "Application"; + /// <inheritdoc /> public string Key => "PluginUpdates"; + /// <inheritdoc /> public bool IsHidden => false; + /// <inheritdoc /> public bool IsEnabled => true; + /// <inheritdoc /> public bool IsLogged => true; } } diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 2de20829c..1c5402268 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; @@ -22,7 +23,7 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Updates { /// <summary> - /// Manages all install, uninstall and update operations (both plugins and system) + /// Manages all install, uninstall and update operations (both plugins and system). /// </summary> public class InstallationManager : IInstallationManager { @@ -49,12 +50,12 @@ namespace Emby.Server.Implementations.Updates /// <summary> /// The current installations. /// </summary> - private List<(InstallationInfo info, CancellationTokenSource token)> _currentInstallations; + private readonly List<(InstallationInfo info, CancellationTokenSource token)> _currentInstallations; /// <summary> /// The completed installations. /// </summary> - private ConcurrentBag<InstallationInfo> _completedInstallationsInternal; + private readonly ConcurrentBag<InstallationInfo> _completedInstallationsInternal; public InstallationManager( ILogger<InstallationManager> logger, @@ -84,51 +85,32 @@ namespace Emby.Server.Implementations.Updates _zipClient = zipClient; } + /// <inheritdoc /> public event EventHandler<InstallationEventArgs> PackageInstalling; + /// <inheritdoc /> public event EventHandler<InstallationEventArgs> PackageInstallationCompleted; + /// <inheritdoc /> public event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed; + /// <inheritdoc /> public event EventHandler<InstallationEventArgs> PackageInstallationCancelled; - /// <summary> - /// Occurs when a plugin is uninstalled. - /// </summary> + /// <inheritdoc /> public event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled; - /// <summary> - /// Occurs when a plugin plugin is updated. - /// </summary> + /// <inheritdoc /> public event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated; - /// <summary> - /// Occurs when a plugin plugin is installed. - /// </summary> + /// <inheritdoc /> public event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled; + /// <inheritdoc /> public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal; - /// <summary> - /// Gets all available packages. - /// </summary> - /// <returns>Task{List{PackageInfo}}.</returns> - public async Task<List<PackageInfo>> GetAvailablePackages( - CancellationToken cancellationToken, - bool withRegistration = true, - string packageType = null, - Version applicationVersion = null) - { - var packages = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); - return FilterPackages(packages, packageType, applicationVersion); - } - - /// <summary> - /// Gets all available packages. - /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{List{PackageInfo}}.</returns> - public async Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken) + /// <inheritdoc /> + public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default) { using (var response = await _httpClient.SendAsync( new HttpRequestOptions @@ -136,178 +118,91 @@ namespace Emby.Server.Implementations.Updates Url = "https://repo.jellyfin.org/releases/plugin/manifest.json", CancellationToken = cancellationToken, CacheMode = CacheMode.Unconditional, - CacheLength = GetCacheLength() + CacheLength = TimeSpan.FromMinutes(3) }, HttpMethod.Get).ConfigureAwait(false)) using (Stream stream = response.Content) { - return FilterPackages(await _jsonSerializer.DeserializeFromStreamAsync<PackageInfo[]>(stream).ConfigureAwait(false)); + return await _jsonSerializer.DeserializeFromStreamAsync<IReadOnlyList<PackageInfo>>( + stream).ConfigureAwait(false); } } - private static TimeSpan GetCacheLength() - { - return TimeSpan.FromMinutes(3); - } - - protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages) + /// <inheritdoc /> + public IEnumerable<PackageInfo> FilterPackages( + IEnumerable<PackageInfo> availablePackages, + string name = null, + Guid guid = default) { - var list = new List<PackageInfo>(); - - foreach (var package in packages) + if (name != null) { - var versions = new List<PackageVersionInfo>(); - foreach (var version in package.versions) - { - if (string.IsNullOrEmpty(version.sourceUrl)) - { - continue; - } - - versions.Add(version); - } - - package.versions = versions - .OrderByDescending(x => x.Version) - .ToArray(); - - if (package.versions.Length == 0) - { - continue; - } - - list.Add(package); + availablePackages = availablePackages.Where(x => x.name.Equals(name, StringComparison.OrdinalIgnoreCase)); } - // Remove packages with no versions - return list; - } - - protected List<PackageInfo> FilterPackages(IEnumerable<PackageInfo> packages, string packageType, Version applicationVersion) - { - var packagesList = FilterPackages(packages); - - var returnList = new List<PackageInfo>(); - - var filterOnPackageType = !string.IsNullOrEmpty(packageType); - - foreach (var p in packagesList) + if (guid != Guid.Empty) { - if (filterOnPackageType && !string.Equals(p.type, packageType, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - // If an app version was supplied, filter the versions for each package to only include supported versions - if (applicationVersion != null) - { - p.versions = p.versions.Where(v => IsPackageVersionUpToDate(v, applicationVersion)).ToArray(); - } - - if (p.versions.Length == 0) - { - continue; - } - - returnList.Add(p); + var strGuid = guid.ToString("N", CultureInfo.InvariantCulture); + availablePackages = availablePackages.Where(x => x.guid.Equals(strGuid, StringComparison.OrdinalIgnoreCase)); } - return returnList; + return availablePackages; } - /// <summary> - /// Determines whether [is package version up to date] [the specified package version info]. - /// </summary> - /// <param name="packageVersionInfo">The package version info.</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <returns><c>true</c> if [is package version up to date] [the specified package version info]; otherwise, <c>false</c>.</returns> - private static bool IsPackageVersionUpToDate(PackageVersionInfo packageVersionInfo, Version currentServerVersion) + /// <inheritdoc /> + public IEnumerable<PackageVersionInfo> GetCompatibleVersions( + IEnumerable<PackageVersionInfo> availableVersions, + Version minVersion = null, + PackageVersionClass classification = PackageVersionClass.Release) { - if (string.IsNullOrEmpty(packageVersionInfo.requiredVersionStr)) + var appVer = _applicationHost.ApplicationVersion; + availableVersions = availableVersions + .Where(x => x.classification == classification + && Version.Parse(x.requiredVersionStr) <= appVer); + + if (minVersion != null) { - return true; + availableVersions = availableVersions.Where(x => x.Version >= minVersion); } - return Version.TryParse(packageVersionInfo.requiredVersionStr, out var requiredVersion) && currentServerVersion >= requiredVersion; + return availableVersions.OrderByDescending(x => x.Version); } - /// <summary> - /// Gets the package. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid</param> - /// <param name="classification">The classification.</param> - /// <param name="version">The version.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - public async Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version) + /// <inheritdoc /> + public IEnumerable<PackageVersionInfo> GetCompatibleVersions( + IEnumerable<PackageInfo> availablePackages, + string name = null, + Guid guid = default, + Version minVersion = null, + PackageVersionClass classification = PackageVersionClass.Release) { - var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false); - - var package = packages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase)) - ?? packages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase)); + var package = FilterPackages(availablePackages, name, guid).FirstOrDefault(); + // Package not found. if (package == null) { return null; } - return package.versions.FirstOrDefault(v => v.Version == version && v.classification == classification); - } - - /// <summary> - /// Gets the latest compatible version. - /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid if this is a plug-in</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <param name="classification">The classification.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - public async Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release) - { - var packages = await GetAvailablePackages(CancellationToken.None, false).ConfigureAwait(false); - - return GetLatestCompatibleVersion(packages, name, guid, currentServerVersion, classification); - } - - /// <summary> - /// Gets the latest compatible version. - /// </summary> - /// <param name="availablePackages">The available packages.</param> - /// <param name="name">The name.</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <param name="classification">The classification.</param> - /// <returns>PackageVersionInfo.</returns> - public PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release) - { - var package = availablePackages.FirstOrDefault(p => string.Equals(p.guid, guid ?? "none", StringComparison.OrdinalIgnoreCase)) - ?? availablePackages.FirstOrDefault(p => p.name.Equals(name, StringComparison.OrdinalIgnoreCase)); - - return package?.versions - .OrderByDescending(x => x.Version) - .FirstOrDefault(v => v.classification <= classification && IsPackageVersionUpToDate(v, currentServerVersion)); + return GetCompatibleVersions( + package.versions, + minVersion, + classification); } - /// <summary> - /// Gets the available plugin updates. - /// </summary> - /// <param name="applicationVersion">The current server version.</param> - /// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param> - /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns> - public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken) + /// <inheritdoc /> + public async Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default) { - var catalog = await GetAvailablePackagesWithoutRegistrationInfo(cancellationToken).ConfigureAwait(false); + var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false); var systemUpdateLevel = _applicationHost.SystemUpdateLevel; // Figure out what needs to be installed - return _applicationHost.Plugins.Select(p => + return _applicationHost.Plugins.Select(x => { - var latestPluginInfo = GetLatestCompatibleVersion(catalog, p.Name, p.Id.ToString(), applicationVersion, systemUpdateLevel); - - return latestPluginInfo != null && latestPluginInfo.Version > p.Version ? latestPluginInfo : null; - }).Where(i => i != null) - .Where(p => !string.IsNullOrEmpty(p.sourceUrl) && !CompletedInstallations.Any(i => string.Equals(i.AssemblyGuid, p.guid, StringComparison.OrdinalIgnoreCase))); + var compatibleversions = GetCompatibleVersions(catalog, x.Name, x.Id, x.Version, systemUpdateLevel); + return compatibleversions.FirstOrDefault(y => y.Version > x.Version); + }).Where(x => x != null) + .Where(x => !CompletedInstallations.Any(y => string.Equals(y.AssemblyGuid, x.guid, StringComparison.OrdinalIgnoreCase))); } /// <inheritdoc /> @@ -393,7 +288,7 @@ namespace Emby.Server.Implementations.Updates finally { // Dispose the progress object and remove the installation from the in-progress list - tuple.Item2.Dispose(); + tuple.innerCancellationTokenSource.Dispose(); } } @@ -441,7 +336,7 @@ namespace Emby.Server.Implementations.Updates // Always override the passed-in target (which is a file) and figure it out again string targetDir = Path.Combine(_appPaths.PluginsPath, package.name); -// CA5351: Do Not Use Broken Cryptographic Algorithms + // CA5351: Do Not Use Broken Cryptographic Algorithms #pragma warning disable CA5351 using (var res = await _httpClient.SendAsync( new HttpRequestOptions @@ -539,18 +434,19 @@ namespace Emby.Server.Implementations.Updates { lock (_currentInstallationsLock) { - var install = _currentInstallations.Find(x => x.Item1.Id == id); + var install = _currentInstallations.Find(x => x.info.Id == id); if (install == default((InstallationInfo, CancellationTokenSource))) { return false; } - install.Item2.Cancel(); + install.token.Cancel(); _currentInstallations.Remove(install); return true; } } + /// <inheritdoc /> public void Dispose() { Dispose(true); @@ -569,7 +465,7 @@ namespace Emby.Server.Implementations.Updates { foreach (var tuple in _currentInstallations) { - tuple.Item2.Dispose(); + tuple.token.Dispose(); } _currentInstallations.Clear(); diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 7dca7e814..a5d65a716 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -40,14 +40,13 @@ namespace MediaBrowser.Api internal IHttpResultFactory ResultFactory { get; private set; } /// <summary> - /// The application paths + /// Gets the configuration manager. /// </summary> - private readonly IServerConfigurationManager _config; + internal IServerConfigurationManager ConfigurationManager { get; } private readonly ISessionManager _sessionManager; private readonly IFileSystem _fileSystem; private readonly IMediaSourceManager _mediaSourceManager; - public readonly IProcessFactory ProcessFactory; /// <summary> /// The active transcoding jobs @@ -73,15 +72,13 @@ namespace MediaBrowser.Api IServerConfigurationManager config, IFileSystem fileSystem, IMediaSourceManager mediaSourceManager, - IProcessFactory processFactory, IHttpResultFactory resultFactory) { Logger = logger; _sessionManager = sessionManager; - _config = config; + ConfigurationManager = config; _fileSystem = fileSystem; _mediaSourceManager = mediaSourceManager; - ProcessFactory = processFactory; ResultFactory = resultFactory; _sessionManager.PlaybackProgress += _sessionManager_PlaybackProgress; @@ -162,7 +159,7 @@ namespace MediaBrowser.Api public EncodingOptions GetEncodingOptions() { - return ConfigurationManagerExtensions.GetConfiguration<EncodingOptions>(_config, "encoding"); + return ConfigurationManagerExtensions.GetConfiguration<EncodingOptions>(ConfigurationManager, "encoding"); } /// <summary> @@ -170,7 +167,7 @@ namespace MediaBrowser.Api /// </summary> private void DeleteEncodedMediaCache() { - var path = _config.ApplicationPaths.GetTranscodingTempPath(); + var path = ConfigurationManager.ApplicationPaths.GetTranscodingTempPath(); if (!Directory.Exists(path)) { diff --git a/MediaBrowser.Api/BaseApiService.cs b/MediaBrowser.Api/BaseApiService.cs index 49f8c6ace..311105596 100644 --- a/MediaBrowser.Api/BaseApiService.cs +++ b/MediaBrowser.Api/BaseApiService.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -298,11 +297,24 @@ namespace MediaBrowser.Api var pathInfo = Parse(Request.PathInfo); var first = pathInfo[0]; + string baseUrl = ApiEntryPoint.Instance.ConfigurationManager.Configuration.BaseUrl; + // backwards compatibility - if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) || - string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase)) + if (baseUrl.Length == 0 + && (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase) + || string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))) + { + index++; + } + else if (string.Equals(first, baseUrl.Remove(0, 1))) { index++; + var second = pathInfo[1]; + if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase) + || string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase)) + { + index++; + } } return pathInfo[index]; diff --git a/MediaBrowser.Api/PackageService.cs b/MediaBrowser.Api/PackageService.cs index 0f04ab45c..1e5a93210 100644 --- a/MediaBrowser.Api/PackageService.cs +++ b/MediaBrowser.Api/PackageService.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Progress; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; @@ -133,7 +133,7 @@ namespace MediaBrowser.Api /// <returns>System.Object.</returns> public object Get(GetPackage request) { - var packages = _installationManager.GetAvailablePackages(CancellationToken.None, applicationVersion: typeof(PackageService).Assembly.GetName().Version).Result; + var packages = _installationManager.GetAvailablePackages().Result; var result = packages.FirstOrDefault(p => string.Equals(p.guid, request.AssemblyGuid ?? "none", StringComparison.OrdinalIgnoreCase)) ?? packages.FirstOrDefault(p => p.name.Equals(request.Name, StringComparison.OrdinalIgnoreCase)); @@ -148,7 +148,7 @@ namespace MediaBrowser.Api /// <returns>System.Object.</returns> public async Task<object> Get(GetPackages request) { - IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages(CancellationToken.None, false, request.PackageType, typeof(PackageService).Assembly.GetName().Version).ConfigureAwait(false); + IEnumerable<PackageInfo> packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); if (!string.IsNullOrEmpty(request.TargetSystems)) { @@ -157,11 +157,6 @@ namespace MediaBrowser.Api packages = packages.Where(p => apps.Contains(p.targetSystem)); } - if (request.IsPremium.HasValue) - { - packages = packages.Where(p => p.isPremium == request.IsPremium.Value); - } - if (request.IsAdult.HasValue) { packages = packages.Where(p => p.adult == request.IsAdult.Value); @@ -182,13 +177,21 @@ namespace MediaBrowser.Api /// <exception cref="ResourceNotFoundException"></exception> public async Task Post(InstallPackage request) { - var package = string.IsNullOrEmpty(request.Version) ? - await _installationManager.GetLatestCompatibleVersion(request.Name, request.AssemblyGuid, typeof(PackageService).Assembly.GetName().Version, request.UpdateClass).ConfigureAwait(false) : - await _installationManager.GetPackage(request.Name, request.AssemblyGuid, request.UpdateClass, Version.Parse(request.Version)).ConfigureAwait(false); + var packages = await _installationManager.GetAvailablePackages().ConfigureAwait(false); + var package = _installationManager.GetCompatibleVersions( + packages, + request.Name, + new Guid(request.AssemblyGuid), + string.IsNullOrEmpty(request.Version) ? null : Version.Parse(request.Version), + request.UpdateClass).FirstOrDefault(); if (package == null) { - throw new ResourceNotFoundException(string.Format("Package not found: {0}", request.Name)); + throw new ResourceNotFoundException( + string.Format( + CultureInfo.InvariantCulture, + "Package not found: {0}", + request.Name)); } await _installationManager.InstallPackage(package); diff --git a/MediaBrowser.Api/Session/SessionsService.cs b/MediaBrowser.Api/Session/SessionsService.cs index 76392e27c..6caf3b480 100644 --- a/MediaBrowser.Api/Session/SessionsService.cs +++ b/MediaBrowser.Api/Session/SessionsService.cs @@ -321,7 +321,7 @@ namespace MediaBrowser.Api.Session DateCreated = DateTime.UtcNow, DeviceId = _appHost.SystemId, DeviceName = _appHost.FriendlyName, - AppVersion = _appHost.ApplicationVersion + AppVersion = _appHost.ApplicationVersionString }); } diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index c8da100f6..6668e98aa 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -67,7 +67,13 @@ namespace MediaBrowser.Common /// Gets the application version. /// </summary> /// <value>The application version.</value> - string ApplicationVersion { get; } + Version ApplicationVersion { get; } + + /// <summary> + /// Gets the application version. + /// </summary> + /// <value>The application version.</value> + string ApplicationVersionString { get; } /// <summary> /// Gets the application user agent. diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index b3367f71d..524d8f3c6 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -13,87 +13,86 @@ namespace MediaBrowser.Common.Updates public interface IInstallationManager : IDisposable { event EventHandler<InstallationEventArgs> PackageInstalling; + event EventHandler<InstallationEventArgs> PackageInstallationCompleted; + event EventHandler<InstallationFailedEventArgs> PackageInstallationFailed; - event EventHandler<InstallationEventArgs> PackageInstallationCancelled; - /// <summary> - /// The completed installations - /// </summary> - IEnumerable<InstallationInfo> CompletedInstallations { get; } + event EventHandler<InstallationEventArgs> PackageInstallationCancelled; /// <summary> - /// Occurs when [plugin uninstalled]. + /// Occurs when a plugin is uninstalled. /// </summary> event EventHandler<GenericEventArgs<IPlugin>> PluginUninstalled; /// <summary> - /// Occurs when [plugin updated]. + /// Occurs when a plugin is updated. /// </summary> event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated; /// <summary> - /// Occurs when [plugin updated]. + /// Occurs when a plugin is installed. /// </summary> event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled; /// <summary> - /// Gets all available packages. + /// Gets the completed installations. /// </summary> - /// <param name="cancellationToken">The cancellation token.</param> - /// <param name="withRegistration">if set to <c>true</c> [with registration].</param> - /// <param name="packageType">Type of the package.</param> - /// <param name="applicationVersion">The application version.</param> - /// <returns>Task{List{PackageInfo}}.</returns> - Task<List<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken, - bool withRegistration = true, string packageType = null, Version applicationVersion = null); + IEnumerable<InstallationInfo> CompletedInstallations { get; } /// <summary> - /// Gets all available packages from a static resource. + /// Gets all available packages. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{List{PackageInfo}}.</returns> - Task<List<PackageInfo>> GetAvailablePackagesWithoutRegistrationInfo(CancellationToken cancellationToken); + /// <returns>Task{IReadOnlyList{PackageInfo}}.</returns> + Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default); /// <summary> - /// Gets the package. + /// Returns all plugins matching the requirements. /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid</param> - /// <param name="classification">The classification.</param> - /// <param name="version">The version.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - Task<PackageVersionInfo> GetPackage(string name, string guid, PackageVersionClass classification, Version version); + /// <param name="availablePackages">The available packages.</param> + /// <param name="name">The name of the plugin.</param> + /// <param name="guid">The id of the plugin.</param> + /// <returns>All plugins matching the requirements.</returns> + IEnumerable<PackageInfo> FilterPackages( + IEnumerable<PackageInfo> availablePackages, + string name = null, + Guid guid = default); /// <summary> - /// Gets the latest compatible version. + /// Returns all compatible versions ordered from newest to oldest. /// </summary> - /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid</param> - /// <param name="currentServerVersion">The current server version.</param> - /// <param name="classification">The classification.</param> - /// <returns>Task{PackageVersionInfo}.</returns> - Task<PackageVersionInfo> GetLatestCompatibleVersion(string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release); + /// <param name="availableVersions">The available version of the plugin.</param> + /// <param name="minVersion">The minimum required version of the plugin.</param> + /// <param name="classification">The classification of updates.</param> + /// <returns>All compatible versions ordered from newest to oldest.</returns> + IEnumerable<PackageVersionInfo> GetCompatibleVersions( + IEnumerable<PackageVersionInfo> availableVersions, + Version minVersion = null, + PackageVersionClass classification = PackageVersionClass.Release); /// <summary> - /// Gets the latest compatible version. + /// Returns all compatible versions ordered from newest to oldest. /// </summary> /// <param name="availablePackages">The available packages.</param> /// <param name="name">The name.</param> - /// <param name="guid">The assembly guid</param> - /// <param name="currentServerVersion">The current server version.</param> + /// <param name="guid">The guid of the plugin.</param> + /// <param name="minVersion">The minimum required version of the plugin.</param> /// <param name="classification">The classification.</param> - /// <returns>PackageVersionInfo.</returns> - PackageVersionInfo GetLatestCompatibleVersion(IEnumerable<PackageInfo> availablePackages, string name, string guid, Version currentServerVersion, PackageVersionClass classification = PackageVersionClass.Release); + /// <returns>All compatible versions ordered from newest to oldest.</returns> + IEnumerable<PackageVersionInfo> GetCompatibleVersions( + IEnumerable<PackageInfo> availablePackages, + string name = null, + Guid guid = default, + Version minVersion = null, + PackageVersionClass classification = PackageVersionClass.Release); /// <summary> - /// Gets the available plugin updates. + /// Returns the available plugin updates. /// </summary> - /// <param name="applicationVersion">The current server version.</param> - /// <param name="withAutoUpdateEnabled">if set to <c>true</c> [with auto update enabled].</param> /// <param name="cancellationToken">The cancellation token.</param> - /// <returns>Task{IEnumerable{PackageVersionInfo}}.</returns> - Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(Version applicationVersion, bool withAutoUpdateEnabled, CancellationToken cancellationToken); + /// <returns>The available plugin updates.</returns> + Task<IEnumerable<PackageVersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default); /// <summary> /// Installs the package. diff --git a/MediaBrowser.Model/Updates/PackageInfo.cs b/MediaBrowser.Model/Updates/PackageInfo.cs index ff4ed26d3..5dd9c6591 100644 --- a/MediaBrowser.Model/Updates/PackageInfo.cs +++ b/MediaBrowser.Model/Updates/PackageInfo.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace MediaBrowser.Model.Updates { @@ -150,7 +151,7 @@ namespace MediaBrowser.Model.Updates /// Gets or sets the versions. /// </summary> /// <value>The versions.</value> - public PackageVersionInfo[] versions { get; set; } + public IReadOnlyList<PackageVersionInfo> versions { get; set; } /// <summary> /// Gets or sets a value indicating whether [enable in application store]. diff --git a/MediaBrowser.Providers/TV/TheTVDB/TvdbUtils.cs b/MediaBrowser.Providers/TV/TheTVDB/TvdbUtils.cs index 112cbf800..dd5ebf270 100644 --- a/MediaBrowser.Providers/TV/TheTVDB/TvdbUtils.cs +++ b/MediaBrowser.Providers/TV/TheTVDB/TvdbUtils.cs @@ -1,5 +1,4 @@ using System; -using System.ComponentModel; using MediaBrowser.Model.Entities; namespace MediaBrowser.Providers.TV.TheTVDB { diff --git a/MediaBrowser.WebDashboard/Api/DashboardService.cs b/MediaBrowser.WebDashboard/Api/DashboardService.cs index d2ffd5efc..fadf32b28 100644 --- a/MediaBrowser.WebDashboard/Api/DashboardService.cs +++ b/MediaBrowser.WebDashboard/Api/DashboardService.cs @@ -205,7 +205,7 @@ namespace MediaBrowser.WebDashboard.Api return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => Task.FromResult(stream)); } - return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator(DashboardUIPath).ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersion, null)); + return _resultFactory.GetStaticResult(Request, plugin.Version.ToString().GetMD5(), null, null, MimeTypes.GetMimeType("page.html"), () => GetPackageCreator(DashboardUIPath).ModifyHtml("dummy.html", stream, null, _appHost.ApplicationVersionString, null)); } throw new ResourceNotFoundException(); @@ -342,7 +342,7 @@ namespace MediaBrowser.WebDashboard.Api cacheDuration = TimeSpan.FromDays(365); } - var cacheKey = (_appHost.ApplicationVersion + (localizationCulture ?? string.Empty) + path).GetMD5(); + var cacheKey = (_appHost.ApplicationVersionString + (localizationCulture ?? string.Empty) + path).GetMD5(); // html gets modified on the fly if (contentType.StartsWith("text/html", StringComparison.OrdinalIgnoreCase)) @@ -364,7 +364,7 @@ namespace MediaBrowser.WebDashboard.Api private Task<Stream> GetResourceStream(string basePath, string virtualPath, string localizationCulture) { return GetPackageCreator(basePath) - .GetResource(virtualPath, null, localizationCulture, _appHost.ApplicationVersion); + .GetResource(virtualPath, null, localizationCulture, _appHost.ApplicationVersionString); } private PackageCreator GetPackageCreator(string basePath) @@ -400,7 +400,7 @@ namespace MediaBrowser.WebDashboard.Api CopyDirectory(inputPath, targetPath); } - var appVersion = _appHost.ApplicationVersion; + var appVersion = _appHost.ApplicationVersionString; await DumpHtml(packageCreator, inputPath, targetPath, mode, appVersion); diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index bb40985a4..aa005b31d 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -6,7 +6,7 @@ </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.3.0" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> <PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="coverlet.collector" Version="1.1.0" /> diff --git a/tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs b/tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs index 28ccd6df1..dd1e04215 100644 --- a/tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs +++ b/tests/Jellyfin.Naming.Tests/EpisodePathParserTest.cs @@ -1,8 +1,9 @@ -namespace Emby.Naming.TV -{ - using Emby.Naming.Common; - using Xunit; +using Emby.Naming.Common; +using Emby.Naming.TV; +using Xunit; +namespace Jellyfin.Naming.Tests +{ public class EpisodePathParserTest { [Theory] @@ -21,8 +22,8 @@ namespace Emby.Naming.TV Assert.Equal(season, res.SeasonNumber); Assert.Equal(episode, res.EpisodeNumber); - //testing other paths delimeter - var res2 = p.Parse(path.Replace("/", "\\"), false); + // testing other paths delimeter + var res2 = p.Parse(path.Replace('/', '\\'), false); Assert.True(res2.Success); Assert.Equal(name, res2.SeriesName); Assert.Equal(season, res2.SeasonNumber); @@ -31,24 +32,24 @@ namespace Emby.Naming.TV [Theory] [InlineData("/media/Foo/Foo 889", "Foo", 889)] - [InlineData("/media/Foo/[Bar] Foo Baz - 11 [1080p]", "Foo Baz", 11)] + [InlineData("/media/Foo/[Bar] Foo Baz - 11 [1080p]", "Foo Baz", 11)] public void ParseEpisodeWithoutSeason(string path, string name, int episode) { NamingOptions o = new NamingOptions(); EpisodePathParser p = new EpisodePathParser(o); - var res = p.Parse(path, true, null, null, true); + var res = p.Parse(path, true, fillExtendedInfo: true); Assert.True(res.Success); Assert.Equal(name, res.SeriesName); - Assert.True(res.SeasonNumber == null); + Assert.Null(res.SeasonNumber); Assert.Equal(episode, res.EpisodeNumber); - //testing other paths delimeter - var res2 = p.Parse(path.Replace("/", "\\"), false, null, null, true); + // testing other paths delimeter + var res2 = p.Parse(path.Replace('/', '\\'), false, fillExtendedInfo: false); Assert.True(res2.Success); Assert.Equal(name, res2.SeriesName); - Assert.True(res2.SeasonNumber == null); + Assert.Null(res2.SeasonNumber); Assert.Equal(episode, res2.EpisodeNumber); } } -}
\ No newline at end of file +} diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index f5e151348..fe1518131 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -2,15 +2,14 @@ <PropertyGroup> <TargetFramework>netcoreapp3.0</TargetFramework> - <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> - <PackageReference Include="xunit" Version="2.4.0" /> - <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" /> - <PackageReference Include="coverlet.collector" Version="1.0.1" /> + <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> + <PackageReference Include="xunit" Version="2.4.1" /> + <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> + <PackageReference Include="coverlet.collector" Version="1.1.0" /> </ItemGroup> <ItemGroup> |
