diff options
Diffstat (limited to 'MediaBrowser.Common')
19 files changed, 181 insertions, 50 deletions
diff --git a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs index ccf965898..89740ae08 100644 --- a/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs +++ b/MediaBrowser.Common/Configuration/EncodingConfigurationExtensions.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using MediaBrowser.Model.Configuration; @@ -17,18 +18,25 @@ namespace MediaBrowser.Common.Configuration => configurationManager.GetConfiguration<EncodingOptions>("encoding"); /// <summary> - /// Retrieves the transcoding temp path from the encoding configuration. + /// Retrieves the transcoding temp path from the encoding configuration, falling back to a default if no path + /// is specified in configuration. If the directory does not exist, it will be created. /// </summary> - /// <param name="configurationManager">The Configuration manager.</param> + /// <param name="configurationManager">The configuration manager.</param> /// <returns>The transcoding temp path.</returns> + /// <exception cref="UnauthorizedAccessException">If the directory does not exist, and the caller does not have the required permission to create it.</exception> + /// <exception cref="NotSupportedException">If there is a custom path transcoding path specified, but it is invalid.</exception> + /// <exception cref="IOException">If the directory does not exist, and it also could not be created.</exception> public static string GetTranscodePath(this IConfigurationManager configurationManager) { + // Get the configured path and fall back to a default var transcodingTempPath = configurationManager.GetEncodingOptions().TranscodingTempPath; if (string.IsNullOrEmpty(transcodingTempPath)) { - return Path.Combine(configurationManager.CommonApplicationPaths.ProgramDataPath, "transcodes"); + transcodingTempPath = Path.Combine(configurationManager.CommonApplicationPaths.ProgramDataPath, "transcodes"); } + // Make sure the directory exists + Directory.CreateDirectory(transcodingTempPath); return transcodingTempPath; } } diff --git a/MediaBrowser.Common/Configuration/IApplicationPaths.cs b/MediaBrowser.Common/Configuration/IApplicationPaths.cs index 5bdea7d8b..870b90796 100644 --- a/MediaBrowser.Common/Configuration/IApplicationPaths.cs +++ b/MediaBrowser.Common/Configuration/IApplicationPaths.cs @@ -1,3 +1,5 @@ +using MediaBrowser.Model.Configuration; + namespace MediaBrowser.Common.Configuration { /// <summary> @@ -12,9 +14,12 @@ namespace MediaBrowser.Common.Configuration string ProgramDataPath { get; } /// <summary> - /// Gets the path to the web UI resources folder + /// Gets the path to the web UI resources folder. /// </summary> - /// <value>The web UI resources path.</value> + /// <remarks> + /// This value is not relevant if the server is configured to not host any static web content. Additionally, + /// the value for <see cref="ServerConfiguration.DashboardSourcePath"/> takes precedence over this one. + /// </remarks> string WebPath { get; } /// <summary> diff --git a/MediaBrowser.Common/Cryptography/Extensions.cs b/MediaBrowser.Common/Cryptography/CryptoExtensions.cs index 1e32a6d1a..157b0ed10 100644 --- a/MediaBrowser.Common/Cryptography/Extensions.cs +++ b/MediaBrowser.Common/Cryptography/CryptoExtensions.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.Common.Cryptography /// <summary> /// Class containing extension methods for working with Jellyfin cryptography objects. /// </summary> - public static class Extensions + public static class CryptoExtensions { /// <summary> /// Creates a new <see cref="PasswordHash" /> instance. diff --git a/MediaBrowser.Common/Extensions/BaseExtensions.cs b/MediaBrowser.Common/Extensions/BaseExtensions.cs index 08964420e..40020093b 100644 --- a/MediaBrowser.Common/Extensions/BaseExtensions.cs +++ b/MediaBrowser.Common/Extensions/BaseExtensions.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Security.Cryptography; using System.Text; diff --git a/MediaBrowser.Common/Extensions/CopyToExtensions.cs b/MediaBrowser.Common/Extensions/CopyToExtensions.cs index 2ecbc6539..94bf7c740 100644 --- a/MediaBrowser.Common/Extensions/CopyToExtensions.cs +++ b/MediaBrowser.Common/Extensions/CopyToExtensions.cs @@ -1,3 +1,5 @@ +#nullable enable + using System.Collections.Generic; namespace MediaBrowser.Common.Extensions diff --git a/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs b/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs index 48e758ee4..258bd6662 100644 --- a/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs +++ b/MediaBrowser.Common/Extensions/MethodNotAllowedException.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; namespace MediaBrowser.Common.Extensions diff --git a/MediaBrowser.Common/Extensions/ProcessExtensions.cs b/MediaBrowser.Common/Extensions/ProcessExtensions.cs new file mode 100644 index 000000000..2f52ba196 --- /dev/null +++ b/MediaBrowser.Common/Extensions/ProcessExtensions.cs @@ -0,0 +1,82 @@ +#nullable enable + +using System; +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Extensions +{ + /// <summary> + /// Extension methods for <see cref="Process"/>. + /// </summary> + public static class ProcessExtensions + { + /// <summary> + /// Asynchronously wait for the process to exit. + /// </summary> + /// <param name="process">The process to wait for.</param> + /// <param name="timeout">The duration to wait before cancelling waiting for the task.</param> + /// <returns>True if the task exited normally, false if the timeout elapsed before the process exited.</returns> + /// <exception cref="InvalidOperationException">If <see cref="Process.EnableRaisingEvents"/> is not set to true for the process.</exception> + public static async Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout) + { + using (var cancelTokenSource = new CancellationTokenSource(timeout)) + { + return await WaitForExitAsync(process, cancelTokenSource.Token).ConfigureAwait(false); + } + } + + /// <summary> + /// Asynchronously wait for the process to exit. + /// </summary> + /// <param name="process">The process to wait for.</param> + /// <param name="cancelToken">A <see cref="CancellationToken"/> to observe while waiting for the process to exit.</param> + /// <returns>True if the task exited normally, false if cancelled before the process exited.</returns> + public static async Task<bool> WaitForExitAsync(this Process process, CancellationToken cancelToken) + { + if (!process.EnableRaisingEvents) + { + throw new InvalidOperationException("EnableRisingEvents must be enabled to async wait for a task to exit."); + } + + // Add an event handler for the process exit event + var tcs = new TaskCompletionSource<bool>(); + process.Exited += (sender, args) => tcs.TrySetResult(true); + + // Return immediately if the process has already exited + if (process.HasExitedSafe()) + { + return true; + } + + // Register with the cancellation token then await + using (var cancelRegistration = cancelToken.Register(() => tcs.TrySetResult(process.HasExitedSafe()))) + { + return await tcs.Task.ConfigureAwait(false); + } + } + + /// <summary> + /// Gets a value indicating whether the associated process has been terminated using + /// <see cref="Process.HasExited"/>. This is safe to call even if there is no operating system process + /// associated with the <see cref="Process"/>. + /// </summary> + /// <param name="process">The process to check the exit status for.</param> + /// <returns> + /// True if the operating system process referenced by the <see cref="Process"/> component has + /// terminated, or if there is no associated operating system process; otherwise, false. + /// </returns> + private static bool HasExitedSafe(this Process process) + { + try + { + return process.HasExited; + } + catch (InvalidOperationException) + { + return true; + } + } + } +} diff --git a/MediaBrowser.Common/Extensions/RateLimitExceededException.cs b/MediaBrowser.Common/Extensions/RateLimitExceededException.cs index 95802a462..7c7bdaa92 100644 --- a/MediaBrowser.Common/Extensions/RateLimitExceededException.cs +++ b/MediaBrowser.Common/Extensions/RateLimitExceededException.cs @@ -1,3 +1,4 @@ +#nullable enable #pragma warning disable CS1591 using System; diff --git a/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs b/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs index 22130c5a1..ebac9d8e6 100644 --- a/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs +++ b/MediaBrowser.Common/Extensions/ResourceNotFoundException.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; namespace MediaBrowser.Common.Extensions diff --git a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs index 0432f36b5..459bec110 100644 --- a/MediaBrowser.Common/Extensions/ShuffleExtensions.cs +++ b/MediaBrowser.Common/Extensions/ShuffleExtensions.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; using System.Collections.Generic; diff --git a/MediaBrowser.Common/Extensions/StringExtensions.cs b/MediaBrowser.Common/Extensions/StringExtensions.cs new file mode 100644 index 000000000..764301741 --- /dev/null +++ b/MediaBrowser.Common/Extensions/StringExtensions.cs @@ -0,0 +1,37 @@ +#nullable enable + +using System; + +namespace MediaBrowser.Common.Extensions +{ + /// <summary> + /// Extensions methods to simplify string operations. + /// </summary> + public static class StringExtensions + { + /// <summary> + /// Returns the part on the left of the <c>needle</c>. + /// </summary> + /// <param name="haystack">The string to seek.</param> + /// <param name="needle">The needle to find.</param> + /// <returns>The part left of the <paramref name="needle" />.</returns> + public static ReadOnlySpan<char> LeftPart(this ReadOnlySpan<char> haystack, char needle) + { + var pos = haystack.IndexOf(needle); + return pos == -1 ? haystack : haystack[..pos]; + } + + /// <summary> + /// Returns the part on the left of the <c>needle</c>. + /// </summary> + /// <param name="haystack">The string to seek.</param> + /// <param name="needle">The needle to find.</param> + /// <param name="stringComparison">One of the enumeration values that specifies the rules for the search.</param> + /// <returns>The part left of the <c>needle</c>.</returns> + public static ReadOnlySpan<char> LeftPart(this ReadOnlySpan<char> haystack, ReadOnlySpan<char> needle, StringComparison stringComparison = default) + { + var pos = haystack.IndexOf(needle, stringComparison); + return pos == -1 ? haystack : haystack[..pos]; + } + } +} diff --git a/MediaBrowser.Common/IApplicationHost.cs b/MediaBrowser.Common/IApplicationHost.cs index 0e282cf53..e8d9282e4 100644 --- a/MediaBrowser.Common/IApplicationHost.cs +++ b/MediaBrowser.Common/IApplicationHost.cs @@ -2,8 +2,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using MediaBrowser.Common.Plugins; -using MediaBrowser.Model.Updates; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace MediaBrowser.Common @@ -49,12 +47,6 @@ namespace MediaBrowser.Common bool CanSelfRestart { get; } /// <summary> - /// Gets the version class of the system. - /// </summary> - /// <value><see cref="PackageVersionClass.Release" /> or <see cref="PackageVersionClass.Beta" />.</value> - PackageVersionClass SystemUpdateLevel { get; } - - /// <summary> /// Gets the application version. /// </summary> /// <value>The application version.</value> @@ -125,9 +117,7 @@ namespace MediaBrowser.Common /// Initializes this instance. /// </summary> /// <param name="serviceCollection">The service collection.</param> - /// <param name="startupConfig">The configuration to use for initialization.</param> - /// <returns>A task.</returns> - Task InitAsync(IServiceCollection serviceCollection, IConfiguration startupConfig); + void Init(IServiceCollection serviceCollection); /// <summary> /// Creates the instance. diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index 77eacf913..69864106c 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -1,5 +1,10 @@ <Project Sdk="Microsoft.NET.Sdk"> + <!-- ProjectGuid is only included as a requirement for SonarQube analysis --> + <PropertyGroup> + <ProjectGuid>{9142EEFA-7570-41E1-BFCC-468BB571AF2F}</ProjectGuid> + </PropertyGroup> + <PropertyGroup> <Authors>Jellyfin Contributors</Authors> <PackageId>Jellyfin.Common</PackageId> @@ -12,8 +17,8 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.2" /> - <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.2" /> + <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.3" /> + <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.3" /> <PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" /> </ItemGroup> @@ -30,7 +35,7 @@ <!-- Code analyzers--> <ItemGroup Condition=" '$(Configuration)' == 'Debug' "> - <!-- <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" /> --> + <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" 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" /> diff --git a/MediaBrowser.Common/Net/HttpRequestOptions.cs b/MediaBrowser.Common/Net/HttpRequestOptions.cs index 51962001e..38274a80e 100644 --- a/MediaBrowser.Common/Net/HttpRequestOptions.cs +++ b/MediaBrowser.Common/Net/HttpRequestOptions.cs @@ -20,7 +20,7 @@ namespace MediaBrowser.Common.Net RequestHeaders = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); CacheMode = CacheMode.None; - DecompressionMethod = CompressionMethod.Deflate; + DecompressionMethod = CompressionMethods.Deflate; } /// <summary> @@ -29,7 +29,7 @@ namespace MediaBrowser.Common.Net /// <value>The URL.</value> public string Url { get; set; } - public CompressionMethod DecompressionMethod { get; set; } + public CompressionMethods DecompressionMethod { get; set; } /// <summary> /// Gets or sets the accept header. @@ -83,8 +83,6 @@ namespace MediaBrowser.Common.Net public string RequestContent { get; set; } - public byte[] RequestContentBytes { get; set; } - public bool BufferContent { get; set; } public bool LogErrorResponseBody { get; set; } @@ -112,7 +110,7 @@ namespace MediaBrowser.Common.Net } [Flags] - public enum CompressionMethod + public enum CompressionMethods { None = 0b00000001, Deflate = 0b00000010, diff --git a/MediaBrowser.Common/Net/HttpResponseInfo.cs b/MediaBrowser.Common/Net/HttpResponseInfo.cs index d7f7a5622..d4fee6c78 100644 --- a/MediaBrowser.Common/Net/HttpResponseInfo.cs +++ b/MediaBrowser.Common/Net/HttpResponseInfo.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Common.Net /// <summary> /// Class HttpResponseInfo. /// </summary> - public class HttpResponseInfo : IDisposable + public sealed class HttpResponseInfo : IDisposable { #pragma warning disable CS1591 public HttpResponseInfo() @@ -22,7 +22,6 @@ namespace MediaBrowser.Common.Net } #pragma warning restore CS1591 -#pragma warning restore SA1600 /// <summary> /// Gets or sets the type of the content. diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs index b24d10ff1..9e4a360c3 100644 --- a/MediaBrowser.Common/Plugins/BasePlugin.cs +++ b/MediaBrowser.Common/Plugins/BasePlugin.cs @@ -67,7 +67,7 @@ namespace MediaBrowser.Common.Plugins } /// <summary> - /// Called when just before the plugin is uninstalled from the server. + /// Called just before the plugin is uninstalled from the server. /// </summary> public virtual void OnUninstalling() { @@ -101,7 +101,7 @@ namespace MediaBrowser.Common.Plugins private readonly object _configurationSyncLock = new object(); /// <summary> - /// The save lock. + /// The configuration save lock. /// </summary> private readonly object _configurationSaveLock = new object(); @@ -148,7 +148,7 @@ namespace MediaBrowser.Common.Plugins protected string AssemblyFileName => Path.GetFileName(AssemblyFilePath); /// <summary> - /// Gets or sets the plugin's configuration. + /// Gets or sets the plugin configuration. /// </summary> /// <value>The configuration.</value> public TConfigurationType Configuration @@ -186,7 +186,7 @@ namespace MediaBrowser.Common.Plugins public string ConfigurationFilePath => Path.Combine(ApplicationPaths.PluginConfigurationsPath, ConfigurationFileName); /// <summary> - /// Gets the plugin's configuration. + /// Gets the plugin configuration. /// </summary> /// <value>The configuration.</value> BasePluginConfiguration IHasPluginConfiguration.Configuration => Configuration; diff --git a/MediaBrowser.Common/System/OperatingSystem.cs b/MediaBrowser.Common/System/OperatingSystem.cs index 7d38ddb6e..5f673d320 100644 --- a/MediaBrowser.Common/System/OperatingSystem.cs +++ b/MediaBrowser.Common/System/OperatingSystem.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Common.System case OperatingSystemId.Linux: return "Linux"; case OperatingSystemId.Darwin: return "macOS"; case OperatingSystemId.Windows: return "Windows"; - default: throw new Exception($"Unknown OS {Id}"); + default: throw new PlatformNotSupportedException($"Unknown OS {Id}"); } } } @@ -53,20 +53,20 @@ namespace MediaBrowser.Common.System default: { string osDescription = RuntimeInformation.OSDescription; - if (osDescription.IndexOf("linux", StringComparison.OrdinalIgnoreCase) != -1) + if (osDescription.Contains("linux", StringComparison.OrdinalIgnoreCase)) { return OperatingSystemId.Linux; } - else if (osDescription.IndexOf("darwin", StringComparison.OrdinalIgnoreCase) != -1) + else if (osDescription.Contains("darwin", StringComparison.OrdinalIgnoreCase)) { return OperatingSystemId.Darwin; } - else if (osDescription.IndexOf("bsd", StringComparison.OrdinalIgnoreCase) != -1) + else if (osDescription.Contains("bsd", StringComparison.OrdinalIgnoreCase)) { return OperatingSystemId.BSD; } - throw new Exception($"Can't resolve OS with description: '{osDescription}'"); + throw new PlatformNotSupportedException($"Can't resolve OS with description: '{osDescription}'"); } } } diff --git a/MediaBrowser.Common/Updates/IInstallationManager.cs b/MediaBrowser.Common/Updates/IInstallationManager.cs index 8ea492261..950604432 100644 --- a/MediaBrowser.Common/Updates/IInstallationManager.cs +++ b/MediaBrowser.Common/Updates/IInstallationManager.cs @@ -28,12 +28,12 @@ namespace MediaBrowser.Common.Updates /// <summary> /// Occurs when a plugin is updated. /// </summary> - event EventHandler<GenericEventArgs<(IPlugin, PackageVersionInfo)>> PluginUpdated; + event EventHandler<GenericEventArgs<(IPlugin, VersionInfo)>> PluginUpdated; /// <summary> /// Occurs when a plugin is installed. /// </summary> - event EventHandler<GenericEventArgs<PackageVersionInfo>> PluginInstalled; + event EventHandler<GenericEventArgs<VersionInfo>> PluginInstalled; /// <summary> /// Gets the completed installations. @@ -64,12 +64,10 @@ namespace MediaBrowser.Common.Updates /// </summary> /// <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); + IEnumerable<VersionInfo> GetCompatibleVersions( + IEnumerable<VersionInfo> availableVersions, + Version minVersion = null); /// <summary> /// Returns all compatible versions ordered from newest to oldest. @@ -78,21 +76,19 @@ namespace MediaBrowser.Common.Updates /// <param name="name">The name.</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>All compatible versions ordered from newest to oldest.</returns> - IEnumerable<PackageVersionInfo> GetCompatibleVersions( + IEnumerable<VersionInfo> GetCompatibleVersions( IEnumerable<PackageInfo> availablePackages, string name = null, Guid guid = default, - Version minVersion = null, - PackageVersionClass classification = PackageVersionClass.Release); + Version minVersion = null); /// <summary> /// Returns the available plugin updates. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The available plugin updates.</returns> - IAsyncEnumerable<PackageVersionInfo> GetAvailablePluginUpdates(CancellationToken cancellationToken = default); + Task<IEnumerable<VersionInfo>> GetAvailablePluginUpdates(CancellationToken cancellationToken = default); /// <summary> /// Installs the package. @@ -100,7 +96,7 @@ namespace MediaBrowser.Common.Updates /// <param name="package">The package.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns><see cref="Task" />.</returns> - Task InstallPackage(PackageVersionInfo package, CancellationToken cancellationToken = default); + Task InstallPackage(VersionInfo package, CancellationToken cancellationToken = default); /// <summary> /// Uninstalls a plugin. diff --git a/MediaBrowser.Common/Updates/InstallationEventArgs.cs b/MediaBrowser.Common/Updates/InstallationEventArgs.cs index 36e124ddf..11eb2ad34 100644 --- a/MediaBrowser.Common/Updates/InstallationEventArgs.cs +++ b/MediaBrowser.Common/Updates/InstallationEventArgs.cs @@ -8,6 +8,6 @@ namespace MediaBrowser.Common.Updates { public InstallationInfo InstallationInfo { get; set; } - public PackageVersionInfo PackageVersionInfo { get; set; } + public VersionInfo VersionInfo { get; set; } } } |
