mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-09 03:04:24 -04:00
Merge branch 'master' into fordiscussion
This commit is contained in:
commit
2c5609b333
@ -28,6 +28,12 @@ jobs:
|
|||||||
inputs:
|
inputs:
|
||||||
script: "wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${{ parameters.GeneratorVersion }}/openapi-generator-cli-${{ parameters.GeneratorVersion }}.jar -O openapi-generator-cli.jar"
|
script: "wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/${{ parameters.GeneratorVersion }}/openapi-generator-cli-${{ parameters.GeneratorVersion }}.jar -O openapi-generator-cli.jar"
|
||||||
|
|
||||||
|
## Authenticate with npm registry
|
||||||
|
- task: npmAuthenticate@0
|
||||||
|
inputs:
|
||||||
|
workingFile: ./.npmrc
|
||||||
|
customEndpoint: 'jellyfin-bot for NPM'
|
||||||
|
|
||||||
## Generate npm api client
|
## Generate npm api client
|
||||||
# Unstable
|
# Unstable
|
||||||
- task: CmdLine@2
|
- task: CmdLine@2
|
||||||
|
3
.npmrc
Normal file
3
.npmrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
registry=https://registry.npmjs.org/
|
||||||
|
@jellyfin:registry=https://pkgs.dev.azure.com/jellyfin-project/jellyfin/_packaging/unstable/npm/registry/
|
||||||
|
always-auth=true
|
@ -1,3 +1,4 @@
|
|||||||
|
#nullable enable
|
||||||
#pragma warning disable CS1591
|
#pragma warning disable CS1591
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@ -16,21 +17,11 @@ namespace Emby.Naming.AudioBook
|
|||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AudioBookFileInfo ParseFile(string path)
|
public AudioBookFileInfo? Resolve(string path, bool isDirectory = false)
|
||||||
{
|
{
|
||||||
return Resolve(path, false);
|
if (path.Length == 0)
|
||||||
}
|
|
||||||
|
|
||||||
public AudioBookFileInfo ParseDirectory(string path)
|
|
||||||
{
|
|
||||||
return Resolve(path, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AudioBookFileInfo Resolve(string path, bool isDirectory = false)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(path));
|
throw new ArgumentException("String can't be empty.", nameof(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -128,7 +128,6 @@ namespace Emby.Server.Implementations
|
|||||||
private IMediaEncoder _mediaEncoder;
|
private IMediaEncoder _mediaEncoder;
|
||||||
private ISessionManager _sessionManager;
|
private ISessionManager _sessionManager;
|
||||||
private IHttpClientFactory _httpClientFactory;
|
private IHttpClientFactory _httpClientFactory;
|
||||||
private IWebSocketManager _webSocketManager;
|
|
||||||
private string[] _urlPrefixes;
|
private string[] _urlPrefixes;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -653,7 +652,6 @@ namespace Emby.Server.Implementations
|
|||||||
_mediaEncoder = Resolve<IMediaEncoder>();
|
_mediaEncoder = Resolve<IMediaEncoder>();
|
||||||
_sessionManager = Resolve<ISessionManager>();
|
_sessionManager = Resolve<ISessionManager>();
|
||||||
_httpClientFactory = Resolve<IHttpClientFactory>();
|
_httpClientFactory = Resolve<IHttpClientFactory>();
|
||||||
_webSocketManager = Resolve<IWebSocketManager>();
|
|
||||||
|
|
||||||
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
|
||||||
|
|
||||||
@ -788,7 +786,6 @@ namespace Emby.Server.Implementations
|
|||||||
}
|
}
|
||||||
|
|
||||||
_urlPrefixes = GetUrlPrefixes().ToArray();
|
_urlPrefixes = GetUrlPrefixes().ToArray();
|
||||||
_webSocketManager.Init(GetExports<IWebSocketListener>());
|
|
||||||
|
|
||||||
Resolve<ILibraryManager>().AddParts(
|
Resolve<ILibraryManager>().AddParts(
|
||||||
GetExports<IResolverIgnoreRule>(),
|
GetExports<IResolverIgnoreRule>(),
|
||||||
@ -1068,7 +1065,7 @@ namespace Emby.Server.Implementations
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Un-versioned folder - Add it under the path name and version 0.0.0.1.
|
// 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));
|
versions.Add((new Version(0, 0, 0, 1), metafile, dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,10 +32,10 @@
|
|||||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Mono.Nat" Version="3.0.0" />
|
<PackageReference Include="Mono.Nat" Version="3.0.0" />
|
||||||
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
|
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.4.0" />
|
||||||
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
|
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Data.Events;
|
using Jellyfin.Data.Events;
|
||||||
@ -14,16 +13,18 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
{
|
{
|
||||||
public class WebSocketManager : IWebSocketManager
|
public class WebSocketManager : IWebSocketManager
|
||||||
{
|
{
|
||||||
|
private readonly Lazy<IEnumerable<IWebSocketListener>> _webSocketListeners;
|
||||||
private readonly ILogger<WebSocketManager> _logger;
|
private readonly ILogger<WebSocketManager> _logger;
|
||||||
private readonly ILoggerFactory _loggerFactory;
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
private IWebSocketListener[] _webSocketListeners = Array.Empty<IWebSocketListener>();
|
|
||||||
private bool _disposed = false;
|
private bool _disposed = false;
|
||||||
|
|
||||||
public WebSocketManager(
|
public WebSocketManager(
|
||||||
|
Lazy<IEnumerable<IWebSocketListener>> webSocketListeners,
|
||||||
ILogger<WebSocketManager> logger,
|
ILogger<WebSocketManager> logger,
|
||||||
ILoggerFactory loggerFactory)
|
ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
|
_webSocketListeners = webSocketListeners;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
}
|
}
|
||||||
@ -68,15 +69,6 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the rest handlers.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="listeners">The web socket listeners.</param>
|
|
||||||
public void Init(IEnumerable<IWebSocketListener> listeners)
|
|
||||||
{
|
|
||||||
_webSocketListeners = listeners.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes the web socket message received.
|
/// Processes the web socket message received.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -90,7 +82,8 @@ namespace Emby.Server.Implementations.HttpServer
|
|||||||
|
|
||||||
IEnumerable<Task> GetTasks()
|
IEnumerable<Task> GetTasks()
|
||||||
{
|
{
|
||||||
foreach (var x in _webSocketListeners)
|
var listeners = _webSocketListeners.Value;
|
||||||
|
foreach (var x in listeners)
|
||||||
{
|
{
|
||||||
yield return x.ProcessMessageAsync(result);
|
yield return x.ProcessMessageAsync(result);
|
||||||
}
|
}
|
||||||
|
3
Emby.Server.Implementations/Localization/Core/hi.json
Normal file
3
Emby.Server.Implementations/Localization/Core/hi.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"Albums": "आल्बुम्"
|
||||||
|
}
|
@ -112,5 +112,5 @@
|
|||||||
"Artists": "Artistë",
|
"Artists": "Artistë",
|
||||||
"Application": "Aplikacioni",
|
"Application": "Aplikacioni",
|
||||||
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
|
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
|
||||||
"Albums": "Albumet"
|
"Albums": "Albume"
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"Channels": "Kanaler",
|
"Channels": "Kanaler",
|
||||||
"ChapterNameValue": "Kapitel {0}",
|
"ChapterNameValue": "Kapitel {0}",
|
||||||
"Collections": "Samlingar",
|
"Collections": "Samlingar",
|
||||||
"DeviceOfflineWithName": "{0} har kopplat från",
|
"DeviceOfflineWithName": "{0} har kopplat ner",
|
||||||
"DeviceOnlineWithName": "{0} är ansluten",
|
"DeviceOnlineWithName": "{0} är ansluten",
|
||||||
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
"FailedLoginAttemptWithUserName": "Misslyckat inloggningsförsök från {0}",
|
||||||
"Favorites": "Favoriter",
|
"Favorites": "Favoriter",
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.9" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" />
|
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.6.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.8" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.9" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -25,11 +25,11 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Linq.Async" Version="4.1.1" />
|
<PackageReference Include="System.Linq.Async" Version="4.1.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.8">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.9">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
@ -4,6 +4,8 @@ using System.IO;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Emby.Drawing;
|
using Emby.Drawing;
|
||||||
using Emby.Server.Implementations;
|
using Emby.Server.Implementations;
|
||||||
|
using Emby.Server.Implementations.Session;
|
||||||
|
using Jellyfin.Api.WebSocketListeners;
|
||||||
using Jellyfin.Drawing.Skia;
|
using Jellyfin.Drawing.Skia;
|
||||||
using Jellyfin.Server.Implementations;
|
using Jellyfin.Server.Implementations;
|
||||||
using Jellyfin.Server.Implementations.Activity;
|
using Jellyfin.Server.Implementations.Activity;
|
||||||
@ -14,6 +16,7 @@ using MediaBrowser.Controller;
|
|||||||
using MediaBrowser.Controller.Drawing;
|
using MediaBrowser.Controller.Drawing;
|
||||||
using MediaBrowser.Controller.Events;
|
using MediaBrowser.Controller.Events;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
using MediaBrowser.Controller.Net;
|
||||||
using MediaBrowser.Model.Activity;
|
using MediaBrowser.Model.Activity;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -80,6 +83,14 @@ namespace Jellyfin.Server
|
|||||||
ServiceCollection.AddSingleton<IUserManager, UserManager>();
|
ServiceCollection.AddSingleton<IUserManager, UserManager>();
|
||||||
ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
|
ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
|
||||||
|
|
||||||
|
ServiceCollection.AddScoped<IWebSocketListener, SessionWebSocketListener>();
|
||||||
|
ServiceCollection.AddScoped<IWebSocketListener, ActivityLogWebSocketListener>();
|
||||||
|
ServiceCollection.AddScoped<IWebSocketListener, ScheduledTasksWebSocketListener>();
|
||||||
|
ServiceCollection.AddScoped<IWebSocketListener, SessionInfoWebSocketListener>();
|
||||||
|
|
||||||
|
// TODO fix circular dependency on IWebSocketManager
|
||||||
|
ServiceCollection.AddScoped(serviceProvider => new Lazy<IEnumerable<IWebSocketListener>>(serviceProvider.GetRequiredService<IEnumerable<IWebSocketListener>>));
|
||||||
|
|
||||||
base.RegisterServices();
|
base.RegisterServices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,10 +38,10 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
<PackageReference Include="CommandLineParser" Version="2.8.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="3.1.9" />
|
||||||
<PackageReference Include="prometheus-net" Version="3.6.0" />
|
<PackageReference Include="prometheus-net" Version="3.6.0" />
|
||||||
<PackageReference Include="prometheus-net.AspNetCore" Version="3.6.0" />
|
<PackageReference Include="prometheus-net.AspNetCore" Version="3.6.0" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||||
|
@ -378,7 +378,7 @@ namespace Jellyfin.Server
|
|||||||
.ConfigureServices(services =>
|
.ConfigureServices(services =>
|
||||||
{
|
{
|
||||||
// Merge the external ServiceCollection into ASP.NET DI
|
// Merge the external ServiceCollection into ASP.NET DI
|
||||||
services.TryAdd(serviceCollection);
|
services.Add(serviceCollection);
|
||||||
})
|
})
|
||||||
.UseStartup<Startup>();
|
.UseStartup<Startup>();
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||||
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
|
<PackageReference Include="Microsoft.Net.Http.Headers" Version="2.2.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -451,11 +451,13 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var arg = new StringBuilder();
|
var arg = new StringBuilder();
|
||||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
||||||
var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty;
|
var outputVideoCodec = GetVideoEncoder(state, encodingOptions) ?? string.Empty;
|
||||||
|
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
||||||
|
var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
var isVaapiEncoder = outputVideoCodec.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
var isQsvDecoder = videoDecoder.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
var isQsvEncoder = outputVideoCodec.IndexOf("qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isNvencHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
|
var isNvdecHevcDecoder = videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
var isLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||||
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
var isMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
@ -517,11 +519,12 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (state.IsVideoRequest
|
if (state.IsVideoRequest
|
||||||
&& string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase))
|
&& (string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
|
||||||
|
|| (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
|
||||||
{
|
{
|
||||||
var isColorDepth10 = IsColorDepth10(state);
|
var isColorDepth10 = IsColorDepth10(state);
|
||||||
|
|
||||||
if (isNvencHevcDecoder && isColorDepth10
|
if (isColorDepth10
|
||||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||||
&& encodingOptions.EnableTonemapping
|
&& encodingOptions.EnableTonemapping
|
||||||
&& !string.IsNullOrEmpty(state.VideoStream.VideoRange)
|
&& !string.IsNullOrEmpty(state.VideoStream.VideoRange)
|
||||||
@ -880,6 +883,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
param += "-quality speed";
|
param += "-quality speed";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var videoStream = state.VideoStream;
|
||||||
|
var isColorDepth10 = IsColorDepth10(state);
|
||||||
|
|
||||||
|
if (isColorDepth10
|
||||||
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||||
|
&& encodingOptions.EnableTonemapping
|
||||||
|
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||||
|
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
// Enhance workload when tone mapping with AMF on some APUs
|
||||||
|
param += " -preanalysis true";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm
|
else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // webm
|
||||||
{
|
{
|
||||||
@ -1023,19 +1039,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
&& !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
&& !string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
&& !string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
|
&& !string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& !string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase)
|
||||||
&& !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
|
&& !string.Equals(videoEncoder, "h264_v4l2m2m", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
param = "-pix_fmt yuv420p " + param;
|
param = "-pix_fmt yuv420p " + param;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions) ?? string.Empty;
|
|
||||||
var videoStream = state.VideoStream;
|
var videoStream = state.VideoStream;
|
||||||
var isColorDepth10 = IsColorDepth10(state);
|
var isColorDepth10 = IsColorDepth10(state);
|
||||||
|
|
||||||
if (videoDecoder.IndexOf("hevc_cuvid", StringComparison.OrdinalIgnoreCase) != -1
|
if (isColorDepth10
|
||||||
&& isColorDepth10
|
|
||||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||||
&& encodingOptions.EnableTonemapping
|
&& encodingOptions.EnableTonemapping
|
||||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||||
@ -1651,47 +1667,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var outputSizeParam = ReadOnlySpan<char>.Empty;
|
var outputSizeParam = ReadOnlySpan<char>.Empty;
|
||||||
var request = state.BaseRequest;
|
var request = state.BaseRequest;
|
||||||
|
|
||||||
outputSizeParam = GetOutputSizeParam(state, options, outputVideoCodec).TrimEnd('"');
|
outputSizeParam = GetOutputSizeParamInternal(state, options, outputVideoCodec);
|
||||||
|
|
||||||
// All possible beginning of video filters
|
|
||||||
// Don't break the order
|
|
||||||
string[] beginOfOutputSizeParam = new[]
|
|
||||||
{
|
|
||||||
// for tonemap_opencl
|
|
||||||
"hwupload,tonemap_opencl",
|
|
||||||
|
|
||||||
// hwupload=extra_hw_frames=64,vpp_qsv (for overlay_qsv on linux)
|
|
||||||
"hwupload=extra_hw_frames",
|
|
||||||
|
|
||||||
// vpp_qsv
|
|
||||||
"vpp",
|
|
||||||
|
|
||||||
// hwdownload,format=p010le (hardware decode + software encode for vaapi)
|
|
||||||
"hwdownload",
|
|
||||||
|
|
||||||
// format=nv12|vaapi,hwupload,scale_vaapi
|
|
||||||
"format",
|
|
||||||
|
|
||||||
// bwdif,scale=expr
|
|
||||||
"bwdif",
|
|
||||||
|
|
||||||
// yadif,scale=expr
|
|
||||||
"yadif",
|
|
||||||
|
|
||||||
// scale=expr
|
|
||||||
"scale"
|
|
||||||
};
|
|
||||||
|
|
||||||
var index = -1;
|
|
||||||
foreach (var param in beginOfOutputSizeParam)
|
|
||||||
{
|
|
||||||
index = outputSizeParam.IndexOf(param, StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (index != -1)
|
|
||||||
{
|
|
||||||
outputSizeParam = outputSizeParam.Slice(index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var videoSizeParam = string.Empty;
|
var videoSizeParam = string.Empty;
|
||||||
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty;
|
var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options) ?? string.Empty;
|
||||||
@ -2083,10 +2059,19 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam);
|
return string.Format(CultureInfo.InvariantCulture, filter, widthParam, heightParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetOutputSizeParam(
|
||||||
|
EncodingJobInfo state,
|
||||||
|
EncodingOptions options,
|
||||||
|
string outputVideoCodec)
|
||||||
|
{
|
||||||
|
string filters = GetOutputSizeParamInternal(state, options, outputVideoCodec);
|
||||||
|
return string.IsNullOrEmpty(filters) ? string.Empty : " -vf \"" + filters + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If we're going to put a fixed size on the command line, this will calculate it.
|
/// If we're going to put a fixed size on the command line, this will calculate it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string GetOutputSizeParam(
|
public string GetOutputSizeParamInternal(
|
||||||
EncodingJobInfo state,
|
EncodingJobInfo state,
|
||||||
EncodingOptions options,
|
EncodingOptions options,
|
||||||
string outputVideoCodec)
|
string outputVideoCodec)
|
||||||
@ -2102,6 +2087,8 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var inputHeight = videoStream?.Height;
|
var inputHeight = videoStream?.Height;
|
||||||
var threeDFormat = state.MediaSource.Video3DFormat;
|
var threeDFormat = state.MediaSource.Video3DFormat;
|
||||||
|
|
||||||
|
var isSwDecoder = string.IsNullOrEmpty(videoDecoder);
|
||||||
|
var isD3d11vaDecoder = videoDecoder.IndexOf("d3d11va", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
var isVaapiDecoder = videoDecoder.IndexOf("vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
var isVaapiH264Encoder = outputVideoCodec.IndexOf("h264_vaapi", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
var isQsvH264Encoder = outputVideoCodec.IndexOf("h264_qsv", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
@ -2117,47 +2104,77 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
|
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
|
||||||
var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
|
var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
|
||||||
|
|
||||||
// Currently only with the use of NVENC decoder can we get a decent performance.
|
var isScalingInAdvance = false;
|
||||||
// Currently only the HEVC/H265 format is supported.
|
var isDeinterlaceH264 = state.DeInterlace("h264", true) || state.DeInterlace("avc", true);
|
||||||
// NVIDIA Pascal and Turing or higher are recommended.
|
var isDeinterlaceHevc = state.DeInterlace("h265", true) || state.DeInterlace("hevc", true);
|
||||||
if (isNvdecHevcDecoder && isColorDepth10
|
|
||||||
&& _mediaEncoder.SupportsHwaccel("opencl")
|
if ((string.Equals(options.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase) && isNvdecHevcDecoder || isSwDecoder)
|
||||||
&& options.EnableTonemapping
|
|| (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase) && isD3d11vaDecoder || isSwDecoder))
|
||||||
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
|
||||||
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
// Currently only with the use of NVENC decoder can we get a decent performance.
|
||||||
|
// Currently only the HEVC/H265 format is supported with NVDEC decoder.
|
||||||
if (options.TonemappingParam != 0)
|
// NVIDIA Pascal and Turing or higher are recommended.
|
||||||
|
// AMD Polaris and Vega or higher are recommended.
|
||||||
|
if (isColorDepth10
|
||||||
|
&& _mediaEncoder.SupportsHwaccel("opencl")
|
||||||
|
&& options.EnableTonemapping
|
||||||
|
&& !string.IsNullOrEmpty(videoStream.VideoRange)
|
||||||
|
&& videoStream.VideoRange.Contains("HDR", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
parameters += ":param={4}";
|
var parameters = "tonemap_opencl=format=nv12:primaries=bt709:transfer=bt709:matrix=bt709:tonemap={0}:desat={1}:threshold={2}:peak={3}";
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
if (options.TonemappingParam != 0)
|
||||||
{
|
{
|
||||||
parameters += ":range={5}";
|
parameters += ":param={4}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload the HDR10 or HLG data to the OpenCL device,
|
if (!string.Equals(options.TonemappingRange, "auto", StringComparison.OrdinalIgnoreCase))
|
||||||
// use tonemap_opencl filter for tone mapping,
|
{
|
||||||
// and then download the SDR data to memory.
|
parameters += ":range={5}";
|
||||||
filters.Add("hwupload");
|
}
|
||||||
filters.Add(
|
|
||||||
string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
parameters,
|
|
||||||
options.TonemappingAlgorithm,
|
|
||||||
options.TonemappingDesat,
|
|
||||||
options.TonemappingThreshold,
|
|
||||||
options.TonemappingPeak,
|
|
||||||
options.TonemappingParam,
|
|
||||||
options.TonemappingRange));
|
|
||||||
filters.Add("hwdownload");
|
|
||||||
|
|
||||||
if (hasGraphicalSubs || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)
|
if (isSwDecoder || isD3d11vaDecoder)
|
||||||
|| string.Equals(outputVideoCodec, "libx264", StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
{
|
isScalingInAdvance = true;
|
||||||
filters.Add("format=nv12");
|
// Add zscale filter before tone mapping filter for performance.
|
||||||
|
var (width, height) = GetFixedOutputSize(inputWidth, inputHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
|
||||||
|
if (width.HasValue && height.HasValue)
|
||||||
|
{
|
||||||
|
filters.Add(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"zscale=s={0}x{1}",
|
||||||
|
width.Value,
|
||||||
|
height.Value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert to hardware pixel format p010 when using SW decoder.
|
||||||
|
filters.Add("format=p010");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload the HDR10 or HLG data to the OpenCL device,
|
||||||
|
// use tonemap_opencl filter for tone mapping,
|
||||||
|
// and then download the SDR data to memory.
|
||||||
|
filters.Add("hwupload");
|
||||||
|
filters.Add(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
parameters,
|
||||||
|
options.TonemappingAlgorithm,
|
||||||
|
options.TonemappingDesat,
|
||||||
|
options.TonemappingThreshold,
|
||||||
|
options.TonemappingPeak,
|
||||||
|
options.TonemappingParam,
|
||||||
|
options.TonemappingRange));
|
||||||
|
filters.Add("hwdownload");
|
||||||
|
|
||||||
|
if (isLibX264Encoder
|
||||||
|
|| hasGraphicalSubs
|
||||||
|
|| (isNvdecHevcDecoder && isDeinterlaceHevc)
|
||||||
|
|| (!isNvdecHevcDecoder && isDeinterlaceH264 || isDeinterlaceHevc))
|
||||||
|
{
|
||||||
|
filters.Add("format=nv12");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2202,7 +2219,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add hardware deinterlace filter before scaling filter
|
// Add hardware deinterlace filter before scaling filter
|
||||||
if (state.DeInterlace("h264", true) || state.DeInterlace("avc", true))
|
if (isDeinterlaceH264)
|
||||||
{
|
{
|
||||||
if (isVaapiH264Encoder)
|
if (isVaapiH264Encoder)
|
||||||
{
|
{
|
||||||
@ -2215,10 +2232,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add software deinterlace filter before scaling filter
|
// Add software deinterlace filter before scaling filter
|
||||||
if ((state.DeInterlace("h264", true)
|
if ((isDeinterlaceH264 || isDeinterlaceHevc)
|
||||||
|| state.DeInterlace("avc", true)
|
|
||||||
|| state.DeInterlace("h265", true)
|
|
||||||
|| state.DeInterlace("hevc", true))
|
|
||||||
&& !isVaapiH264Encoder
|
&& !isVaapiH264Encoder
|
||||||
&& !isQsvH264Encoder
|
&& !isQsvH264Encoder
|
||||||
&& !isNvdecH264Decoder)
|
&& !isNvdecH264Decoder)
|
||||||
@ -2242,7 +2256,21 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr
|
// Add scaling filter: scale_*=format=nv12 or scale_*=w=*:h=*:format=nv12 or scale=expr
|
||||||
filters.AddRange(GetScalingFilters(state, inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight));
|
if (!isScalingInAdvance)
|
||||||
|
{
|
||||||
|
filters.AddRange(
|
||||||
|
GetScalingFilters(
|
||||||
|
state,
|
||||||
|
inputWidth,
|
||||||
|
inputHeight,
|
||||||
|
threeDFormat,
|
||||||
|
videoDecoder,
|
||||||
|
outputVideoCodec,
|
||||||
|
request.Width,
|
||||||
|
request.Height,
|
||||||
|
request.MaxWidth,
|
||||||
|
request.MaxHeight));
|
||||||
|
}
|
||||||
|
|
||||||
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
|
// Add parameters to use VAAPI with burn-in text subtitles (GH issue #642)
|
||||||
if (isVaapiH264Encoder)
|
if (isVaapiH264Encoder)
|
||||||
@ -2275,7 +2303,7 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
{
|
{
|
||||||
output += string.Format(
|
output += string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
" -vf \"{0}\"",
|
"{0}",
|
||||||
string.Join(",", filters));
|
string.Join(",", filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3068,21 +3096,31 @@ namespace MediaBrowser.Controller.MediaEncoding
|
|||||||
var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1);
|
var isWindows8orLater = Environment.OSVersion.Version.Major > 6 || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor > 1);
|
||||||
var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va");
|
var isDxvaSupported = _mediaEncoder.SupportsHwaccel("dxva2") || _mediaEncoder.SupportsHwaccel("d3d11va");
|
||||||
|
|
||||||
if ((isDxvaSupported || IsVaapiSupported(state)) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
if (string.Equals(options.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (isLinux)
|
// Currently there is no AMF decoder on Linux, only have h264 encoder.
|
||||||
|
if (isDxvaSupported && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "-hwaccel vaapi";
|
if (isWindows && isWindows8orLater)
|
||||||
}
|
{
|
||||||
|
return "-hwaccel d3d11va";
|
||||||
|
}
|
||||||
|
|
||||||
if (isWindows && isWindows8orLater)
|
if (isWindows && !isWindows8orLater)
|
||||||
{
|
{
|
||||||
return "-hwaccel d3d11va";
|
return "-hwaccel dxva2";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isWindows && !isWindows8orLater)
|
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (IsVaapiSupported(state) && options.HardwareDecodingCodecs.Contains(videoCodec, StringComparer.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return "-hwaccel dxva2";
|
if (isLinux)
|
||||||
|
{
|
||||||
|
return "-hwaccel vaapi";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,12 +16,6 @@ namespace MediaBrowser.Controller.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
|
event EventHandler<GenericEventArgs<IWebSocketConnection>> WebSocketConnected;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Inits this instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="listeners">The websocket listeners.</param>
|
|
||||||
void Init(IEnumerable<IWebSocketListener> listeners);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The HTTP request handler.
|
/// The HTTP request handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -666,6 +666,16 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
|
stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate);
|
||||||
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
|
stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate);
|
||||||
|
|
||||||
|
// Interlaced video streams in Matroska containers return the field rate instead of the frame rate
|
||||||
|
// as both the average and real frame rate, so we half the returned frame rates to get the correct values
|
||||||
|
//
|
||||||
|
// https://gitlab.com/mbunkus/mkvtoolnix/-/wikis/Wrong-frame-rate-displayed
|
||||||
|
if (stream.IsInterlaced && formatInfo.FormatName.Contains("matroska", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
stream.AverageFrameRate /= 2;
|
||||||
|
stream.RealFrameRate /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) ||
|
if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) ||
|
||||||
string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase))
|
string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="5.0.0-preview.8.20407.11" />
|
<PackageReference Include="System.Text.Json" Version="5.0.0-preview.8.20407.11" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -43,7 +43,10 @@ namespace MediaBrowser.Model.System
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether the startup wizard is completed.
|
/// Gets or sets a value indicating whether the startup wizard is completed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The startup completion status.</value>
|
/// <remarks>
|
||||||
public bool StartupWizardCompleted { get; set; }
|
/// Nullable for OpenAPI specification only to retain backwards compatibility in apiclients.
|
||||||
|
/// </remarks>
|
||||||
|
/// <value>The startup completion status.</value>]
|
||||||
|
public bool? StartupWizardCompleted { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.9" />
|
||||||
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
|
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
|
||||||
<PackageReference Include="PlaylistsNET" Version="1.1.2" />
|
<PackageReference Include="PlaylistsNET" Version="1.1.2" />
|
||||||
<PackageReference Include="TMDbLib" Version="1.7.3-alpha" />
|
<PackageReference Include="TMDbLib" Version="1.7.3-alpha" />
|
||||||
|
@ -46,6 +46,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
|
|
||||||
private readonly string _musicBrainzBaseUrl;
|
private readonly string _musicBrainzBaseUrl;
|
||||||
|
|
||||||
|
private SemaphoreSlim _apiRequestLock = new SemaphoreSlim(1, 1);
|
||||||
private Stopwatch _stopWatchMusicBrainz = new Stopwatch();
|
private Stopwatch _stopWatchMusicBrainz = new Stopwatch();
|
||||||
|
|
||||||
public MusicBrainzAlbumProvider(
|
public MusicBrainzAlbumProvider(
|
||||||
@ -742,48 +743,58 @@ namespace MediaBrowser.Providers.Music
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal async Task<HttpResponseMessage> GetMusicBrainzResponse(string url, CancellationToken cancellationToken)
|
internal async Task<HttpResponseMessage> GetMusicBrainzResponse(string url, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using var options = new HttpRequestMessage(HttpMethod.Get, _musicBrainzBaseUrl.TrimEnd('/') + url);
|
await _apiRequestLock.WaitAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// MusicBrainz request a contact email address is supplied, as comment, in user agent field:
|
try
|
||||||
// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent
|
|
||||||
options.Headers.UserAgent.ParseAdd(string.Format(
|
|
||||||
CultureInfo.InvariantCulture,
|
|
||||||
"{0} ( {1} )",
|
|
||||||
_appHost.ApplicationUserAgent,
|
|
||||||
_appHost.ApplicationUserAgentAddress));
|
|
||||||
|
|
||||||
HttpResponseMessage response;
|
|
||||||
var attempts = 0u;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
attempts++;
|
HttpResponseMessage response;
|
||||||
|
var attempts = 0u;
|
||||||
|
var requestUrl = _musicBrainzBaseUrl.TrimEnd('/') + url;
|
||||||
|
|
||||||
if (_stopWatchMusicBrainz.ElapsedMilliseconds < _musicBrainzQueryIntervalMs)
|
do
|
||||||
{
|
{
|
||||||
// MusicBrainz is extremely adamant about limiting to one request per second
|
attempts++;
|
||||||
var delayMs = _musicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
|
|
||||||
await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false);
|
if (_stopWatchMusicBrainz.ElapsedMilliseconds < _musicBrainzQueryIntervalMs)
|
||||||
|
{
|
||||||
|
// MusicBrainz is extremely adamant about limiting to one request per second.
|
||||||
|
var delayMs = _musicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
|
||||||
|
await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write time since last request to debug log as evidence we're meeting rate limit
|
||||||
|
// requirement, before resetting stopwatch back to zero.
|
||||||
|
_logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds);
|
||||||
|
_stopWatchMusicBrainz.Restart();
|
||||||
|
|
||||||
|
using var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
|
||||||
|
|
||||||
|
// MusicBrainz request a contact email address is supplied, as comment, in user agent field:
|
||||||
|
// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting#User-Agent .
|
||||||
|
request.Headers.UserAgent.ParseAdd(string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"{0} ( {1} )",
|
||||||
|
_appHost.ApplicationUserAgent,
|
||||||
|
_appHost.ApplicationUserAgentAddress));
|
||||||
|
|
||||||
|
response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(request).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// We retry a finite number of times, and only whilst MB is indicating 503 (throttling).
|
||||||
|
}
|
||||||
|
while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable);
|
||||||
|
|
||||||
|
// Log error if unable to query MB database due to throttling.
|
||||||
|
if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable)
|
||||||
|
{
|
||||||
|
_logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, requestUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write time since last request to debug log as evidence we're meeting rate limit
|
return response;
|
||||||
// requirement, before resetting stopwatch back to zero.
|
|
||||||
_logger.LogDebug("GetMusicBrainzResponse: Time since previous request: {0} ms", _stopWatchMusicBrainz.ElapsedMilliseconds);
|
|
||||||
_stopWatchMusicBrainz.Restart();
|
|
||||||
|
|
||||||
response = await _httpClientFactory.CreateClient(NamedClient.Default).SendAsync(options).ConfigureAwait(false);
|
|
||||||
|
|
||||||
// We retry a finite number of times, and only whilst MB is indicating 503 (throttling)
|
|
||||||
}
|
}
|
||||||
while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable);
|
finally
|
||||||
|
|
||||||
// Log error if unable to query MB database due to throttling
|
|
||||||
if (attempts == MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable)
|
|
||||||
{
|
{
|
||||||
_logger.LogError("GetMusicBrainzResponse: 503 Service Unavailable (throttled) response received {0} times whilst requesting {1}", attempts, options.RequestUri);
|
_apiRequestLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
4
debian/postrm
vendored
4
debian/postrm
vendored
@ -25,7 +25,7 @@ case "$1" in
|
|||||||
purge)
|
purge)
|
||||||
echo PURGE | debconf-communicate $NAME > /dev/null 2>&1 || true
|
echo PURGE | debconf-communicate $NAME > /dev/null 2>&1 || true
|
||||||
|
|
||||||
if [[ -x "/etc/init.d/jellyfin" ]] || [[ -e "/etc/init/jellyfin.connf" ]]; then
|
if [[ -x "/etc/init.d/jellyfin" ]] || [[ -e "/etc/init/jellyfin.conf" ]]; then
|
||||||
update-rc.d jellyfin remove >/dev/null 2>&1 || true
|
update-rc.d jellyfin remove >/dev/null 2>&1 || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ case "$1" in
|
|||||||
rm -rf $PROGRAMDATA
|
rm -rf $PROGRAMDATA
|
||||||
fi
|
fi
|
||||||
# Remove binary symlink
|
# Remove binary symlink
|
||||||
[[ -f /usr/bin/jellyfin ]] && rm /usr/bin/jellyfin
|
rm -f /usr/bin/jellyfin
|
||||||
# Remove sudoers config
|
# Remove sudoers config
|
||||||
[[ -f /etc/sudoers.d/jellyfin-sudoers ]] && rm /etc/sudoers.d/jellyfin-sudoers
|
[[ -f /etc/sudoers.d/jellyfin-sudoers ]] && rm /etc/sudoers.d/jellyfin-sudoers
|
||||||
# Remove anything at the default locations; catches situations where the user moved the defaults
|
# Remove anything at the default locations; catches situations where the user moved the defaults
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -15,7 +15,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,7 +16,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -15,7 +15,7 @@ RUN apt-get update \
|
|||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
# https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current
|
||||||
RUN wget https://download.visualstudio.microsoft.com/download/pr/f01e3d97-c1c3-4635-bc77-0c893be36820/6ec6acabc22468c6cc68b61625b14a7d/dotnet-sdk-3.1.402-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
||||||
&& mkdir -p dotnet-sdk \
|
&& mkdir -p dotnet-sdk \
|
||||||
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
&& tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \
|
||||||
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
&& ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
<PackageReference Include="AutoFixture" Version="4.13.0" />
|
<PackageReference Include="AutoFixture" Version="4.13.0" />
|
||||||
<PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" />
|
<PackageReference Include="AutoFixture.AutoMoq" Version="4.13.0" />
|
||||||
<PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" />
|
<PackageReference Include="AutoFixture.Xunit2" Version="4.13.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.8" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.8" />
|
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.9" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||||
<PackageReference Include="xunit" Version="2.4.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Emby.Naming.AudioBook;
|
using Emby.Naming.AudioBook;
|
||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@ -42,16 +43,22 @@ namespace Jellyfin.Naming.Tests.AudioBook
|
|||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(GetResolveFileTestData))]
|
[MemberData(nameof(GetResolveFileTestData))]
|
||||||
public void ResolveFile_ValidFileName_Success(AudioBookFileInfo expectedResult)
|
public void Resolve_ValidFileName_Success(AudioBookFileInfo expectedResult)
|
||||||
{
|
{
|
||||||
var result = new AudioBookResolver(_namingOptions).Resolve(expectedResult.Path);
|
var result = new AudioBookResolver(_namingOptions).Resolve(expectedResult.Path);
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(result.Path, expectedResult.Path);
|
Assert.Equal(result!.Path, expectedResult.Path);
|
||||||
Assert.Equal(result.Container, expectedResult.Container);
|
Assert.Equal(result!.Container, expectedResult.Container);
|
||||||
Assert.Equal(result.ChapterNumber, expectedResult.ChapterNumber);
|
Assert.Equal(result!.ChapterNumber, expectedResult.ChapterNumber);
|
||||||
Assert.Equal(result.PartNumber, expectedResult.PartNumber);
|
Assert.Equal(result!.PartNumber, expectedResult.PartNumber);
|
||||||
Assert.Equal(result.IsDirectory, expectedResult.IsDirectory);
|
Assert.Equal(result!.IsDirectory, expectedResult.IsDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Resolve_EmptyFileName_ArgumentException()
|
||||||
|
{
|
||||||
|
Assert.Throws<ArgumentException>(() => new AudioBookResolver(_namingOptions).Resolve(string.Empty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user