aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci-codeql-analysis.yml8
-rw-r--r--.github/workflows/ci-compat.yml4
-rw-r--r--.github/workflows/ci-openapi.yml4
-rw-r--r--.github/workflows/ci-tests.yml4
-rw-r--r--.github/workflows/commands.yml4
-rw-r--r--.github/workflows/issue-stale.yml2
-rw-r--r--.github/workflows/issue-template-check.yml2
-rw-r--r--.github/workflows/pull-request-stale.yaml2
-rw-r--r--.github/workflows/release-bump-version.yaml4
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs13
-rw-r--r--Emby.Server.Implementations/Localization/Core/sw.json1
-rw-r--r--Jellyfin.Server.Implementations/Item/BaseItemRepository.cs23
-rw-r--r--Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs5
-rw-r--r--Jellyfin.Server/Filters/CachingOpenApiProvider.cs89
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs2
-rw-r--r--MediaBrowser.Controller/IO/FileSystemHelper.cs42
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs28
-rw-r--r--MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs7
-rw-r--r--MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs2
-rw-r--r--MediaBrowser.Providers/Manager/MetadataService.cs4
20 files changed, 203 insertions, 47 deletions
diff --git a/.github/workflows/ci-codeql-analysis.yml b/.github/workflows/ci-codeql-analysis.yml
index 2918bd6a7..5a6cccda0 100644
--- a/.github/workflows/ci-codeql-analysis.yml
+++ b/.github/workflows/ci-codeql-analysis.yml
@@ -20,18 +20,18 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup .NET
uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
dotnet-version: '9.0.x'
- name: Initialize CodeQL
- uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
+ uses: github/codeql-action/init@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
with:
languages: ${{ matrix.language }}
queries: +security-extended
- name: Autobuild
- uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
+ uses: github/codeql-action/autobuild@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
+ uses: github/codeql-action/analyze@cf1bb45a277cb3c205638b2cd5c984db1c46a412 # v4.31.7
diff --git a/.github/workflows/ci-compat.yml b/.github/workflows/ci-compat.yml
index 298c21d7f..8a755a317 100644
--- a/.github/workflows/ci-compat.yml
+++ b/.github/workflows/ci-compat.yml
@@ -11,7 +11,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -40,7 +40,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
diff --git a/.github/workflows/ci-openapi.yml b/.github/workflows/ci-openapi.yml
index e1ee6ebe5..0a391dbe1 100644
--- a/.github/workflows/ci-openapi.yml
+++ b/.github/workflows/ci-openapi.yml
@@ -16,7 +16,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
@@ -41,7 +41,7 @@ jobs:
permissions: read-all
steps:
- name: Checkout repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml
index b2ac7a56e..f70243221 100644
--- a/.github/workflows/ci-tests.yml
+++ b/.github/workflows/ci-tests.yml
@@ -20,7 +20,7 @@ jobs:
runs-on: "${{ matrix.os }}"
steps:
- - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: actions/setup-dotnet@2016bd2012dba4e32de620c46fe006a3ac9f0602 # v5.0.1
with:
@@ -35,7 +35,7 @@ jobs:
--verbosity minimal
- name: Merge code coverage results
- uses: danielpalme/ReportGenerator-GitHub-Action@dcdfb6e704e87df6b2ed0cf123a6c9f69e364869 # v5.5.0
+ uses: danielpalme/ReportGenerator-GitHub-Action@ee0ae774f6d3afedcbd1683c1ab21b83670bdf8e # v5.5.1
with:
reports: "**/coverage.cobertura.xml"
targetdir: "merged/"
diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml
index 4ec92d42e..0d3e09d1a 100644
--- a/.github/workflows/commands.yml
+++ b/.github/workflows/commands.yml
@@ -24,7 +24,7 @@ jobs:
reactions: '+1'
- name: Checkout the latest code
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ secrets.JF_BOT_TOKEN }}
fetch-depth: 0
@@ -40,7 +40,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: pull in script
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
diff --git a/.github/workflows/issue-stale.yml b/.github/workflows/issue-stale.yml
index db22848c3..cb535297e 100644
--- a/.github/workflows/issue-stale.yml
+++ b/.github/workflows/issue-stale.yml
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
+ - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
ascending: true
diff --git a/.github/workflows/issue-template-check.yml b/.github/workflows/issue-template-check.yml
index 50453d112..8be48b5c3 100644
--- a/.github/workflows/issue-template-check.yml
+++ b/.github/workflows/issue-template-check.yml
@@ -10,7 +10,7 @@ jobs:
issues: write
steps:
- name: pull in script
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: jellyfin/jellyfin-triage-script
- name: install python
diff --git a/.github/workflows/pull-request-stale.yaml b/.github/workflows/pull-request-stale.yaml
index 223ffc590..0d74e643e 100644
--- a/.github/workflows/pull-request-stale.yaml
+++ b/.github/workflows/pull-request-stale.yaml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
if: ${{ contains(github.repository, 'jellyfin/') }}
steps:
- - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
+ - uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
with:
repo-token: ${{ secrets.JF_BOT_TOKEN }}
ascending: true
diff --git a/.github/workflows/release-bump-version.yaml b/.github/workflows/release-bump-version.yaml
index fa4025de5..d39d2cb9c 100644
--- a/.github/workflows/release-bump-version.yaml
+++ b/.github/workflows/release-bump-version.yaml
@@ -33,7 +33,7 @@ jobs:
yq-version: v4.9.8
- name: Checkout Repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ env.TAG_BRANCH }}
@@ -66,7 +66,7 @@ jobs:
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
steps:
- name: Checkout Repository
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
+ uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ env.TAG_BRANCH }}
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index fad97344b..4d68cb444 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -497,8 +497,17 @@ namespace Emby.Server.Implementations.IO
/// <inheritdoc />
public virtual bool AreEqual(string path1, string path2)
{
- return Path.TrimEndingDirectorySeparator(path1).Equals(
- Path.TrimEndingDirectorySeparator(path2),
+ if (string.IsNullOrWhiteSpace(path1) || string.IsNullOrWhiteSpace(path2))
+ {
+ return false;
+ }
+
+ var normalized1 = Path.TrimEndingDirectorySeparator(path1);
+ var normalized2 = Path.TrimEndingDirectorySeparator(path2);
+
+ return string.Equals(
+ normalized1,
+ normalized2,
_isEnvironmentCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
diff --git a/Emby.Server.Implementations/Localization/Core/sw.json b/Emby.Server.Implementations/Localization/Core/sw.json
new file mode 100644
index 000000000..0967ef424
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/sw.json
@@ -0,0 +1 @@
+{}
diff --git a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
index 2c18ce69a..84168291a 100644
--- a/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
+++ b/Jellyfin.Server.Implementations/Item/BaseItemRepository.cs
@@ -618,12 +618,18 @@ public sealed class BaseItemRepository
{
context.BaseItemProviders.Where(e => e.ItemId == entity.Id).ExecuteDelete();
context.BaseItemImageInfos.Where(e => e.ItemId == entity.Id).ExecuteDelete();
+ context.BaseItemMetadataFields.Where(e => e.ItemId == entity.Id).ExecuteDelete();
if (entity.Images is { Count: > 0 })
{
context.BaseItemImageInfos.AddRange(entity.Images);
}
+ if (entity.LockedFields is { Count: > 0 })
+ {
+ context.BaseItemMetadataFields.AddRange(entity.LockedFields);
+ }
+
context.BaseItems.Attach(entity).State = EntityState.Modified;
}
}
@@ -1647,19 +1653,18 @@ public sealed class BaseItemRepository
var tags = filter.Tags.ToList();
var excludeTags = filter.ExcludeTags.ToList();
- if (filter.IsMovie == true)
+ if (filter.IsMovie.HasValue)
{
- if (filter.IncludeItemTypes.Length == 0
- || filter.IncludeItemTypes.Contains(BaseItemKind.Movie)
- || filter.IncludeItemTypes.Contains(BaseItemKind.Trailer))
+ var shouldIncludeAllMovieTypes = filter.IsMovie.Value
+ && (filter.IncludeItemTypes.Length == 0
+ || filter.IncludeItemTypes.Contains(BaseItemKind.Movie)
+ || filter.IncludeItemTypes.Contains(BaseItemKind.Trailer));
+
+ if (!shouldIncludeAllMovieTypes)
{
- baseQuery = baseQuery.Where(e => e.IsMovie);
+ baseQuery = baseQuery.Where(e => e.IsMovie == filter.IsMovie.Value);
}
}
- else if (filter.IsMovie.HasValue)
- {
- baseQuery = baseQuery.Where(e => e.IsMovie == filter.IsMovie);
- }
if (filter.IsSeries.HasValue)
{
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 08c1a5065..04dd19eda 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -33,9 +33,11 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Interfaces;
using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.Swagger;
using Swashbuckle.AspNetCore.SwaggerGen;
using AuthenticationSchemes = Jellyfin.Api.Constants.AuthenticationSchemes;
@@ -259,7 +261,8 @@ namespace Jellyfin.Server.Extensions
c.OperationFilter<FileRequestFilter>();
c.OperationFilter<ParameterObsoleteFilter>();
c.DocumentFilter<AdditionalModelFilter>();
- });
+ })
+ .Replace(ServiceDescriptor.Transient<ISwaggerProvider, CachingOpenApiProvider>());
}
private static void AddPolicy(this AuthorizationOptions authorizationOptions, string policyName, IAuthorizationRequirement authorizationRequirement)
diff --git a/Jellyfin.Server/Filters/CachingOpenApiProvider.cs b/Jellyfin.Server/Filters/CachingOpenApiProvider.cs
new file mode 100644
index 000000000..4169f2fb3
--- /dev/null
+++ b/Jellyfin.Server/Filters/CachingOpenApiProvider.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Threading;
+using Microsoft.AspNetCore.Mvc.ApiExplorer;
+using Microsoft.Extensions.Caching.Memory;
+using Microsoft.Extensions.Options;
+using Microsoft.OpenApi.Models;
+using Swashbuckle.AspNetCore.Swagger;
+using Swashbuckle.AspNetCore.SwaggerGen;
+
+namespace Jellyfin.Server.Filters;
+
+/// <summary>
+/// OpenApi provider with caching.
+/// </summary>
+internal sealed class CachingOpenApiProvider : ISwaggerProvider
+{
+ private const string CacheKey = "openapi.json";
+
+ private static readonly MemoryCacheEntryOptions _cacheOptions = new() { SlidingExpiration = TimeSpan.FromMinutes(5) };
+ private static readonly SemaphoreSlim _lock = new(1, 1);
+ private static readonly TimeSpan _lockTimeout = TimeSpan.FromSeconds(1);
+
+ private readonly IMemoryCache _memoryCache;
+ private readonly SwaggerGenerator _swaggerGenerator;
+ private readonly SwaggerGeneratorOptions _swaggerGeneratorOptions;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="CachingOpenApiProvider"/> class.
+ /// </summary>
+ /// <param name="optionsAccessor">The options accessor.</param>
+ /// <param name="apiDescriptionsProvider">The api descriptions provider.</param>
+ /// <param name="schemaGenerator">The schema generator.</param>
+ /// <param name="memoryCache">The memory cache.</param>
+ public CachingOpenApiProvider(
+ IOptions<SwaggerGeneratorOptions> optionsAccessor,
+ IApiDescriptionGroupCollectionProvider apiDescriptionsProvider,
+ ISchemaGenerator schemaGenerator,
+ IMemoryCache memoryCache)
+ {
+ _swaggerGeneratorOptions = optionsAccessor.Value;
+ _swaggerGenerator = new SwaggerGenerator(_swaggerGeneratorOptions, apiDescriptionsProvider, schemaGenerator);
+ _memoryCache = memoryCache;
+ }
+
+ /// <inheritdoc />
+ public OpenApiDocument GetSwagger(string documentName, string? host = null, string? basePath = null)
+ {
+ if (_memoryCache.TryGetValue(CacheKey, out OpenApiDocument? openApiDocument) && openApiDocument is not null)
+ {
+ return AdjustDocument(openApiDocument, host, basePath);
+ }
+
+ var acquired = _lock.Wait(_lockTimeout);
+ try
+ {
+ if (_memoryCache.TryGetValue(CacheKey, out openApiDocument) && openApiDocument is not null)
+ {
+ return AdjustDocument(openApiDocument, host, basePath);
+ }
+
+ if (!acquired)
+ {
+ throw new InvalidOperationException("OpenApi document is generating");
+ }
+
+ openApiDocument = _swaggerGenerator.GetSwagger(documentName);
+ _memoryCache.Set(CacheKey, openApiDocument, _cacheOptions);
+ return AdjustDocument(openApiDocument, host, basePath);
+ }
+ finally
+ {
+ if (acquired)
+ {
+ _lock.Release();
+ }
+ }
+ }
+
+ private OpenApiDocument AdjustDocument(OpenApiDocument document, string? host, string? basePath)
+ {
+ document.Servers = _swaggerGeneratorOptions.Servers.Count != 0
+ ? _swaggerGeneratorOptions.Servers
+ : string.IsNullOrEmpty(host) && string.IsNullOrEmpty(basePath)
+ ? []
+ : [new OpenApiServer { Url = $"{host}{basePath}" }];
+
+ return document;
+ }
+}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 151b957fe..59a967725 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -1409,7 +1409,7 @@ namespace MediaBrowser.Controller.Entities
if (this is BoxSet && (query.OrderBy is null || query.OrderBy.Count == 0))
{
realChildren = realChildren
- .OrderBy(e => e.ProductionYear ?? int.MaxValue)
+ .OrderBy(e => e.PremiereDate ?? DateTime.MaxValue)
.ToArray();
}
diff --git a/MediaBrowser.Controller/IO/FileSystemHelper.cs b/MediaBrowser.Controller/IO/FileSystemHelper.cs
index 3e390ca42..44b7fadf5 100644
--- a/MediaBrowser.Controller/IO/FileSystemHelper.cs
+++ b/MediaBrowser.Controller/IO/FileSystemHelper.cs
@@ -64,6 +64,29 @@ public static class FileSystemHelper
}
/// <summary>
+ /// Resolves a single link hop for the specified path.
+ /// </summary>
+ /// <remarks>
+ /// Returns <c>null</c> if the path is not a symbolic link or the filesystem does not support link resolution (e.g., exFAT).
+ /// </remarks>
+ /// <param name="path">The file path to resolve.</param>
+ /// <returns>
+ /// A <see cref="FileInfo"/> representing the next link target if the path is a link; otherwise, <c>null</c>.
+ /// </returns>
+ private static FileInfo? Resolve(string path)
+ {
+ try
+ {
+ return File.ResolveLinkTarget(path, returnFinalTarget: false) as FileInfo;
+ }
+ catch (IOException)
+ {
+ // Filesystem doesn't support links (e.g., exFAT).
+ return null;
+ }
+ }
+
+ /// <summary>
/// Gets the target of the specified file link.
/// </summary>
/// <remarks>
@@ -84,23 +107,26 @@ public static class FileSystemHelper
if (!returnFinalTarget)
{
- return File.ResolveLinkTarget(linkPath, returnFinalTarget: false) as FileInfo;
- }
-
- if (File.ResolveLinkTarget(linkPath, returnFinalTarget: false) is not FileInfo targetInfo)
- {
- return null;
+ return Resolve(linkPath);
}
- if (!targetInfo.Exists)
+ var targetInfo = Resolve(linkPath);
+ if (targetInfo is null || !targetInfo.Exists)
{
return targetInfo;
}
var currentPath = targetInfo.FullName;
var visited = new HashSet<string>(StringComparer.Ordinal) { linkPath, currentPath };
- while (File.ResolveLinkTarget(currentPath, returnFinalTarget: false) is FileInfo linkInfo)
+
+ while (true)
{
+ var linkInfo = Resolve(currentPath);
+ if (linkInfo is null)
+ {
+ break;
+ }
+
var targetPath = linkInfo.FullName;
// If an infinite loop is detected, return the file info for the
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index a1d891535..843590a1f 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -2378,6 +2378,13 @@ namespace MediaBrowser.Controller.MediaEncoding
var requestHasSDR = requestedRangeTypes.Contains(VideoRangeType.SDR.ToString(), StringComparison.OrdinalIgnoreCase);
var requestHasDOVI = requestedRangeTypes.Contains(VideoRangeType.DOVI.ToString(), StringComparison.OrdinalIgnoreCase);
+ // If SDR is the only supported range, we should not copy any of the HDR streams.
+ // All the following copy check assumes at least one HDR format is supported.
+ if (requestedRangeTypes.Length == 1 && requestHasSDR && videoStream.VideoRangeType != VideoRangeType.SDR)
+ {
+ return false;
+ }
+
// If the client does not support DOVI and the video stream is DOVI without fallback, we should not copy it.
if (!requestHasDOVI && videoStream.VideoRangeType == VideoRangeType.DOVI)
{
@@ -5942,28 +5949,37 @@ namespace MediaBrowser.Controller.MediaEncoding
var isFullAfbcPipeline = isEncoderSupportAfbc && isDrmInDrmOut && !doOclTonemap;
var swapOutputWandH = doRkVppTranspose && swapWAndH;
- var outFormat = doOclTonemap ? "p010" : (isMjpegEncoder ? "bgra" : "nv12"); // RGA only support full range in rgb fmts
+ var outFormat = doOclTonemap ? "p010" : "nv12";
var hwScaleFilter = GetHwScaleFilter("vpp", "rkrga", outFormat, swapOutputWandH, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH);
- var doScaling = GetHwScaleFilter("vpp", "rkrga", string.Empty, swapOutputWandH, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH);
+ var doScaling = !string.IsNullOrEmpty(GetHwScaleFilter("vpp", "rkrga", string.Empty, swapOutputWandH, swpInW, swpInH, reqW, reqH, reqMaxW, reqMaxH));
if (!hasSubs
|| doRkVppTranspose
|| !isFullAfbcPipeline
- || !string.IsNullOrEmpty(doScaling))
+ || doScaling)
{
+ var isScaleRatioSupported = IsScaleRatioSupported(inW, inH, reqW, reqH, reqMaxW, reqMaxH, 8.0f);
+
// RGA3 hardware only support (1/8 ~ 8) scaling in each blit operation,
// but in Trickplay there's a case: (3840/320 == 12), enable 2pass for it
- if (!string.IsNullOrEmpty(doScaling)
- && !IsScaleRatioSupported(inW, inH, reqW, reqH, reqMaxW, reqMaxH, 8.0f))
+ if (doScaling && !isScaleRatioSupported)
{
// Vendor provided BSP kernel has an RGA driver bug that causes the output to be corrupted for P010 format.
// Use NV15 instead of P010 to avoid the issue.
// SDR inputs are using BGRA formats already which is not affected.
- var intermediateFormat = string.Equals(outFormat, "p010", StringComparison.OrdinalIgnoreCase) ? "nv15" : outFormat;
+ var intermediateFormat = doOclTonemap ? "nv15" : (isMjpegEncoder ? "bgra" : outFormat);
var hwScaleFilterFirstPass = $"scale_rkrga=w=iw/7.9:h=ih/7.9:format={intermediateFormat}:force_original_aspect_ratio=increase:force_divisible_by=4:afbc=1";
mainFilters.Add(hwScaleFilterFirstPass);
}
+ // The RKMPP MJPEG encoder on some newer chip models no longer supports RGB input.
+ // Use 2pass here to enable RGA output of full-range YUV in the 2nd pass.
+ if (isMjpegEncoder && !doOclTonemap && ((doScaling && isScaleRatioSupported) || !doScaling))
+ {
+ var hwScaleFilterFirstPass = "vpp_rkrga=format=bgra:afbc=1";
+ mainFilters.Add(hwScaleFilterFirstPass);
+ }
+
if (!string.IsNullOrEmpty(hwScaleFilter) && doRkVppTranspose)
{
hwScaleFilter += $":transpose={transposeDir}";
diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
index 7c0be5a9f..dc20a6d63 100644
--- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
+++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs
@@ -1,3 +1,4 @@
+using System;
using System.IO;
using System.Linq;
using BDInfo.IO;
@@ -58,6 +59,8 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
}
}
+ private static bool IsHidden(ReadOnlySpan<char> name) => name.StartsWith('.');
+
/// <summary>
/// Gets the directories.
/// </summary>
@@ -65,6 +68,7 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
public IDirectoryInfo[] GetDirectories()
{
return _fileSystem.GetDirectories(_impl.FullName)
+ .Where(d => !IsHidden(d.Name))
.Select(x => new BdInfoDirectoryInfo(_fileSystem, x))
.ToArray();
}
@@ -76,6 +80,7 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
public IFileInfo[] GetFiles()
{
return _fileSystem.GetFiles(_impl.FullName)
+ .Where(d => !IsHidden(d.Name))
.Select(x => new BdInfoFileInfo(x))
.ToArray();
}
@@ -88,6 +93,7 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
public IFileInfo[] GetFiles(string searchPattern)
{
return _fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false)
+ .Where(d => !IsHidden(d.Name))
.Select(x => new BdInfoFileInfo(x))
.ToArray();
}
@@ -105,6 +111,7 @@ public class BdInfoDirectoryInfo : IDirectoryInfo
new[] { searchPattern },
false,
searchOption == SearchOption.AllDirectories)
+ .Where(d => !IsHidden(d.Name))
.Select(x => new BdInfoFileInfo(x))
.ToArray();
}
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index b7fef842b..73c5b88c8 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -511,7 +511,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
? "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_chapters -show_format"
: "{0} -i {1} -threads {2} -v warning -print_format json -show_streams -show_format";
- if (!isAudio && _proberSupportsFirstVideoFrame)
+ if (protocol == MediaProtocol.File && !isAudio && _proberSupportsFirstVideoFrame)
{
args += " -show_frames -only_first_vframe";
}
diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs
index f220ec4a1..a2102ca9c 100644
--- a/MediaBrowser.Providers/Manager/MetadataService.cs
+++ b/MediaBrowser.Providers/Manager/MetadataService.cs
@@ -151,9 +151,9 @@ namespace MediaBrowser.Providers.Manager
.ConfigureAwait(false);
updateType |= beforeSaveResult;
- if (!isFirstRefresh)
+ if (isFirstRefresh)
{
- updateType = await SaveInternal(item, refreshOptions, updateType, isFirstRefresh, requiresRefresh, metadataResult, cancellationToken).ConfigureAwait(false);
+ await SaveItemAsync(metadataResult, ItemUpdateType.MetadataImport, cancellationToken).ConfigureAwait(false);
}
// Next run metadata providers