From e5a2a763d69f04e4aeec2020a645510ccd7dee49 Mon Sep 17 00:00:00 2001
From: Jason Dove <1695733+jasongdove@users.noreply.github.com>
Date: Tue, 21 Jul 2026 15:22:36 -0500
Subject: [PATCH] fix: randomize start points with classic playlists (#2948)
* fix: randomize start points with classic playlists
* update dependencies
---
CHANGELOG.md | 2 +
.../ErsatzTV.Application.csproj | 4 +-
.../ErsatzTV.Core.Tests.csproj | 18 +++---
.../Scheduling/PlaylistEnumeratorTests.cs | 5 ++
ErsatzTV.Core/ErsatzTV.Core.csproj | 18 +++---
.../BlockScheduling/BlockPlayoutEnumerator.cs | 1 +
.../Scheduling/Engine/MarathonHelper.cs | 2 +
.../Scheduling/Engine/PlaylistHelper.cs | 1 +
.../Scheduling/Engine/SchedulingEngine.cs | 1 +
.../Scheduling/PlaylistEnumerator.cs | 20 +++++-
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs | 1 +
.../YamlScheduling/EnumeratorCache.cs | 1 +
.../ErsatzTV.FFmpeg.Tests.csproj | 8 +--
ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj | 4 +-
.../ErsatzTV.Infrastructure.Sqlite.csproj | 2 +-
.../ErsatzTV.Infrastructure.Tests.csproj | 6 +-
.../ErsatzTV.Infrastructure.csproj | 6 +-
.../Core/FFmpeg/TranscodingTests.cs | 13 ++--
.../Core/Metadata/MovieFolderScannerTests.cs | 64 +++++++++----------
.../ErsatzTV.Scanner.Tests.csproj | 6 +-
ErsatzTV.Scanner/ErsatzTV.Scanner.csproj | 10 +--
ErsatzTV.Tests/ErsatzTV.Tests.csproj | 1 +
ErsatzTV/ErsatzTV.csproj | 21 +++---
23 files changed, 124 insertions(+), 91 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b27c598f5..46e9383f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,6 +8,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Update Plex movie and other video titles when changed from Plex
- The first library scan after updating will act like a deep scan due to adding title to the Plex etag calculation
- Future periodic scans will update titles in ETV automatically (deep scans will not be required to update titles)
+- Randomize start points on playlist items in classic schedules when setting is enabled
+ - Playlists ignored this setting in earlier builds
## [26.6.0] - 2026-07-09
### Added
diff --git a/ErsatzTV.Application/ErsatzTV.Application.csproj b/ErsatzTV.Application/ErsatzTV.Application.csproj
index 0ac00ea47..133ef6984 100644
--- a/ErsatzTV.Application/ErsatzTV.Application.csproj
+++ b/ErsatzTV.Application/ErsatzTV.Application.csproj
@@ -14,8 +14,8 @@
-
-
+
+
diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
index 9a882a6a1..c40941431 100644
--- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
+++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
@@ -9,20 +9,20 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
+
-
+
diff --git a/ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs b/ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs
index 1d174815b..90f3e3a20 100644
--- a/ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs
+++ b/ErsatzTV.Core.Tests/Scheduling/PlaylistEnumeratorTests.cs
@@ -62,6 +62,7 @@ public class PlaylistEnumeratorTests
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
var items = new List();
@@ -130,6 +131,7 @@ public class PlaylistEnumeratorTests
new CollectionEnumeratorState(),
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
var items = new List();
@@ -200,6 +202,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
var items = new List();
@@ -270,6 +273,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
var items = new List();
@@ -352,6 +356,7 @@ public class PlaylistEnumeratorTests
state,
shufflePlaylistItems: true,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
enumerator.CountForFiller.ShouldBe(7);
diff --git a/ErsatzTV.Core/ErsatzTV.Core.csproj b/ErsatzTV.Core/ErsatzTV.Core.csproj
index 02be50aed..d753c77f6 100644
--- a/ErsatzTV.Core/ErsatzTV.Core.csproj
+++ b/ErsatzTV.Core/ErsatzTV.Core.csproj
@@ -16,19 +16,19 @@
-
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
diff --git a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs
index 2cb096bad..4c6586f42 100644
--- a/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs
+++ b/ErsatzTV.Core/Scheduling/BlockScheduling/BlockPlayoutEnumerator.cs
@@ -168,6 +168,7 @@ public static class BlockPlayoutEnumerator
state,
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
cancellationToken);
DateTime historyTime = currentTime.UtcDateTime;
diff --git a/ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs b/ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs
index e7975327c..f67c5b04b 100644
--- a/ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs
+++ b/ErsatzTV.Core/Scheduling/Engine/MarathonHelper.cs
@@ -66,6 +66,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
state,
marathonShuffleGroups,
marathonBatchSize,
+ randomStartPoint: false,
cancellationToken);
}
@@ -136,6 +137,7 @@ public class MarathonHelper(IMediaCollectionRepository mediaCollectionRepository
state,
shuffleGroups,
batchSize: Option.None,
+ randomStartPoint: false,
cancellationToken);
return new PlaylistContentResult(
diff --git a/ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs b/ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs
index cb1bfa06a..d7ff4363d 100644
--- a/ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs
+++ b/ErsatzTV.Core/Scheduling/Engine/PlaylistHelper.cs
@@ -58,6 +58,7 @@ public class PlaylistHelper(IMediaCollectionRepository mediaCollectionRepository
state,
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
cancellationToken);
return new PlaylistContentResult(
diff --git a/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs b/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs
index 53837822e..2139f65c9 100644
--- a/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs
+++ b/ErsatzTV.Core/Scheduling/Engine/SchedulingEngine.cs
@@ -257,6 +257,7 @@ public class SchedulingEngine(
state,
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
CancellationToken.None);
string historyKey = HistoryDetails.KeyForSchedulingContent(key, PlaybackOrder.None);
diff --git a/ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs b/ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs
index 44706de67..194a99eb3 100644
--- a/ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs
+++ b/ErsatzTV.Core/Scheduling/PlaylistEnumerator.cs
@@ -121,6 +121,7 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
CollectionEnumeratorState state,
bool shufflePlaylistItems,
Option batchSize,
+ bool randomStartPoint,
CancellationToken cancellationToken)
{
var result = new PlaylistEnumerator
@@ -131,6 +132,10 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
_batchSize = batchSize
};
+ // random start points only apply to a fresh build with no saved state
+ var random = new Random(state.Seed);
+ randomStartPoint = randomStartPoint && state.Index == 0;
+
// collections should share enumerators
var enumeratorMap = new Dictionary();
result._allMediaItemIds = [];
@@ -166,6 +171,11 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
switch (playlistItem.PlaybackOrder)
{
case PlaybackOrder.Chronological:
+ if (randomStartPoint)
+ {
+ initState.Index = random.Next(0, items.Count - 1);
+ }
+
enumerator = new ChronologicalMediaCollectionEnumerator(items, initState);
break;
// TODO: fix multi episode shuffle?
@@ -187,18 +197,22 @@ public class PlaylistEnumerator : IMediaCollectionEnumerator
CollectionKey.ForPlaylistItem(playlistItem),
cancellationToken),
initState,
- // TODO: fix this
- false,
+ randomStartPoint,
cancellationToken);
break;
case PlaybackOrder.SeasonEpisode:
- // TODO: check random start point?
+ if (randomStartPoint)
+ {
+ initState.Index = random.Next(0, items.Count - 1);
+ }
+
enumerator = new SeasonEpisodeMediaCollectionEnumerator(items, initState);
// season, episode will filter out season 0, so we may get an empty enumerator back
if (enumerator.Count == 0)
{
enumerator = null;
}
+
break;
case PlaybackOrder.Random:
enumerator = new RandomizedMediaCollectionEnumerator(items, initState);
diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
index 582eb65d1..bfdb642dc 100644
--- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
+++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
@@ -1325,6 +1325,7 @@ public class PlayoutBuilder : IPlayoutBuilder
state,
marathonShuffleGroups,
batchSize: Option.None,
+ randomStartPoint,
cancellationToken);
}
}
diff --git a/ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs b/ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs
index 9c394253c..af3d9c09e 100644
--- a/ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs
+++ b/ErsatzTV.Core/Scheduling/YamlScheduling/EnumeratorCache.cs
@@ -175,6 +175,7 @@ public class EnumeratorCache(IMediaCollectionRepository mediaCollectionRepositor
state,
shufflePlaylistItems: false,
batchSize: Option.None,
+ randomStartPoint: false,
cancellationToken);
}
diff --git a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj
index c81e4c005..22d393f1f 100644
--- a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj
+++ b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
index e08b73939..8b7a66f11 100644
--- a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
+++ b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
@@ -15,8 +15,8 @@
-
-
+
+
diff --git a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj
index 352bd81f8..23fe09aea 100644
--- a/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj
+++ b/ErsatzTV.Infrastructure.Sqlite/ErsatzTV.Infrastructure.Sqlite.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
index ed169e16e..6dd693849 100644
--- a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
+++ b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj
@@ -9,8 +9,8 @@
-
-
+
+
@@ -22,7 +22,7 @@
all
-
+
diff --git a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
index f4cf012a5..3fc8fb95a 100644
--- a/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
+++ b/ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
@@ -18,8 +18,8 @@
-
-
+
+
@@ -36,7 +36,7 @@
-
+
diff --git a/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs b/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
index 179a37dfd..082bf04a3 100644
--- a/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
+++ b/ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs
@@ -348,13 +348,13 @@ public class TranscodingTests
metadataRepository.When(x => x.UpdateStatistics(Arg.Any(), Arg.Any(), Arg.Any()))
.Do(x =>
{
- MediaVersion version = x.Arg();
- if (version.Streams.Any(s => s.MediaStreamKind == MediaStreamKind.Video && !s.AttachedPic))
+ MediaVersion? version = x.Arg();
+ if (version != null && version.Streams.Any(s => s.MediaStreamKind == MediaStreamKind.Video && !s.AttachedPic))
{
version.MediaFiles = videoVersion.MediaFiles;
videoVersion = version;
}
- else
+ else if (version != null)
{
version.MediaFiles = songVersion.MediaFiles;
songVersion = version;
@@ -520,8 +520,11 @@ public class TranscodingTests
.Do(args =>
{
MediaVersion? version = args.Arg();
- version.MediaFiles = v.MediaFiles;
- v = version;
+ if (version != null)
+ {
+ version.MediaFiles = v.MediaFiles;
+ v = version;
+ }
});
var localStatisticsProvider = new LocalStatisticsProvider(
diff --git a/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs b/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs
index 4a2e37132..610bff242 100644
--- a/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs
+++ b/ErsatzTV.Scanner.Tests/Core/Metadata/MovieFolderScannerTests.cs
@@ -59,7 +59,7 @@ public class MovieFolderScannerTests
_movieRepository = Substitute.For();
_movieRepository.GetOrAdd(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())
.Returns(args =>
- Right>(new FakeMovieWithPath(args.Arg()))
+ Right>(new FakeMovieWithPath(args.Arg() ?? string.Empty))
.AsTask());
_movieRepository.FindMoviePaths(Arg.Any())
.Returns(new List().AsEnumerable().AsTask());
@@ -78,7 +78,7 @@ public class MovieFolderScannerTests
_localMetadataProvider.RefreshFallbackMetadata(Arg.Any())
.Returns(arg =>
{
- ((Movie)arg.Arg()).MovieMetadata = [new MovieMetadata { Artwork = [] }];
+ (arg.Arg() as Movie ?? new Movie()).MovieMetadata = [new MovieMetadata { Artwork = [] }];
return Task.FromResult(true);
});
@@ -141,10 +141,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
@@ -190,10 +190,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
@@ -238,10 +238,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshSidecarMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath),
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath),
metadataPath);
}
@@ -287,10 +287,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshSidecarMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath),
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath),
metadataPath);
}
@@ -340,10 +340,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(posterPath, ArtworkKind.Poster);
}
@@ -394,10 +394,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(posterPath, ArtworkKind.Poster);
}
@@ -448,10 +448,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(posterPath, ArtworkKind.Poster);
}
@@ -502,10 +502,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt);
}
@@ -556,10 +556,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt);
}
@@ -610,10 +610,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _imageCache.Received(1).CopyArtworkToCache(fanArtPath, ArtworkKind.FanArt);
}
@@ -664,10 +664,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
// Should receive Poster call (as folder.ext is valid for poster)
await _imageCache.Received(1).CopyArtworkToCache(folderImagePath, ArtworkKind.Poster);
@@ -805,10 +805,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
@@ -854,10 +854,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
@@ -905,10 +905,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
@@ -950,10 +950,10 @@ public class MovieFolderScannerTests
await _localStatisticsProvider.Received(1).RefreshStatistics(
FFmpegPath,
FFprobePath,
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
await _localMetadataProvider.Received(1).RefreshFallbackMetadata(
- Arg.Is(i => i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
+ Arg.Is(i => i != null && i.MediaVersions.Head().MediaFiles.Head().Path == moviePath));
}
[Test]
diff --git a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
index 073a3f933..0df5a6caa 100644
--- a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
+++ b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj
@@ -10,8 +10,8 @@
-
-
+
+
@@ -23,7 +23,7 @@
all
-
+
diff --git a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj
index 8963ce279..128416a88 100644
--- a/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj
+++ b/ErsatzTV.Scanner/ErsatzTV.Scanner.csproj
@@ -26,16 +26,16 @@
-
-
-
-
+
+
+
+
-
+
diff --git a/ErsatzTV.Tests/ErsatzTV.Tests.csproj b/ErsatzTV.Tests/ErsatzTV.Tests.csproj
index 5f8a6b2d2..27e94d915 100644
--- a/ErsatzTV.Tests/ErsatzTV.Tests.csproj
+++ b/ErsatzTV.Tests/ErsatzTV.Tests.csproj
@@ -4,6 +4,7 @@
net10.0
enable
enable
+ direct
diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj
index 0387fd85d..036c721cf 100644
--- a/ErsatzTV/ErsatzTV.csproj
+++ b/ErsatzTV/ErsatzTV.csproj
@@ -13,6 +13,7 @@
bf31217d-f4ec-4520-8cc3-138059044ede
latest-Recommended
true
+ direct
true
en-US
@@ -36,30 +37,30 @@
-
+
-
-
-
-
+
+
+
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
-
+
+