Misc fixes (#16837)
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
Stale PR Check / Check PRs with merge conflicts (push) Has been cancelled
Stale Issue Labeler / Check for stale issues (push) Has been cancelled

* Order chapter response by start time

* Properly handle cancellation in MediaSegmentManager

* Prevent unecessary log spam in NetworkUtils

* Fixup
This commit is contained in:
Bond-009
2026-05-17 14:07:43 +02:00
committed by GitHub
4 changed files with 87 additions and 11 deletions

View File

@@ -55,6 +55,7 @@ public class ChapterRepository : IChapterRepository
{
using var context = _dbProvider.CreateDbContext();
return context.Chapters.AsNoTracking().Where(e => e.ItemId.Equals(baseItemId))
.OrderBy(e => e.StartPositionTicks)
.Select(e => new
{
chapter = e,
@@ -69,18 +70,16 @@ public class ChapterRepository : IChapterRepository
public void SaveChapters(Guid itemId, IReadOnlyList<ChapterInfo> chapters)
{
using var context = _dbProvider.CreateDbContext();
using (var transaction = context.Database.BeginTransaction())
using var transaction = context.Database.BeginTransaction();
context.Chapters.Where(e => e.ItemId.Equals(itemId)).ExecuteDelete();
for (var i = 0; i < chapters.Count; i++)
{
context.Chapters.Where(e => e.ItemId.Equals(itemId)).ExecuteDelete();
for (var i = 0; i < chapters.Count; i++)
{
var chapter = chapters[i];
context.Chapters.Add(Map(chapter, i, itemId));
}
context.SaveChanges();
transaction.Commit();
var chapter = chapters[i];
context.Chapters.Add(Map(chapter, i, itemId));
}
context.SaveChanges();
transaction.Commit();
}
/// <inheritdoc />

View File

@@ -81,6 +81,8 @@ public class MediaSegmentManager : IMediaSegmentManager
foreach (var provider in providers)
{
cancellationToken.ThrowIfCancellationRequested();
if (!await provider.Supports(baseItem).ConfigureAwait(false))
{
_logger.LogDebug("Media Segment provider {ProviderName} does not support item with path {MediaPath}", provider.Name, baseItem.Path);
@@ -146,6 +148,15 @@ public class MediaSegmentManager : IMediaSegmentManager
await CreateSegmentAsync(segment, providerId).ConfigureAwait(false);
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
throw;
}
catch (Exception ex) when (cancellationToken.IsCancellationRequested)
{
_logger.LogDebug(ex, "Provider {ProviderName} aborted segment extraction for {MediaPath} due to shutdown", provider.Name, baseItem.Path);
break;
}
catch (Exception ex)
{
_logger.LogError(ex, "Provider {ProviderName} failed to extract segments from {MediaPath}", provider.Name, baseItem.Path);

View File

@@ -180,9 +180,16 @@ public static partial class NetworkUtils
List<IPData>? tmpResult = null;
for (int a = 0; a < values.Length; a++)
{
// Skip entries whose '!' polarity doesn't match this pass
var trimmed = values[a].AsSpan().Trim();
if (trimmed.StartsWith('!') != negated)
{
continue;
}
if (TryParseToSubnet(values[a], out var innerResult, negated))
{
(tmpResult ??= new()).Add(innerResult);
(tmpResult ??= []).Add(innerResult);
}
else
{

View File

@@ -135,6 +135,65 @@ namespace Jellyfin.Networking.Tests
Times.Once);
}
/// <summary>
/// Verifies that IPv4 entries whose '!' polarity doesn't match the requested pass are skipped silently,
/// not logged as invalid. Callers parse the same list twice (LAN and excluded) so the off-polarity
/// entries are expected, not erroneous.
/// </summary>
[Fact]
public static void TryParseToSubnets_PolarityMismatchIPv4_DoesNotWarn()
{
var logger = new Mock<ILogger>();
var values = new[] { "127.0.0.0/8", "192.168.178.0/24", "!10.0.0.0/8" };
// Non-negated pass picks up the two non-'!' entries and ignores '!10.0.0.0/8' silently.
Assert.True(NetworkUtils.TryParseToSubnets(values, out var lanResult, false, logger.Object));
Assert.NotNull(lanResult);
Assert.Equal(2, lanResult.Count);
// Negated pass picks up the single '!' entry and ignores the others silently.
Assert.True(NetworkUtils.TryParseToSubnets(values, out var excludedResult, true, logger.Object));
Assert.NotNull(excludedResult);
Assert.Single(excludedResult);
logger.Verify(
l => l.Log(
LogLevel.Warning,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Never);
}
/// <summary>
/// Same as the IPv4 case but for IPv6 entries — makes sure the polarity pre-check works
/// for IPv6 CIDR notation (with '::') as well.
/// </summary>
[Fact]
public static void TryParseToSubnets_PolarityMismatchIPv6_DoesNotWarn()
{
var logger = new Mock<ILogger>();
var values = new[] { "fd00::/8", "fe80::/10", "!fd12:3456:789a::/48" };
Assert.True(NetworkUtils.TryParseToSubnets(values, out var lanResult, false, logger.Object));
Assert.NotNull(lanResult);
Assert.Equal(2, lanResult.Count);
Assert.True(NetworkUtils.TryParseToSubnets(values, out var excludedResult, true, logger.Object));
Assert.NotNull(excludedResult);
Assert.Single(excludedResult);
logger.Verify(
l => l.Log(
LogLevel.Warning,
It.IsAny<EventId>(),
It.IsAny<It.IsAnyType>(),
It.IsAny<Exception>(),
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
Times.Never);
}
/// <summary>
/// Checks if IPv4 address is within a defined subnet.
/// </summary>