From caedd8370bf0a548e5d03fcf7ddeb0f1049ed59c Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Thu, 15 Jan 2026 22:31:58 -0600 Subject: [PATCH] fix other video artwork in xmltv --- CHANGELOG.md | 2 ++ .../Commands/RefreshChannelDataHandler.cs | 4 ++++ .../Repositories/IOtherVideoRepository.cs | 1 + .../Data/Repositories/OtherVideoRepository.cs | 11 +++++++++++ .../Core/Metadata/OtherVideoFolderScanner.cs | 15 +++++++++++---- ErsatzTV/Resources/Templates/_otherVideo.sbntxt | 6 ++++-- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00a1fd800..5d31dd524 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - MySql: fix searching for shows and seasons in schedule items editor - Fix 500 errors when serving XMLTV due to concurrent file reads and writes - Fix playback of AC3 audio when targeting stereo output and input layout changes mid-stream +- Use other video artwork in XMLTV template +- Remove artwork from other videos when artwork has been removed from disk ## [26.1.1] - 2026-01-08 ### Fixed diff --git a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs index 562996299..5d0207327 100644 --- a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs @@ -883,6 +883,8 @@ public class RefreshChannelDataHandler : IRequestHandler metadata.Genres ??= []; metadata.Guids ??= []; + string artworkPath = GetPrioritizedArtworkPath(metadata); + var data = new { ProgrammeStart = start, @@ -897,6 +899,8 @@ public class RefreshChannelDataHandler : IRequestHandler OtherVideoPlot = metadata.Plot, OtherVideoHasYear = metadata.Year.HasValue, OtherVideoYear = metadata.Year, + OtherVideoHasArtwork = !string.IsNullOrWhiteSpace(artworkPath), + OtherVideoArtworkUrl = artworkPath, OtherVideoGenres = metadata.Genres.Map(g => g.Name).OrderBy(n => n), OtherVideoHasContentRating = !string.IsNullOrWhiteSpace(metadata.ContentRating), OtherVideoContentRating = metadata.ContentRating diff --git a/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs b/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs index 819477dfc..c1ee47f00 100644 --- a/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs +++ b/ErsatzTV.Core/Interfaces/Repositories/IOtherVideoRepository.cs @@ -19,4 +19,5 @@ public interface IOtherVideoRepository Task AddActor(OtherVideoMetadata metadata, Actor actor); Task AddDirector(OtherVideoMetadata metadata, Director director); Task AddWriter(OtherVideoMetadata metadata, Writer writer); + Task RemoveArtwork(OtherVideoMetadata metadata, ArtworkKind artworkKind); } diff --git a/ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs b/ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs index faaca624b..2c4135c3b 100644 --- a/ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs +++ b/ErsatzTV.Infrastructure/Data/Repositories/OtherVideoRepository.cs @@ -46,6 +46,8 @@ public class OtherVideoRepository : IOtherVideoRepository .ThenInclude(ovm => ovm.Directors) .Include(i => i.OtherVideoMetadata) .ThenInclude(ovm => ovm.Writers) + .Include(i => i.OtherVideoMetadata) + .ThenInclude(ovm => ovm.Artwork) .Include(ov => ov.LibraryPath) .ThenInclude(lp => lp.Library) .Include(ov => ov.MediaVersions) @@ -173,6 +175,15 @@ public class OtherVideoRepository : IOtherVideoRepository new { writer.Name, MetadataId = metadata.Id }).Map(result => result > 0); } + public async Task RemoveArtwork(OtherVideoMetadata metadata, ArtworkKind artworkKind) + { + await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); + var ids = metadata.Artwork.Where(a => a.ArtworkKind == artworkKind).Select(a => a.Id).ToHashSet(); + return await dbContext.Artwork + .Where(a => ids.Contains(a.Id)) + .ExecuteDeleteAsync() > 0; + } + private async Task>> AddOtherVideo( TvContext dbContext, int libraryPathId, diff --git a/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs b/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs index ecbacbdc3..79432f109 100644 --- a/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs +++ b/ErsatzTV.Scanner/Core/Metadata/OtherVideoFolderScanner.cs @@ -359,11 +359,18 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan { OtherVideo otherVideo = result.Item; - Option maybeThumbnail = LocateThumbnail(otherVideo); - foreach (string thumbnailFile in maybeThumbnail) + foreach (var metadata in otherVideo.OtherVideoMetadata.HeadOrNone()) { - OtherVideoMetadata metadata = otherVideo.OtherVideoMetadata.Head(); - await RefreshArtwork(thumbnailFile, metadata, ArtworkKind.Thumbnail, None, None, cancellationToken); + Option maybeThumbnail = LocateThumbnail(otherVideo); + foreach (string thumbnailFile in maybeThumbnail) + { + await RefreshArtwork(thumbnailFile, metadata, ArtworkKind.Thumbnail, None, None, cancellationToken); + } + + if (maybeThumbnail.IsNone && metadata.Artwork.Any(a => a.ArtworkKind is ArtworkKind.Thumbnail)) + { + await _otherVideoRepository.RemoveArtwork(metadata, ArtworkKind.Thumbnail); + } } return result; diff --git a/ErsatzTV/Resources/Templates/_otherVideo.sbntxt b/ErsatzTV/Resources/Templates/_otherVideo.sbntxt index 8293494d5..fc32a1059 100644 --- a/ErsatzTV/Resources/Templates/_otherVideo.sbntxt +++ b/ErsatzTV/Resources/Templates/_otherVideo.sbntxt @@ -13,6 +13,8 @@ Available values: - other_video_plot - other_video_has_year - other_video_year + - other_video_has_artwork + - other_video_artwork_url - other_video_genres - other_video_has_content_rating - other_video_content_rating @@ -35,8 +37,8 @@ The resulting XML will be minified by ErsatzTV - so feel free to keep things nic {{ for genre in other_video_genres }} {{ genre }} {{ end }} - {{ if movie_has_artwork }} - + {{ if other_video_has_artwork }} + {{ end }} {{ end }} {{ if other_video_has_content_rating }}