mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-31 14:33:54 -04:00
commit
6d1abf67c3
@ -7,7 +7,7 @@ parameters:
|
|||||||
default: "ubuntu-latest"
|
default: "ubuntu-latest"
|
||||||
- name: DotNetSdkVersion
|
- name: DotNetSdkVersion
|
||||||
type: string
|
type: string
|
||||||
default: 7.0.x
|
default: 8.0.x
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: CompatibilityCheck
|
- job: CompatibilityCheck
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
parameters:
|
parameters:
|
||||||
LinuxImage: 'ubuntu-latest'
|
LinuxImage: 'ubuntu-latest'
|
||||||
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
RestoreBuildProjects: 'Jellyfin.Server/Jellyfin.Server.csproj'
|
||||||
DotNetSdkVersion: 7.0.x
|
DotNetSdkVersion: 8.0.x
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: Build
|
- job: Build
|
||||||
|
@ -208,10 +208,10 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- task: UseDotNet@2
|
- task: UseDotNet@2
|
||||||
displayName: 'Use .NET 7.0 sdk'
|
displayName: 'Use .NET 8.0 sdk'
|
||||||
inputs:
|
inputs:
|
||||||
packageType: 'sdk'
|
packageType: 'sdk'
|
||||||
version: '7.0.x'
|
version: '8.0.x'
|
||||||
|
|
||||||
- task: DotNetCoreCLI@2
|
- task: DotNetCoreCLI@2
|
||||||
displayName: 'Build Stable Nuget packages'
|
displayName: 'Build Stable Nuget packages'
|
||||||
|
@ -10,7 +10,7 @@ parameters:
|
|||||||
default: "tests/**/*Tests.csproj"
|
default: "tests/**/*Tests.csproj"
|
||||||
- name: DotNetSdkVersion
|
- name: DotNetSdkVersion
|
||||||
type: string
|
type: string
|
||||||
default: 7.0.x
|
default: 8.0.x
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
- job: Test
|
- job: Test
|
||||||
@ -94,5 +94,5 @@ jobs:
|
|||||||
displayName: 'Publish OpenAPI Artifact'
|
displayName: 'Publish OpenAPI Artifact'
|
||||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
|
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
|
||||||
inputs:
|
inputs:
|
||||||
targetPath: "tests/Jellyfin.Server.Integration.Tests/bin/Release/net7.0/openapi.json"
|
targetPath: "tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json"
|
||||||
artifactName: 'OpenAPI Spec'
|
artifactName: 'OpenAPI Spec'
|
||||||
|
2
.github/workflows/ci-codeql-analysis.yml
vendored
2
.github/workflows/ci-codeql-analysis.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '7.0.x'
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6
|
uses: github/codeql-action/init@689fdc5193eeb735ecb2e52e819e3382876f93f4 # v2.22.6
|
||||||
|
8
.github/workflows/ci-openapi.yml
vendored
8
.github/workflows/ci-openapi.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '7.0.x'
|
dotnet-version: '8.0.x'
|
||||||
- name: Generate openapi.json
|
- name: Generate openapi.json
|
||||||
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
|
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
|
||||||
- name: Upload openapi.json
|
- name: Upload openapi.json
|
||||||
@ -30,7 +30,7 @@ jobs:
|
|||||||
name: openapi-head
|
name: openapi-head
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net7.0/openapi.json
|
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
|
||||||
|
|
||||||
openapi-base:
|
openapi-base:
|
||||||
name: OpenAPI - BASE
|
name: OpenAPI - BASE
|
||||||
@ -55,7 +55,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
uses: actions/setup-dotnet@3447fd6a9f9e57506b15f895c5b76d3b197dc7c2 # v3.2.0
|
||||||
with:
|
with:
|
||||||
dotnet-version: '7.0.x'
|
dotnet-version: '8.0.x'
|
||||||
- name: Generate openapi.json
|
- name: Generate openapi.json
|
||||||
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
|
run: dotnet test tests/Jellyfin.Server.Integration.Tests/Jellyfin.Server.Integration.Tests.csproj -c Release --filter "Jellyfin.Server.Integration.Tests.OpenApiSpecTests"
|
||||||
- name: Upload openapi.json
|
- name: Upload openapi.json
|
||||||
@ -64,7 +64,7 @@ jobs:
|
|||||||
name: openapi-base
|
name: openapi-base
|
||||||
retention-days: 14
|
retention-days: 14
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net7.0/openapi.json
|
path: tests/Jellyfin.Server.Integration.Tests/bin/Release/net8.0/openapi.json
|
||||||
|
|
||||||
openapi-diff:
|
openapi-diff:
|
||||||
permissions:
|
permissions:
|
||||||
|
2
.github/workflows/ci-tests.yml
vendored
2
.github/workflows/ci-tests.yml
vendored
@ -9,7 +9,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
SDK_VERSION: "7.0.x"
|
SDK_VERSION: "8.0.x"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
run-tests:
|
run-tests:
|
||||||
|
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -6,7 +6,7 @@
|
|||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net7.0/jellyfin.dll",
|
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
|
||||||
"args": [],
|
"args": [],
|
||||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
@ -22,7 +22,7 @@
|
|||||||
"type": "coreclr",
|
"type": "coreclr",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"preLaunchTask": "build",
|
"preLaunchTask": "build",
|
||||||
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net7.0/jellyfin.dll",
|
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/net8.0/jellyfin.dll",
|
||||||
"args": ["--nowebclient"],
|
"args": ["--nowebclient"],
|
||||||
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
"cwd": "${workspaceFolder}/Jellyfin.Server",
|
||||||
"console": "internalConsole",
|
"console": "internalConsole",
|
||||||
|
@ -23,30 +23,30 @@
|
|||||||
<PackageVersion Include="libse" Version="3.6.13" />
|
<PackageVersion Include="libse" Version="3.6.13" />
|
||||||
<PackageVersion Include="LrcParser" Version="2023.524.0" />
|
<PackageVersion Include="LrcParser" Version="2023.524.0" />
|
||||||
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="5.0.1" />
|
<PackageVersion Include="MetaBrainz.MusicBrainz" Version="5.0.1" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.AspNetCore.Authorization" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
|
<PackageVersion Include="Microsoft.AspNetCore.HttpOverrides" Version="2.2.0" />
|
||||||
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.BannedApiAnalyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.Data.Sqlite" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Relational" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
|
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="7.0.13" />
|
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Http" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.Extensions.Options" Version="7.0.1" />
|
<PackageVersion Include="Microsoft.Extensions.Options" Version="8.0.0" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
|
||||||
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
|
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
|
||||||
<PackageVersion Include="MimeTypes" Version="2.4.0" />
|
<PackageVersion Include="MimeTypes" Version="2.4.0" />
|
||||||
@ -77,9 +77,9 @@
|
|||||||
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
<PackageVersion Include="Swashbuckle.AspNetCore" Version="6.2.3" />
|
||||||
<PackageVersion Include="System.Globalization" Version="4.3.0" />
|
<PackageVersion Include="System.Globalization" Version="4.3.0" />
|
||||||
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
|
<PackageVersion Include="System.Linq.Async" Version="6.0.1" />
|
||||||
<PackageVersion Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
<PackageVersion Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.Text.Json" Version="7.0.3" />
|
<PackageVersion Include="System.Text.Json" Version="8.0.0" />
|
||||||
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="7.0.0" />
|
<PackageVersion Include="System.Threading.Tasks.Dataflow" Version="8.0.0" />
|
||||||
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
|
<PackageVersion Include="TagLibSharp" Version="2.3.0" />
|
||||||
<PackageVersion Include="TMDbLib" Version="2.0.0" />
|
<PackageVersion Include="TMDbLib" Version="2.0.0" />
|
||||||
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
|
<PackageVersion Include="UTF.Unknown" Version="2.5.1" />
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#####################################
|
#####################################
|
||||||
# Requires binfm_misc registration
|
# Requires binfm_misc registration
|
||||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||||
ARG DOTNET_VERSION=7.0
|
ARG DOTNET_VERSION=8.0
|
||||||
|
|
||||||
FROM node:20-alpine as web-builder
|
FROM node:20-alpine as web-builder
|
||||||
ARG JELLYFIN_WEB_VERSION=master
|
ARG JELLYFIN_WEB_VERSION=master
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#####################################
|
#####################################
|
||||||
# Requires binfm_misc registration
|
# Requires binfm_misc registration
|
||||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||||
ARG DOTNET_VERSION=7.0
|
ARG DOTNET_VERSION=8.0
|
||||||
|
|
||||||
|
|
||||||
FROM node:20-alpine as web-builder
|
FROM node:20-alpine as web-builder
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#####################################
|
#####################################
|
||||||
# Requires binfm_misc registration
|
# Requires binfm_misc registration
|
||||||
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
|
||||||
ARG DOTNET_VERSION=7.0
|
ARG DOTNET_VERSION=8.0
|
||||||
|
|
||||||
|
|
||||||
FROM node:20-alpine as web-builder
|
FROM node:20-alpine as web-builder
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -99,6 +99,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Prometheus.DotNetRuntime;
|
using Prometheus.DotNetRuntime;
|
||||||
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
|
using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations
|
namespace Emby.Server.Implementations
|
||||||
@ -309,7 +310,9 @@ namespace Emby.Server.Implementations
|
|||||||
{
|
{
|
||||||
_creatingInstances.Add(type);
|
_creatingInstances.Add(type);
|
||||||
Logger.LogDebug("Creating instance of {Type}", type);
|
Logger.LogDebug("Creating instance of {Type}", type);
|
||||||
return ActivatorUtilities.CreateInstance(ServiceProvider, type);
|
return ServiceProvider is null
|
||||||
|
? Activator.CreateInstance(type)
|
||||||
|
: ActivatorUtilities.CreateInstance(ServiceProvider, type);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -12,6 +12,7 @@ using MediaBrowser.Controller;
|
|||||||
using MediaBrowser.Controller.Plugins;
|
using MediaBrowser.Controller.Plugins;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.EntryPoints
|
namespace Emby.Server.Implementations.EntryPoints
|
||||||
{
|
{
|
||||||
|
@ -84,15 +84,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Close()
|
public async Task Close()
|
||||||
{
|
{
|
||||||
EnableStreamSharing = false;
|
EnableStreamSharing = false;
|
||||||
|
|
||||||
Logger.LogInformation("Closing {Type}", GetType().Name);
|
Logger.LogInformation("Closing {Type}", GetType().Name);
|
||||||
|
|
||||||
LiveStreamCancellationTokenSource.Cancel();
|
await LiveStreamCancellationTokenSource.CancelAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream GetStream()
|
public Stream GetStream()
|
||||||
|
@ -27,13 +27,12 @@ namespace Jellyfin.Api.Auth
|
|||||||
/// <param name="options">Options monitor.</param>
|
/// <param name="options">Options monitor.</param>
|
||||||
/// <param name="logger">The logger.</param>
|
/// <param name="logger">The logger.</param>
|
||||||
/// <param name="encoder">The url encoder.</param>
|
/// <param name="encoder">The url encoder.</param>
|
||||||
/// <param name="clock">The system clock.</param>
|
|
||||||
public CustomAuthenticationHandler(
|
public CustomAuthenticationHandler(
|
||||||
IAuthService authService,
|
IAuthService authService,
|
||||||
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
ILoggerFactory logger,
|
ILoggerFactory logger,
|
||||||
UrlEncoder encoder,
|
UrlEncoder encoder)
|
||||||
ISystemClock clock) : base(options, logger, encoder, clock)
|
: base(options, logger, encoder)
|
||||||
{
|
{
|
||||||
_authService = authService;
|
_authService = authService;
|
||||||
_logger = logger.CreateLogger<CustomAuthenticationHandler>();
|
_logger = logger.CreateLogger<CustomAuthenticationHandler>();
|
||||||
|
@ -169,7 +169,7 @@ public class EnvironmentController : BaseJellyfinApiController
|
|||||||
// Check if unc share
|
// Check if unc share
|
||||||
var index = path.LastIndexOf(UncSeparator);
|
var index = path.LastIndexOf(UncSeparator);
|
||||||
|
|
||||||
if (index != -1 && path.IndexOf(UncSeparator, StringComparison.OrdinalIgnoreCase) == 0)
|
if (index != -1 && path[0] == UncSeparator)
|
||||||
{
|
{
|
||||||
parent = path.Substring(0, index);
|
parent = path.Substring(0, index);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ public class HlsSegmentController : BaseJellyfinApiController
|
|||||||
var pathExtension = Path.GetExtension(path);
|
var pathExtension = Path.GetExtension(path);
|
||||||
if ((string.Equals(pathExtension, segmentContainer, StringComparison.OrdinalIgnoreCase)
|
if ((string.Equals(pathExtension, segmentContainer, StringComparison.OrdinalIgnoreCase)
|
||||||
|| string.Equals(pathExtension, ".m3u8", StringComparison.OrdinalIgnoreCase))
|
|| string.Equals(pathExtension, ".m3u8", StringComparison.OrdinalIgnoreCase))
|
||||||
&& path.IndexOf(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase) != -1)
|
&& path.Contains(normalizedPlaylistId, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
playlistPath = path;
|
playlistPath = path;
|
||||||
break;
|
break;
|
||||||
|
@ -80,7 +80,7 @@ public class ImageController : BaseJellyfinApiController
|
|||||||
_appPaths = appPaths;
|
_appPaths = appPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream GetFromBase64Stream(Stream inputStream)
|
private static CryptoStream GetFromBase64Stream(Stream inputStream)
|
||||||
=> new CryptoStream(inputStream, new FromBase64Transform(), CryptoStreamMode.Read);
|
=> new CryptoStream(inputStream, new FromBase64Transform(), CryptoStreamMode.Read);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -2080,30 +2080,30 @@ public class ImageController : BaseJellyfinApiController
|
|||||||
|
|
||||||
foreach (var (key, value) in headers)
|
foreach (var (key, value) in headers)
|
||||||
{
|
{
|
||||||
Response.Headers.Add(key, value);
|
Response.Headers.Append(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response.ContentType = imageContentType ?? MediaTypeNames.Text.Plain;
|
Response.ContentType = imageContentType ?? MediaTypeNames.Text.Plain;
|
||||||
Response.Headers.Add(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateImageModified).TotalSeconds).ToString(CultureInfo.InvariantCulture));
|
Response.Headers.Append(HeaderNames.Age, Convert.ToInt64((DateTime.UtcNow - dateImageModified).TotalSeconds).ToString(CultureInfo.InvariantCulture));
|
||||||
Response.Headers.Add(HeaderNames.Vary, HeaderNames.Accept);
|
Response.Headers.Append(HeaderNames.Vary, HeaderNames.Accept);
|
||||||
|
|
||||||
if (disableCaching)
|
if (disableCaching)
|
||||||
{
|
{
|
||||||
Response.Headers.Add(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate");
|
Response.Headers.Append(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate");
|
||||||
Response.Headers.Add(HeaderNames.Pragma, "no-cache, no-store, must-revalidate");
|
Response.Headers.Append(HeaderNames.Pragma, "no-cache, no-store, must-revalidate");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (cacheDuration.HasValue)
|
if (cacheDuration.HasValue)
|
||||||
{
|
{
|
||||||
Response.Headers.Add(HeaderNames.CacheControl, "public, max-age=" + cacheDuration.Value.TotalSeconds);
|
Response.Headers.Append(HeaderNames.CacheControl, "public, max-age=" + cacheDuration.Value.TotalSeconds);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Response.Headers.Add(HeaderNames.CacheControl, "public");
|
Response.Headers.Append(HeaderNames.CacheControl, "public");
|
||||||
}
|
}
|
||||||
|
|
||||||
Response.Headers.Add(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", CultureInfo.InvariantCulture));
|
Response.Headers.Append(HeaderNames.LastModified, dateImageModified.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss \"GMT\"", CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
// if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified
|
// if the image was not modified since "ifModifiedSinceHeader"-header, return a HTTP status code 304 not modified
|
||||||
if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue)
|
if (!(dateImageModified > ifModifiedSinceHeader) && cacheDuration.HasValue)
|
||||||
|
@ -150,7 +150,7 @@ public class MusicGenresController : BaseJellyfinApiController
|
|||||||
|
|
||||||
MusicGenre? item;
|
MusicGenre? item;
|
||||||
|
|
||||||
if (genreName.IndexOf(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase) != -1)
|
if (genreName.Contains(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
item = GetItemFromSlugName<MusicGenre>(_libraryManager, genreName, dtoOptions, BaseItemKind.MusicGenre);
|
item = GetItemFromSlugName<MusicGenre>(_libraryManager, genreName, dtoOptions, BaseItemKind.MusicGenre);
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,10 @@ public static class DtoExtensions
|
|||||||
|
|
||||||
if (!dtoOptions.ContainsField(ItemFields.RecursiveItemCount))
|
if (!dtoOptions.ContainsField(ItemFields.RecursiveItemCount))
|
||||||
{
|
{
|
||||||
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
|
if (client.Contains("kodi", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("wmc", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("media center", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1)
|
client.Contains("classic", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
int oldLen = dtoOptions.Fields.Count;
|
int oldLen = dtoOptions.Fields.Count;
|
||||||
var arr = new ItemFields[oldLen + 1];
|
var arr = new ItemFields[oldLen + 1];
|
||||||
@ -53,13 +53,13 @@ public static class DtoExtensions
|
|||||||
|
|
||||||
if (!dtoOptions.ContainsField(ItemFields.ChildCount))
|
if (!dtoOptions.ContainsField(ItemFields.ChildCount))
|
||||||
{
|
{
|
||||||
if (client.IndexOf("kodi", StringComparison.OrdinalIgnoreCase) != -1 ||
|
if (client.Contains("kodi", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("wmc", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("wmc", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("media center", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("media center", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("classic", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("classic", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("roku", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("roku", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("samsung", StringComparison.OrdinalIgnoreCase) != -1 ||
|
client.Contains("samsung", StringComparison.OrdinalIgnoreCase) ||
|
||||||
client.IndexOf("androidtv", StringComparison.OrdinalIgnoreCase) != -1)
|
client.Contains("androidtv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
int oldLen = dtoOptions.Fields.Count;
|
int oldLen = dtoOptions.Fields.Count;
|
||||||
var arr = new ItemFields[oldLen + 1];
|
var arr = new ItemFields[oldLen + 1];
|
||||||
|
@ -147,7 +147,7 @@ public class DynamicHlsHelper
|
|||||||
cancellationTokenSource.Token)
|
cancellationTokenSource.Token)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
_httpContextAccessor.HttpContext.Response.Headers.Add(HeaderNames.Expires, "0");
|
_httpContextAccessor.HttpContext.Response.Headers.Append(HeaderNames.Expires, "0");
|
||||||
if (isHeadRequest)
|
if (isHeadRequest)
|
||||||
{
|
{
|
||||||
return new FileContentResult(Array.Empty<byte>(), MimeTypes.GetMimeType("playlist.m3u8"));
|
return new FileContentResult(Array.Empty<byte>(), MimeTypes.GetMimeType("playlist.m3u8"));
|
||||||
@ -568,7 +568,7 @@ public class DynamicHlsHelper
|
|||||||
&& state.VideoStream is not null
|
&& state.VideoStream is not null
|
||||||
&& state.VideoStream.Level.HasValue)
|
&& state.VideoStream.Level.HasValue)
|
||||||
{
|
{
|
||||||
levelString = state.VideoStream.Level.ToString() ?? string.Empty;
|
levelString = state.VideoStream.Level.Value.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -53,7 +53,7 @@ public static class HlsHelpers
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.IndexOf("#EXTINF:", StringComparison.OrdinalIgnoreCase) != -1)
|
if (line.Contains("#EXTINF:", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
if (count >= segmentCount)
|
if (count >= segmentCount)
|
||||||
|
@ -279,15 +279,15 @@ public static class StreamingHelpers
|
|||||||
var profile = state.DeviceProfile;
|
var profile = state.DeviceProfile;
|
||||||
|
|
||||||
StringValues transferMode = request.Headers["transferMode.dlna.org"];
|
StringValues transferMode = request.Headers["transferMode.dlna.org"];
|
||||||
responseHeaders.Add("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
|
responseHeaders.Append("transferMode.dlna.org", string.IsNullOrEmpty(transferMode) ? "Streaming" : transferMode.ToString());
|
||||||
responseHeaders.Add("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");
|
responseHeaders.Append("realTimeInfo.dlna.org", "DLNA.ORG_TLAG=*");
|
||||||
|
|
||||||
if (state.RunTimeTicks.HasValue)
|
if (state.RunTimeTicks.HasValue)
|
||||||
{
|
{
|
||||||
if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(request.Headers["getMediaInfo.sec"], "1", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
|
var ms = TimeSpan.FromTicks(state.RunTimeTicks.Value).TotalMilliseconds;
|
||||||
responseHeaders.Add("MediaInfo.sec", string.Format(
|
responseHeaders.Append("MediaInfo.sec", string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
"SEC_Duration={0};",
|
"SEC_Duration={0};",
|
||||||
Convert.ToInt32(ms)));
|
Convert.ToInt32(ms)));
|
||||||
@ -305,7 +305,7 @@ public static class StreamingHelpers
|
|||||||
|
|
||||||
if (!state.IsVideoRequest)
|
if (!state.IsVideoRequest)
|
||||||
{
|
{
|
||||||
responseHeaders.Add("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
|
responseHeaders.Append("contentFeatures.dlna.org", ContentFeatureBuilder.BuildAudioHeader(
|
||||||
profile,
|
profile,
|
||||||
state.OutputContainer,
|
state.OutputContainer,
|
||||||
audioCodec,
|
audioCodec,
|
||||||
@ -321,7 +321,7 @@ public static class StreamingHelpers
|
|||||||
{
|
{
|
||||||
var videoCodec = state.ActualOutputVideoCodec;
|
var videoCodec = state.ActualOutputVideoCodec;
|
||||||
|
|
||||||
responseHeaders.Add(
|
responseHeaders.Append(
|
||||||
"contentFeatures.dlna.org",
|
"contentFeatures.dlna.org",
|
||||||
ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
|
ContentFeatureBuilder.BuildVideoHeader(profile, state.OutputContainer, videoCodec, audioCodec, state.OutputWidth, state.OutputHeight, state.TargetVideoBitDepth, state.OutputVideoBitrate, state.TargetTimestamp, isStaticallyStreamed, state.RunTimeTicks, state.TargetVideoProfile, state.TargetVideoRangeType, state.TargetVideoLevel, state.TargetFramerate, state.TargetPacketLength, state.TranscodeSeekInfo, state.IsTargetAnamorphic, state.IsTargetInterlaced, state.TargetRefFrames, state.TargetVideoStreamCount, state.TargetAudioStreamCount, state.TargetVideoCodecTag, state.IsTargetAVC).FirstOrDefault() ?? string.Empty);
|
||||||
}
|
}
|
||||||
@ -404,12 +404,12 @@ public static class StreamingHelpers
|
|||||||
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks!.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
var runtimeSeconds = TimeSpan.FromTicks(state.RunTimeTicks!.Value).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
||||||
var startSeconds = TimeSpan.FromTicks(startTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
var startSeconds = TimeSpan.FromTicks(startTimeTicks ?? 0).TotalSeconds.ToString(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
responseHeaders.Add("TimeSeekRange.dlna.org", string.Format(
|
responseHeaders.Append("TimeSeekRange.dlna.org", string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
"npt={0}-{1}/{1}",
|
"npt={0}-{1}/{1}",
|
||||||
startSeconds,
|
startSeconds,
|
||||||
runtimeSeconds));
|
runtimeSeconds));
|
||||||
responseHeaders.Add("X-AvailableSeekRange", string.Format(
|
responseHeaders.Append("X-AvailableSeekRange", string.Format(
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
"1 npt={0}-{1}",
|
"1 npt={0}-{1}",
|
||||||
startSeconds,
|
startSeconds,
|
||||||
|
@ -280,6 +280,7 @@ public class TranscodingJobHelper : IDisposable
|
|||||||
|
|
||||||
if (job.CancellationTokenSource?.IsCancellationRequested == false)
|
if (job.CancellationTokenSource?.IsCancellationRequested == false)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CA1849 // Can't await in lock block
|
||||||
job.CancellationTokenSource.Cancel();
|
job.CancellationTokenSource.Cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,7 +292,6 @@ public class TranscodingJobHelper : IDisposable
|
|||||||
|
|
||||||
lock (job.ProcessLock!)
|
lock (job.ProcessLock!)
|
||||||
{
|
{
|
||||||
#pragma warning disable CA1849 // Can't await in lock block
|
|
||||||
job.TranscodingThrottler?.Stop().GetAwaiter().GetResult();
|
job.TranscodingThrottler?.Stop().GetAwaiter().GetResult();
|
||||||
|
|
||||||
var process = job.Process;
|
var process = job.Process;
|
||||||
@ -405,7 +405,7 @@ public class TranscodingJobHelper : IDisposable
|
|||||||
var name = Path.GetFileNameWithoutExtension(outputFilePath);
|
var name = Path.GetFileNameWithoutExtension(outputFilePath);
|
||||||
|
|
||||||
var filesToDelete = _fileSystem.GetFilePaths(directory)
|
var filesToDelete = _fileSystem.GetFilePaths(directory)
|
||||||
.Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1);
|
.Where(f => f.Contains(name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
List<Exception>? exs = null;
|
List<Exception>? exs = null;
|
||||||
foreach (var file in filesToDelete)
|
foreach (var file in filesToDelete)
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -86,11 +86,11 @@ public class StreamState : EncodingJobInfo, IDisposable
|
|||||||
{
|
{
|
||||||
var userAgent = UserAgent ?? string.Empty;
|
var userAgent = UserAgent ?? string.Empty;
|
||||||
|
|
||||||
if (userAgent.IndexOf("AppleTV", StringComparison.OrdinalIgnoreCase) != -1
|
if (userAgent.Contains("AppleTV", StringComparison.OrdinalIgnoreCase)
|
||||||
|| userAgent.IndexOf("cfnetwork", StringComparison.OrdinalIgnoreCase) != -1
|
|| userAgent.Contains("cfnetwork", StringComparison.OrdinalIgnoreCase)
|
||||||
|| userAgent.IndexOf("ipad", StringComparison.OrdinalIgnoreCase) != -1
|
|| userAgent.Contains("ipad", StringComparison.OrdinalIgnoreCase)
|
||||||
|| userAgent.IndexOf("iphone", StringComparison.OrdinalIgnoreCase) != -1
|
|| userAgent.Contains("iphone", StringComparison.OrdinalIgnoreCase)
|
||||||
|| userAgent.IndexOf("ipod", StringComparison.OrdinalIgnoreCase) != -1)
|
|| userAgent.Contains("ipod", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return 6;
|
return 6;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -65,7 +65,7 @@ namespace Jellyfin.Networking.HappyEyeballs
|
|||||||
// See https://github.com/dotnet/corefx/pull/29792/files#r189415885 for more details.
|
// See https://github.com/dotnet/corefx/pull/29792/files#r189415885 for more details.
|
||||||
if (await Task.WhenAny(tryConnectAsyncIPv6, Task.Delay(200, cancelIPv6.Token)).ConfigureAwait(false) == tryConnectAsyncIPv6 && tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
if (await Task.WhenAny(tryConnectAsyncIPv6, Task.Delay(200, cancelIPv6.Token)).ConfigureAwait(false) == tryConnectAsyncIPv6 && tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
||||||
{
|
{
|
||||||
cancelIPv6.Cancel();
|
await cancelIPv6.CancelAsync().ConfigureAwait(false);
|
||||||
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ namespace Jellyfin.Networking.HappyEyeballs
|
|||||||
{
|
{
|
||||||
if (tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
if (tryConnectAsyncIPv6.IsCompletedSuccessfully)
|
||||||
{
|
{
|
||||||
cancelIPv4.Cancel();
|
await cancelIPv4.CancelAsync().ConfigureAwait(false);
|
||||||
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
return tryConnectAsyncIPv6.GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ namespace Jellyfin.Networking.HappyEyeballs
|
|||||||
{
|
{
|
||||||
if (tryConnectAsyncIPv4.IsCompletedSuccessfully)
|
if (tryConnectAsyncIPv4.IsCompletedSuccessfully)
|
||||||
{
|
{
|
||||||
cancelIPv6.Cancel();
|
await cancelIPv6.CancelAsync().ConfigureAwait(false);
|
||||||
return tryConnectAsyncIPv4.GetAwaiter().GetResult();
|
return tryConnectAsyncIPv4.GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -15,6 +15,8 @@ using Microsoft.AspNetCore.HttpOverrides;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
namespace Jellyfin.Networking.Manager
|
namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
@ -423,7 +425,7 @@ namespace Jellyfin.Networking.Manager
|
|||||||
{
|
{
|
||||||
// Parse config values into filter collection
|
// Parse config values into filter collection
|
||||||
var remoteIPFilter = config.RemoteIPFilter;
|
var remoteIPFilter = config.RemoteIPFilter;
|
||||||
if (remoteIPFilter.Any() && !string.IsNullOrWhiteSpace(remoteIPFilter.First()))
|
if (remoteIPFilter.Length != 0 && !string.IsNullOrWhiteSpace(remoteIPFilter[0]))
|
||||||
{
|
{
|
||||||
// Parse all IPs with netmask to a subnet
|
// Parse all IPs with netmask to a subnet
|
||||||
var remoteAddressFilter = new List<IPNetwork>();
|
var remoteAddressFilter = new List<IPNetwork>();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -60,7 +60,7 @@ namespace Jellyfin.Server.Implementations.Security
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AuthorizationInfo> GetAuthorizationInfoFromDictionary(
|
private async Task<AuthorizationInfo> GetAuthorizationInfoFromDictionary(
|
||||||
IReadOnlyDictionary<string, string>? auth,
|
Dictionary<string, string>? auth,
|
||||||
IHeaderDictionary headers,
|
IHeaderDictionary headers,
|
||||||
IQueryCollection queryString)
|
IQueryCollection queryString)
|
||||||
{
|
{
|
||||||
|
@ -748,7 +748,7 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
return GetPasswordResetProviders(user)[0];
|
return GetPasswordResetProviders(user)[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<IAuthenticationProvider> GetAuthenticationProviders(User? user)
|
private List<IAuthenticationProvider> GetAuthenticationProviders(User? user)
|
||||||
{
|
{
|
||||||
var authenticationProviderId = user?.AuthenticationProviderId;
|
var authenticationProviderId = user?.AuthenticationProviderId;
|
||||||
|
|
||||||
@ -775,7 +775,7 @@ namespace Jellyfin.Server.Implementations.Users
|
|||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<IPasswordResetProvider> GetPasswordResetProviders(User user)
|
private IPasswordResetProvider[] GetPasswordResetProviders(User user)
|
||||||
{
|
{
|
||||||
var passwordResetProviderId = user.PasswordResetProviderId;
|
var passwordResetProviderId = user.PasswordResetProviderId;
|
||||||
var providers = _passwordResetProviders.Where(i => i.IsEnabled).ToArray();
|
var providers = _passwordResetProviders.Where(i => i.IsEnabled).ToArray();
|
||||||
|
@ -37,6 +37,7 @@ using Microsoft.OpenApi.Interfaces;
|
|||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
|
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
|
||||||
|
using IPNetwork = System.Net.IPNetwork;
|
||||||
|
|
||||||
namespace Jellyfin.Server.Extensions
|
namespace Jellyfin.Server.Extensions
|
||||||
{
|
{
|
||||||
@ -311,7 +312,7 @@ namespace Jellyfin.Server.Extensions
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
options.KnownNetworks.Add(new IPNetwork(addr, prefixLength));
|
options.KnownNetworks.Add(new Microsoft.AspNetCore.HttpOverrides.IPNetwork(addr, prefixLength));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AssemblyName>jellyfin</AssemblyName>
|
<AssemblyName>jellyfin</AssemblyName>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ServerGarbageCollection>false</ServerGarbageCollection>
|
<ServerGarbageCollection>false</ServerGarbageCollection>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
@ -78,11 +78,7 @@ namespace Jellyfin.Server.Migrations.Routines
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var ratingValue = _localizationManager.GetRatingLevel(ratingString).ToString();
|
var ratingValue = _localizationManager.GetRatingLevel(ratingString)?.ToString(CultureInfo.InvariantCulture) ?? "NULL";
|
||||||
if (string.IsNullOrEmpty(ratingValue))
|
|
||||||
{
|
|
||||||
ratingValue = "NULL";
|
|
||||||
}
|
|
||||||
|
|
||||||
using var statement = connection.PrepareStatement("UPDATE TypedBaseItems SET InheritedParentalRatingValue = @Value WHERE OfficialRating = @Rating;");
|
using var statement = connection.PrepareStatement("UPDATE TypedBaseItems SET InheritedParentalRatingValue = @Value WHERE OfficialRating = @Rating;");
|
||||||
statement.TryBind("@Value", ratingValue);
|
statement.TryBind("@Value", ratingValue);
|
||||||
|
@ -40,7 +40,7 @@ namespace Jellyfin.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public const string LoggingConfigFileSystem = "logging.json";
|
public const string LoggingConfigFileSystem = "logging.json";
|
||||||
|
|
||||||
private static readonly ILoggerFactory _loggerFactory = new SerilogLoggerFactory();
|
private static readonly SerilogLoggerFactory _loggerFactory = new SerilogLoggerFactory();
|
||||||
private static long _startTimestamp;
|
private static long _startTimestamp;
|
||||||
private static ILogger _logger = NullLogger.Instance;
|
private static ILogger _logger = NullLogger.Instance;
|
||||||
private static bool _restartOnShutdown;
|
private static bool _restartOnShutdown;
|
||||||
|
@ -35,7 +35,7 @@ namespace Jellyfin.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
private readonly IServerApplicationHost _serverApplicationHost;
|
private readonly CoreAppHost _serverApplicationHost;
|
||||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net;
|
namespace MediaBrowser.Common.Net;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ using System.Net;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net;
|
namespace MediaBrowser.Common.Net;
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -20,6 +20,7 @@ using MediaBrowser.Model.Dto;
|
|||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.MediaInfo;
|
using MediaBrowser.Model.MediaInfo;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.MediaEncoding
|
namespace MediaBrowser.Controller.MediaEncoding
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -121,7 +121,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
"yadif_videotoolbox"
|
"yadif_videotoolbox"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly IReadOnlyDictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
private static readonly Dictionary<int, string[]> _filterOptionsDict = new Dictionary<int, string[]>
|
||||||
{
|
{
|
||||||
{ 0, new string[] { "scale_cuda", "Output format (default \"same\")" } },
|
{ 0, new string[] { "scale_cuda", "Output format (default \"same\")" } },
|
||||||
{ 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } },
|
{ 1, new string[] { "tonemap_cuda", "GPU accelerated HDR to SDR tonemapping" } },
|
||||||
@ -132,7 +132,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
};
|
};
|
||||||
|
|
||||||
// These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below
|
// These are the library versions that corresponds to our minimum ffmpeg version 4.x according to the version table below
|
||||||
private static readonly IReadOnlyDictionary<string, Version> _ffmpegMinimumLibraryVersions = new Dictionary<string, Version>
|
private static readonly Dictionary<string, Version> _ffmpegMinimumLibraryVersions = new Dictionary<string, Version>
|
||||||
{
|
{
|
||||||
{ "libavutil", new Version(56, 14) },
|
{ "libavutil", new Version(56, 14) },
|
||||||
{ "libavcodec", new Version(58, 18) },
|
{ "libavcodec", new Version(58, 18) },
|
||||||
@ -197,7 +197,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
|
|
||||||
internal bool ValidateVersionInternal(string versionOutput)
|
internal bool ValidateVersionInternal(string versionOutput)
|
||||||
{
|
{
|
||||||
if (versionOutput.IndexOf("Libav developers", StringComparison.OrdinalIgnoreCase) != -1)
|
if (versionOutput.Contains("Libav developers", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported");
|
_logger.LogError("FFmpeg validation: avconv instead of ffmpeg is not supported");
|
||||||
return false;
|
return false;
|
||||||
@ -333,7 +333,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="output">The 'ffmpeg -version' output.</param>
|
/// <param name="output">The 'ffmpeg -version' output.</param>
|
||||||
/// <returns>The library names and major.minor version numbers.</returns>
|
/// <returns>The library names and major.minor version numbers.</returns>
|
||||||
private static IReadOnlyDictionary<string, Version> GetFFmpegLibraryVersions(string output)
|
private static Dictionary<string, Version> GetFFmpegLibraryVersions(string output)
|
||||||
{
|
{
|
||||||
var map = new Dictionary<string, Version>();
|
var map = new Dictionary<string, Version>();
|
||||||
|
|
||||||
@ -537,9 +537,9 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IDictionary<int, bool> GetFFmpegFiltersWithOption()
|
private Dictionary<int, bool> GetFFmpegFiltersWithOption()
|
||||||
{
|
{
|
||||||
IDictionary<int, bool> dict = new Dictionary<int, bool>();
|
Dictionary<int, bool> dict = new Dictionary<int, bool>();
|
||||||
for (int i = 0; i < _filterOptionsDict.Count; i++)
|
for (int i = 0; i < _filterOptionsDict.Count; i++)
|
||||||
{
|
{
|
||||||
if (_filterOptionsDict.TryGetValue(i, out var val) && val.Length == 2)
|
if (_filterOptionsDict.TryGetValue(i, out var val) && val.Length == 2)
|
||||||
|
@ -59,7 +59,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
/// <returns>System.String.</returns>
|
/// <returns>System.String.</returns>
|
||||||
private static string GetFileInputArgument(string path, string inputPrefix)
|
private static string GetFileInputArgument(string path, string inputPrefix)
|
||||||
{
|
{
|
||||||
if (path.IndexOf("://", StringComparison.Ordinal) != -1)
|
if (path.Contains("://", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path);
|
return string.Format(CultureInfo.InvariantCulture, "\"{0}\"", path);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -516,7 +516,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
|
|
||||||
private void ProcessPairs(string key, List<NameValuePair> pairs, MediaInfo info)
|
private void ProcessPairs(string key, List<NameValuePair> pairs, MediaInfo info)
|
||||||
{
|
{
|
||||||
IList<BaseItemPerson> peoples = new List<BaseItemPerson>();
|
List<BaseItemPerson> peoples = new List<BaseItemPerson>();
|
||||||
if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(key, "studio", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
info.Studios = pairs.Select(p => p.Value)
|
info.Studios = pairs.Select(p => p.Value)
|
||||||
@ -612,11 +612,11 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
{
|
{
|
||||||
codec = "dvbsub";
|
codec = "dvbsub";
|
||||||
}
|
}
|
||||||
else if ((codec ?? string.Empty).IndexOf("PGS", StringComparison.OrdinalIgnoreCase) != -1)
|
else if ((codec ?? string.Empty).Contains("PGS", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
codec = "PGSSUB";
|
codec = "PGSSUB";
|
||||||
}
|
}
|
||||||
else if ((codec ?? string.Empty).IndexOf("DVD", StringComparison.OrdinalIgnoreCase) != -1)
|
else if ((codec ?? string.Empty).Contains("DVD", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
codec = "DVDSUB";
|
codec = "DVDSUB";
|
||||||
}
|
}
|
||||||
@ -1182,7 +1182,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, CultureInfo.InvariantCulture);
|
info.Size = string.IsNullOrEmpty(data.Format.Size) ? null : long.Parse(data.Format.Size, CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetAudioInfoFromTags(MediaInfo audio, IReadOnlyDictionary<string, string> tags)
|
private void SetAudioInfoFromTags(MediaInfo audio, Dictionary<string, string> tags)
|
||||||
{
|
{
|
||||||
var people = new List<BaseItemPerson>();
|
var people = new List<BaseItemPerson>();
|
||||||
if (tags.TryGetValue("composer", out var composer) && !string.IsNullOrWhiteSpace(composer))
|
if (tags.TryGetValue("composer", out var composer) && !string.IsNullOrWhiteSpace(composer))
|
||||||
@ -1339,7 +1339,7 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
{
|
{
|
||||||
// Only use the comma as a delimiter if there are no slashes or pipes.
|
// Only use the comma as a delimiter if there are no slashes or pipes.
|
||||||
// We want to be careful not to split names that have commas in them
|
// We want to be careful not to split names that have commas in them
|
||||||
var delimiter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.IndexOf(i, StringComparison.Ordinal) != -1) ?
|
var delimiter = !allowCommaDelimiter || _nameDelimiters.Any(i => val.Contains(i, StringComparison.Ordinal)) ?
|
||||||
_nameDelimiters :
|
_nameDelimiters :
|
||||||
new[] { ',' };
|
new[] { ',' };
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||||||
public bool SupportsFileExtension(string fileExtension)
|
public bool SupportsFileExtension(string fileExtension)
|
||||||
=> _subtitleFormats.ContainsKey(fileExtension);
|
=> _subtitleFormats.ContainsKey(fileExtension);
|
||||||
|
|
||||||
private IEnumerable<SubtitleFormat> GetSubtitleFormats()
|
private List<SubtitleFormat> GetSubtitleFormats()
|
||||||
{
|
{
|
||||||
var subtitleFormats = new List<SubtitleFormat>();
|
var subtitleFormats = new List<SubtitleFormat>();
|
||||||
var assembly = typeof(SubtitleFormat).Assembly;
|
var assembly = typeof(SubtitleFormat).Assembly;
|
||||||
|
@ -63,7 +63,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
|||||||
|
|
||||||
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
|
private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
|
||||||
|
|
||||||
private Stream ConvertSubtitles(
|
private MemoryStream ConvertSubtitles(
|
||||||
Stream stream,
|
Stream stream,
|
||||||
string inputFormat,
|
string inputFormat,
|
||||||
string outputFormat,
|
string outputFormat,
|
||||||
|
@ -835,11 +835,6 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
playlistItem.SetOption(qualifier, "profile", videoStream.Profile.ToLowerInvariant());
|
playlistItem.SetOption(qualifier, "profile", videoStream.Profile.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoStream is not null && videoStream.Level != 0)
|
|
||||||
{
|
|
||||||
playlistItem.SetOption(qualifier, "level", videoStream.Level.ToString() ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prefer matching audio codecs, could do better here
|
// Prefer matching audio codecs, could do better here
|
||||||
var audioCodecs = ContainerProfile.SplitValue(audioCodec);
|
var audioCodecs = ContainerProfile.SplitValue(audioCodec);
|
||||||
|
|
||||||
@ -866,16 +861,16 @@ namespace MediaBrowser.Model.Dlna
|
|||||||
|
|
||||||
// Copy matching audio codec options
|
// Copy matching audio codec options
|
||||||
playlistItem.AudioSampleRate = audioStream.SampleRate;
|
playlistItem.AudioSampleRate = audioStream.SampleRate;
|
||||||
playlistItem.SetOption(qualifier, "audiochannels", audioStream.Channels.ToString() ?? string.Empty);
|
playlistItem.SetOption(qualifier, "audiochannels", audioStream.Channels?.ToString(CultureInfo.InvariantCulture) ?? string.Empty);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(audioStream.Profile))
|
if (!string.IsNullOrEmpty(audioStream.Profile))
|
||||||
{
|
{
|
||||||
playlistItem.SetOption(audioStream.Codec, "profile", audioStream.Profile.ToLowerInvariant());
|
playlistItem.SetOption(audioStream.Codec, "profile", audioStream.Profile.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (audioStream.Level != 0)
|
if (audioStream.Level.HasValue && audioStream.Level.Value != 0)
|
||||||
{
|
{
|
||||||
playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.ToString() ?? string.Empty);
|
playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
namespace MediaBrowser.Model.Net;
|
namespace MediaBrowser.Model.Net;
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ public class LrcLyricParser : ILyricParser
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="metaData">The metadata from the LRC file.</param>
|
/// <param name="metaData">The metadata from the LRC file.</param>
|
||||||
/// <returns>A lyricMetadata object with mapped property data.</returns>
|
/// <returns>A lyricMetadata object with mapped property data.</returns>
|
||||||
private static LyricMetadata MapMetadataValues(IDictionary<string, string> metaData)
|
private static LyricMetadata MapMetadataValues(Dictionary<string, string> metaData)
|
||||||
{
|
{
|
||||||
LyricMetadata lyricMetadata = new();
|
LyricMetadata lyricMetadata = new();
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
IDynamicImageProvider provider,
|
IDynamicImageProvider provider,
|
||||||
ImageRefreshOptions refreshOptions,
|
ImageRefreshOptions refreshOptions,
|
||||||
TypeOptions savedOptions,
|
TypeOptions savedOptions,
|
||||||
ICollection<ImageType> downloadedImages,
|
List<ImageType> downloadedImages,
|
||||||
RefreshResult result,
|
RefreshResult result,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@ -263,7 +263,7 @@ namespace MediaBrowser.Providers.Manager
|
|||||||
ImageRefreshOptions refreshOptions,
|
ImageRefreshOptions refreshOptions,
|
||||||
TypeOptions savedOptions,
|
TypeOptions savedOptions,
|
||||||
int backdropLimit,
|
int backdropLimit,
|
||||||
ICollection<ImageType> downloadedImages,
|
List<ImageType> downloadedImages,
|
||||||
RefreshResult result,
|
RefreshResult result,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||||
|
@ -82,8 +82,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
|
||||||
var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("front", StringComparison.OrdinalIgnoreCase) != -1) ??
|
var imageStream = imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).Contains("front", StringComparison.OrdinalIgnoreCase)) ??
|
||||||
imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).IndexOf("cover", StringComparison.OrdinalIgnoreCase) != -1) ??
|
imageStreams.FirstOrDefault(i => (i.Comment ?? string.Empty).Contains("cover", StringComparison.OrdinalIgnoreCase)) ??
|
||||||
imageStreams.FirstOrDefault();
|
imageStreams.FirstOrDefault();
|
||||||
|
|
||||||
var imageStreamIndex = imageStream?.Index;
|
var imageStreamIndex = imageStream?.Index;
|
||||||
|
@ -183,7 +183,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
files.AddRange(directoryService.GetFilePaths(internalMetadataPath, clearCache, true));
|
files.AddRange(directoryService.GetFilePaths(internalMetadataPath, clearCache, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!files.Any())
|
if (files.Count == 0)
|
||||||
{
|
{
|
||||||
return Array.Empty<ExternalPathParserResult>();
|
return Array.Empty<ExternalPathParserResult>();
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ namespace MediaBrowser.Providers.Music
|
|||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var id = item.GetProviderId(provider);
|
var id = item.GetProviderId(provider);
|
||||||
if (ids.Any())
|
if (ids.Length != 0)
|
||||||
{
|
{
|
||||||
var firstId = ids[0];
|
var firstId = ids[0];
|
||||||
if (!string.IsNullOrEmpty(firstId)
|
if (!string.IsNullOrEmpty(firstId)
|
||||||
|
@ -73,7 +73,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
|||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<RemoteImageInfo> GetImages(AudioDbAlbumProvider.Album item)
|
private List<RemoteImageInfo> GetImages(AudioDbAlbumProvider.Album item)
|
||||||
{
|
{
|
||||||
var list = new List<RemoteImageInfo>();
|
var list = new List<RemoteImageInfo>();
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
|
|||||||
return Enumerable.Empty<RemoteImageInfo>();
|
return Enumerable.Empty<RemoteImageInfo>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<RemoteImageInfo> GetImages(AudioDbArtistProvider.Artist item)
|
private List<RemoteImageInfo> GetImages(AudioDbArtistProvider.Artist item)
|
||||||
{
|
{
|
||||||
var list = new List<RemoteImageInfo>();
|
var list = new List<RemoteImageInfo>();
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ namespace MediaBrowser.Providers.TV
|
|||||||
var seasonNumber = virtualSeason.IndexNumber;
|
var seasonNumber = virtualSeason.IndexNumber;
|
||||||
// If there's a physical season with the same number or no episodes in the season, delete it
|
// If there's a physical season with the same number or no episodes in the season, delete it
|
||||||
if ((seasonNumber.HasValue && physicalSeasonNumbers.Contains(seasonNumber.Value))
|
if ((seasonNumber.HasValue && physicalSeasonNumbers.Contains(seasonNumber.Value))
|
||||||
|| !virtualSeason.GetEpisodes().Any())
|
|| virtualSeason.GetEpisodes().Count == 0)
|
||||||
{
|
{
|
||||||
Logger.LogInformation("Removing virtual season {SeasonNumber} in series {SeriesName}", virtualSeason.IndexNumber, series.Name);
|
Logger.LogInformation("Removing virtual season {SeasonNumber} in series {SeriesName}", virtualSeason.IndexNumber, series.Name);
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -314,11 +314,11 @@ namespace MediaBrowser.XbmcMetadata.Savers
|
|||||||
{
|
{
|
||||||
var codec = stream.Codec;
|
var codec = stream.Codec;
|
||||||
|
|
||||||
if ((stream.CodecTag ?? string.Empty).IndexOf("xvid", StringComparison.OrdinalIgnoreCase) != -1)
|
if ((stream.CodecTag ?? string.Empty).Contains("xvid", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
codec = "xvid";
|
codec = "xvid";
|
||||||
}
|
}
|
||||||
else if ((stream.CodecTag ?? string.Empty).IndexOf("divx", StringComparison.OrdinalIgnoreCase) != -1)
|
else if ((stream.CodecTag ?? string.Empty).Contains("divx", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
codec = "divx";
|
codec = "divx";
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ A second option is to build the project and then run the resulting executable fi
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
dotnet build # Build the project
|
dotnet build # Build the project
|
||||||
cd Jellyfin.Server/bin/Debug/net7.0 # Change into the build output directory
|
cd Jellyfin.Server/bin/Debug/net8.0 # Change into the build output directory
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Execute the build output. On Linux, Mac, etc. use `./jellyfin` and on Windows use `jellyfin.exe`.
|
2. Execute the build output. On Linux, Mac, etc. use `./jellyfin` and on Windows use `jellyfin.exe`.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<AnalysisMode>AllDisabledByDefault</AnalysisMode>
|
<AnalysisMode>AllDisabledByDefault</AnalysisMode>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
|
@ -13,7 +13,7 @@ RUN yum update -yq \
|
|||||||
&& yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget
|
&& yum install -yq @buildsys-build rpmdevtools yum-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel git wget
|
||||||
|
|
||||||
# Install DotNET SDK
|
# Install DotNET SDK
|
||||||
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/ff8c660f-ffa9-4814-ac2d-4089e6ec4eb5/dc806d344844f1d58d8015d105e85c65/dotnet-sdk-7.0.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-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
|
||||||
|
@ -12,7 +12,7 @@ RUN dnf update -yq \
|
|||||||
&& dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget make
|
&& dnf install -yq @buildsys-build rpmdevtools git dnf-plugins-core libcurl-devel fontconfig-devel freetype-devel openssl-devel glibc-devel libicu-devel systemd wget make
|
||||||
|
|
||||||
# Install DotNET SDK
|
# Install DotNET SDK
|
||||||
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/ff8c660f-ffa9-4814-ac2d-4089e6ec4eb5/dc806d344844f1d58d8015d105e85c65/dotnet-sdk-7.0.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-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
|
||||||
|
@ -17,7 +17,7 @@ RUN apt-get update -yqq \
|
|||||||
libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0
|
libfreetype6-dev libssl-dev libssl1.1 liblttng-ust0
|
||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/ff8c660f-ffa9-4814-ac2d-4089e6ec4eb5/dc806d344844f1d58d8015d105e85c65/dotnet-sdk-7.0.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-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 -yqq \
|
|||||||
mmv build-essential lsb-release
|
mmv build-essential lsb-release
|
||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/ff8c660f-ffa9-4814-ac2d-4089e6ec4eb5/dc806d344844f1d58d8015d105e85c65/dotnet-sdk-7.0.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-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 -yqq \
|
|||||||
mmv build-essential lsb-release
|
mmv build-essential lsb-release
|
||||||
|
|
||||||
# Install dotnet repository
|
# Install dotnet repository
|
||||||
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/ff8c660f-ffa9-4814-ac2d-4089e6ec4eb5/dc806d344844f1d58d8015d105e85c65/dotnet-sdk-7.0.403-linux-x64.tar.gz -O dotnet-sdk.tar.gz \
|
RUN wget -q https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-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
|
||||||
|
@ -73,7 +73,7 @@ dotnet publish --configuration Release --self-contained --runtime %{dotnet_runti
|
|||||||
%install
|
%install
|
||||||
# Jellyfin files
|
# Jellyfin files
|
||||||
%{__mkdir} -p %{buildroot}%{_libdir}/jellyfin %{buildroot}%{_bindir}
|
%{__mkdir} -p %{buildroot}%{_libdir}/jellyfin %{buildroot}%{_bindir}
|
||||||
%{__cp} -r Jellyfin.Server/bin/Release/net7.0/%{dotnet_runtime}/publish/* %{buildroot}%{_libdir}/jellyfin
|
%{__cp} -r Jellyfin.Server/bin/Release/net8.0/%{dotnet_runtime}/publish/* %{buildroot}%{_libdir}/jellyfin
|
||||||
%{__install} -D %{SOURCE10} %{buildroot}%{_bindir}/jellyfin
|
%{__install} -D %{SOURCE10} %{buildroot}%{_bindir}/jellyfin
|
||||||
sed -i -e 's|/usr/lib64|%{_libdir}|g' %{buildroot}%{_bindir}/jellyfin
|
sed -i -e 's|/usr/lib64|%{_libdir}|g' %{buildroot}%{_bindir}/jellyfin
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -8,4 +8,4 @@ cp bin/Emby.Server.Implementations.dll .
|
|||||||
|
|
||||||
dotnet build
|
dotnet build
|
||||||
mkdir -p Findings
|
mkdir -p Findings
|
||||||
AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net7.0/Emby.Server.Implementations.Fuzz "$1"
|
AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net8.0/Emby.Server.Implementations.Fuzz "$1"
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -8,4 +8,4 @@ cp bin/Jellyfin.Api.dll .
|
|||||||
|
|
||||||
dotnet build
|
dotnet build
|
||||||
mkdir -p Findings
|
mkdir -p Findings
|
||||||
AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net7.0/Jellyfin.Api.Fuzz "$1"
|
AFL_SKIP_BIN_CHECK=1 afl-fuzz -i "Testcases/$1" -o "Findings/$1" -t 5000 ./bin/Debug/net8.0/Jellyfin.Api.Fuzz "$1"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "7.0.0",
|
"version": "8.0.0",
|
||||||
"rollForward": "latestMinor"
|
"rollForward": "latestMinor"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,6 +140,9 @@
|
|||||||
<Rule Id="CA1812" Action="Info" />
|
<Rule Id="CA1812" Action="Info" />
|
||||||
<!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
|
<!-- disable warning CA1822: Member does not access instance data and can be marked as static -->
|
||||||
<Rule Id="CA1822" Action="Info" />
|
<Rule Id="CA1822" Action="Info" />
|
||||||
|
<!-- TODO: Enable -->
|
||||||
|
<!-- CA1861: Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array -->
|
||||||
|
<Rule Id="CA1861" Action="Info" />
|
||||||
<!-- disable warning CA2000: Dispose objects before losing scope -->
|
<!-- disable warning CA2000: Dispose objects before losing scope -->
|
||||||
<Rule Id="CA2000" Action="Info" />
|
<Rule Id="CA2000" Action="Info" />
|
||||||
<!-- disable warning CA2253: Named placeholders should not be numeric values -->
|
<!-- disable warning CA2253: Named placeholders should not be numeric values -->
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<!-- TODO: Remove once we update SkiaSharp > 2.88.5 -->
|
||||||
|
<NoWarn>NU1903</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.Json.Serialization.Metadata;
|
||||||
using Jellyfin.Extensions.Json.Converters;
|
using Jellyfin.Extensions.Json.Converters;
|
||||||
|
|
||||||
namespace Jellyfin.Extensions.Json
|
namespace Jellyfin.Extensions.Json
|
||||||
@ -41,7 +42,8 @@ namespace Jellyfin.Extensions.Json
|
|||||||
new JsonNullableStructConverterFactory(),
|
new JsonNullableStructConverterFactory(),
|
||||||
new JsonDateTimeConverter(),
|
new JsonDateTimeConverter(),
|
||||||
new JsonStringConverter()
|
new JsonStringConverter()
|
||||||
}
|
},
|
||||||
|
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly JsonSerializerOptions _pascalCaseJsonSerializerOptions = new(_jsonSerializerOptions)
|
private static readonly JsonSerializerOptions _pascalCaseJsonSerializerOptions = new(_jsonSerializerOptions)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ namespace Jellyfin.MediaEncoding.Keyframes.FfProbe;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static class FfProbeKeyframeExtractor
|
public static class FfProbeKeyframeExtractor
|
||||||
{
|
{
|
||||||
private const string DefaultArguments = "-fflags +genpts -v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"";
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extracts the keyframes using the ffprobe executable at the specified path.
|
/// Extracts the keyframes using the ffprobe executable at the specified path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -26,7 +24,10 @@ public static class FfProbeKeyframeExtractor
|
|||||||
StartInfo = new ProcessStartInfo
|
StartInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = ffProbePath,
|
FileName = ffProbePath,
|
||||||
Arguments = string.Format(CultureInfo.InvariantCulture, DefaultArguments, filePath),
|
Arguments = string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"-fflags +genpts -v error -skip_frame nokey -show_entries format=duration -show_entries stream=duration -show_entries packet=pts_time,flags -select_streams v -of csv \"{0}\"",
|
||||||
|
filePath),
|
||||||
|
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
|
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)/jellyfin-tests.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)/jellyfin-tests.ruleset</CodeAnalysisRuleSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -109,7 +109,7 @@ public class UserControllerTests
|
|||||||
v.ErrorMessage.Contains("required", StringComparison.CurrentCultureIgnoreCase));
|
v.ErrorMessage.Contains("required", StringComparison.CurrentCultureIgnoreCase));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<ValidationResult> Validate(object model)
|
private List<ValidationResult> Validate(object model)
|
||||||
{
|
{
|
||||||
var result = new List<ValidationResult>();
|
var result = new List<ValidationResult>();
|
||||||
var context = new ValidationContext(model, null, null);
|
var context = new ValidationContext(model, null, null);
|
||||||
|
@ -7,135 +7,128 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Jellyfin.Extensions.Tests.Json.Converters
|
namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||||
{
|
{
|
||||||
public static class JsonCommaDelimitedArrayTests
|
public class JsonCommaDelimitedArrayTests
|
||||||
{
|
{
|
||||||
[Fact]
|
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
|
||||||
public static void Deserialize_String_Null_Success()
|
|
||||||
{
|
{
|
||||||
var options = new JsonSerializerOptions();
|
Converters =
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": null }", options);
|
{
|
||||||
|
new JsonStringEnumConverter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Deserialize_String_Null_Success()
|
||||||
|
{
|
||||||
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": null }", _jsonOptions);
|
||||||
Assert.Null(value?.Value);
|
Assert.Null(value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_Empty_Success()
|
public void Deserialize_Empty_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<string>
|
var desiredValue = new GenericBodyArrayModel<string>
|
||||||
{
|
{
|
||||||
Value = Array.Empty<string>()
|
Value = Array.Empty<string>()
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": """" }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": """" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Valid_Success()
|
public void Deserialize_String_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<string>
|
var desiredValue = new GenericBodyArrayModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a,b,c"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Space_Valid_Success()
|
public void Deserialize_String_Space_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<string>
|
var desiredValue = new GenericBodyArrayModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a, b, c"" }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": ""a, b, c"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Valid_Success()
|
public void Deserialize_GenericCommandType_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_EmptyEntry_Success()
|
public void Deserialize_GenericCommandType_EmptyEntry_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,,MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,,MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Invalid_Success()
|
public void Deserialize_GenericCommandType_Invalid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,TotallyNotAVallidCommand,MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,TotallyNotAVallidCommand,MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Space_Valid_Success()
|
public void Deserialize_GenericCommandType_Space_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Array_Valid_Success()
|
public void Deserialize_String_Array_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<string>
|
var desiredValue = new GenericBodyArrayModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Array_Valid_Success()
|
public void Deserialize_GenericCommandType_Array_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
var desiredValue = new GenericBodyArrayModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyArrayModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,86 +6,85 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Jellyfin.Extensions.Tests.Json.Converters
|
namespace Jellyfin.Extensions.Tests.Json.Converters
|
||||||
{
|
{
|
||||||
public static class JsonCommaDelimitedIReadOnlyListTests
|
public class JsonCommaDelimitedIReadOnlyListTests
|
||||||
{
|
{
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
Converters =
|
||||||
|
{
|
||||||
|
new JsonStringEnumConverter()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Valid_Success()
|
public void Deserialize_String_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a,b,c"" }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a,b,c"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Space_Valid_Success()
|
public void Deserialize_String_Space_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a, b, c"" }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": ""a, b, c"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Valid_Success()
|
public void Deserialize_GenericCommandType_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp,MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Space_Valid_Success()
|
public void Deserialize_GenericCommandType_Space_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": ""MoveUp, MoveDown"" }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_String_Array_Valid_Success()
|
public void Deserialize_String_Array_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
var desiredValue = new GenericBodyIReadOnlyListModel<string>
|
||||||
{
|
{
|
||||||
Value = new[] { "a", "b", "c" }
|
Value = new[] { "a", "b", "c" }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", _jsonOptions);
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<string>>(@"{ ""Value"": [""a"",""b"",""c""] }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public static void Deserialize_GenericCommandType_Array_Valid_Success()
|
public void Deserialize_GenericCommandType_Array_Valid_Success()
|
||||||
{
|
{
|
||||||
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
var desiredValue = new GenericBodyIReadOnlyListModel<GeneralCommandType>
|
||||||
{
|
{
|
||||||
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
Value = new[] { GeneralCommandType.MoveUp, GeneralCommandType.MoveDown }
|
||||||
};
|
};
|
||||||
|
|
||||||
var options = new JsonSerializerOptions();
|
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", _jsonOptions);
|
||||||
options.Converters.Add(new JsonStringEnumConverter());
|
|
||||||
var value = JsonSerializer.Deserialize<GenericBodyIReadOnlyListModel<GeneralCommandType>>(@"{ ""Value"": [""MoveUp"", ""MoveDown""] }", options);
|
|
||||||
Assert.Equal(desiredValue.Value, value?.Value);
|
Assert.Equal(desiredValue.Value, value?.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
|
|
||||||
namespace Jellyfin.Networking.Tests
|
namespace Jellyfin.Networking.Tests
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
|||||||
{
|
{
|
||||||
public partial class ItemImageProviderTests
|
public partial class ItemImageProviderTests
|
||||||
{
|
{
|
||||||
private const string TestDataImagePath = "Test Data/Images/blank{0}.jpg";
|
private static readonly CompositeFormat _testDataImagePath = CompositeFormat.Parse("Test Data/Images/blank{0}.jpg");
|
||||||
|
|
||||||
[GeneratedRegex("[0-9]+")]
|
[GeneratedRegex("[0-9]+")]
|
||||||
private static partial Regex NumbersRegex();
|
private static partial Regex NumbersRegex();
|
||||||
@ -275,7 +275,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
|||||||
{
|
{
|
||||||
HasImage = true,
|
HasImage = true,
|
||||||
Format = ImageFormat.Jpg,
|
Format = ImageFormat.Jpg,
|
||||||
Path = responseHasPath ? string.Format(CultureInfo.InvariantCulture, TestDataImagePath, 0) : null,
|
Path = responseHasPath ? string.Format(CultureInfo.InvariantCulture, _testDataImagePath, 0) : null,
|
||||||
Protocol = protocol
|
Protocol = protocol
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -563,21 +563,21 @@ namespace Jellyfin.Providers.Tests.Manager
|
|||||||
mockFileSystem.Setup(fs => fs.GetFilePaths(It.IsAny<string>(), It.IsAny<bool>()))
|
mockFileSystem.Setup(fs => fs.GetFilePaths(It.IsAny<string>(), It.IsAny<bool>()))
|
||||||
.Returns(new[]
|
.Returns(new[]
|
||||||
{
|
{
|
||||||
string.Format(CultureInfo.InvariantCulture, TestDataImagePath, 0),
|
string.Format(CultureInfo.InvariantCulture, _testDataImagePath, 0),
|
||||||
string.Format(CultureInfo.InvariantCulture, TestDataImagePath, 1)
|
string.Format(CultureInfo.InvariantCulture, _testDataImagePath, 1)
|
||||||
});
|
});
|
||||||
|
|
||||||
return new ItemImageProvider(new NullLogger<ItemImageProvider>(), providerManager, mockFileSystem.Object);
|
return new ItemImageProvider(new NullLogger<ItemImageProvider>(), providerManager, mockFileSystem.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BaseItem GetItemWithImages(ImageType type, int count, bool validPaths)
|
private static Video GetItemWithImages(ImageType type, int count, bool validPaths)
|
||||||
{
|
{
|
||||||
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
// Has to exist for querying DateModified time on file, results stored but not checked so not populating
|
||||||
BaseItem.FileSystem ??= Mock.Of<IFileSystem>();
|
BaseItem.FileSystem ??= Mock.Of<IFileSystem>();
|
||||||
|
|
||||||
var item = new Video();
|
var item = new Video();
|
||||||
|
|
||||||
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
var path = validPaths ? _testDataImagePath.Format : "invalid path {0}";
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
item.SetImagePath(type, i, new FileSystemMetadata
|
item.SetImagePath(type, i, new FileSystemMetadata
|
||||||
@ -604,7 +604,7 @@ namespace Jellyfin.Providers.Tests.Manager
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private static LocalImageInfo[] GetImages(ImageType type, int count, bool validPaths)
|
private static LocalImageInfo[] GetImages(ImageType type, int count, bool validPaths)
|
||||||
{
|
{
|
||||||
var path = validPaths ? TestDataImagePath : "invalid path {0}";
|
var path = validPaths ? _testDataImagePath.Format : "invalid path {0}";
|
||||||
var images = new LocalImageInfo[count];
|
var images = new LocalImageInfo[count];
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
|
@ -9,22 +9,21 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting
|
|||||||
{
|
{
|
||||||
public class AiredEpisodeOrderComparerTests
|
public class AiredEpisodeOrderComparerTests
|
||||||
{
|
{
|
||||||
|
private readonly AiredEpisodeOrderComparer _cmp = new AiredEpisodeOrderComparer();
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[ClassData(typeof(EpisodeBadData))]
|
[ClassData(typeof(EpisodeBadData))]
|
||||||
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem? x, BaseItem? y)
|
public void Compare_GivenNull_ThrowsArgumentNullException(BaseItem? x, BaseItem? y)
|
||||||
{
|
{
|
||||||
var cmp = new AiredEpisodeOrderComparer();
|
Assert.Throws<ArgumentNullException>(() => _cmp.Compare(x, y));
|
||||||
Assert.Throws<ArgumentNullException>(() => cmp.Compare(x, y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[ClassData(typeof(EpisodeTestData))]
|
[ClassData(typeof(EpisodeTestData))]
|
||||||
public void AiredEpisodeOrderCompareTest(BaseItem x, BaseItem y, int expected)
|
public void AiredEpisodeOrderCompareTest(BaseItem x, BaseItem y, int expected)
|
||||||
{
|
{
|
||||||
var cmp = new AiredEpisodeOrderComparer();
|
Assert.Equal(expected, _cmp.Compare(x, y));
|
||||||
|
Assert.Equal(-expected, _cmp.Compare(y, x));
|
||||||
Assert.Equal(expected, cmp.Compare(x, y));
|
|
||||||
Assert.Equal(-expected, cmp.Compare(y, x));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class EpisodeBadData : TheoryData<BaseItem?, BaseItem?>
|
private sealed class EpisodeBadData : TheoryData<BaseItem?, BaseItem?>
|
||||||
|
@ -9,7 +9,7 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting;
|
|||||||
|
|
||||||
public class IndexNumberComparerTests
|
public class IndexNumberComparerTests
|
||||||
{
|
{
|
||||||
private readonly IBaseItemComparer _cmp = new IndexNumberComparer();
|
private readonly IndexNumberComparer _cmp = new IndexNumberComparer();
|
||||||
|
|
||||||
public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
|
public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
|
||||||
=> new()
|
=> new()
|
||||||
|
@ -9,7 +9,7 @@ namespace Jellyfin.Server.Implementations.Tests.Sorting;
|
|||||||
|
|
||||||
public class ParentIndexNumberComparerTests
|
public class ParentIndexNumberComparerTests
|
||||||
{
|
{
|
||||||
private readonly IBaseItemComparer _cmp = new ParentIndexNumberComparer();
|
private readonly ParentIndexNumberComparer _cmp = new ParentIndexNumberComparer();
|
||||||
|
|
||||||
public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
|
public static TheoryData<BaseItem?, BaseItem?> Compare_GivenNull_ThrowsArgumentNullException_TestData()
|
||||||
=> new()
|
=> new()
|
||||||
|
@ -6,11 +6,12 @@ using Jellyfin.Server.Extensions;
|
|||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Net;
|
using MediaBrowser.Common.Net;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging.Abstractions;
|
using Microsoft.Extensions.Logging.Abstractions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
|
||||||
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
namespace Jellyfin.Server.Tests
|
namespace Jellyfin.Server.Tests
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user