From 9e324f14a750211ca5be9234ada1ed1067c1e3f2 Mon Sep 17 00:00:00 2001 From: Thomas Gander Date: Sat, 24 Jan 2026 08:34:42 -0700 Subject: [PATCH] Significantly refactored code to help with readability of logging and episode processing --- .../Helpers/LoggingHelper.cs | 154 ++---------------- .../Helpers/MovieHelper.cs | 50 ++---- .../Helpers/SeriesHelper.cs | 89 +++++----- .../ScheduledTasks/StaleMediaTask.cs | 78 +++++---- 4 files changed, 128 insertions(+), 243 deletions(-) diff --git a/Jellyfin.Plugin.MediaCleaner/Helpers/LoggingHelper.cs b/Jellyfin.Plugin.MediaCleaner/Helpers/LoggingHelper.cs index 9ac7b8b..c78aadf 100644 --- a/Jellyfin.Plugin.MediaCleaner/Helpers/LoggingHelper.cs +++ b/Jellyfin.Plugin.MediaCleaner/Helpers/LoggingHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using Jellyfin.Plugin.MediaCleaner.Configuration; using Jellyfin.Plugin.MediaCleaner.Models; @@ -10,150 +11,25 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Plugin.MediaCleaner.Helpers; -public class LoggingHelper +public class LoggingHelper(ILogger logger) { - private readonly ILogger _logger; + private readonly ILogger _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - public LoggingHelper(ILogger logger) + [SuppressMessage("Microsoft.Performance", "CA2254:TemplateShouldBeConstant", Justification = "Message parameter is intentionally variable for flexible debug logging")] + public void LogDebugInformation(string message, params object?[] args) { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + if (Configuration.DebugMode) + { + _logger.LogInformation(message, args); + } + } + + [SuppressMessage("Microsoft.Performance", "CA2254:TemplateShouldBeConstant", Justification = "Message parameter is intentionally variable for flexible logging")] + public void LogInformation(string message, params object?[] args) + { + _logger.LogInformation(message, args); } private static PluginConfiguration Configuration => Plugin.Instance!.Configuration; - - public void StartLogging() - { - if (Configuration.DebugMode) - { - _logger.LogInformation("--DEBUG MODE ACTIVE--"); - } - - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Starting stale media scan..."); - } - - public void EndLogging() - { - _logger.LogInformation("Ending stale media scan..."); - _logger.LogInformation("-------------------------------------------------"); - } - - public void PrintDebugEndOfScanningForSeries(BaseItem item) - { - if (Configuration.DebugMode) - { - _logger.LogInformation("End of scanning for series: {Series}", item); - _logger.LogInformation("-------------------------------------------------"); - } - } - - - public void StartScanningSeriesItems() - { - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Starting scan of series items."); - _logger.LogInformation("-------------------------------------------------"); - } - - public void StartScanningMoviesItems() - { - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Starting scan of movies items."); - _logger.LogInformation("-------------------------------------------------"); - } - - public void PrintItemsInformation(IReadOnlyCollection items) - { - ArgumentNullException.ThrowIfNull(items); - - _logger.LogInformation("Total items: {ItemCount}", items.Count); - _logger.LogInformation("Stale items found: {AllItems}", items); - } - - public void PrintStaleMoviesInformation(IReadOnlyCollection staleMovies) - { - ArgumentNullException.ThrowIfNull(staleMovies); - - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Stale Movies found: {StaleMovies}", staleMovies.Count); - - if (staleMovies.Count > 0 && Configuration.DebugMode) - { - foreach (var movieInfo in staleMovies) - { - _logger.LogInformation("Movie Info: ID: {Id} | Movie Name: {MovieName}", [movieInfo.Id, movieInfo.Name]); - } - } - } - - public void PrintStaleEpisodesInformation(Func, List> findSeriesInfoFromEpisodes, IReadOnlyCollection staleEpisodes) - { - ArgumentNullException.ThrowIfNull(staleEpisodes); - ArgumentNullException.ThrowIfNull(findSeriesInfoFromEpisodes); - - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Stale Episodes found: {StaleEpisodes}", staleEpisodes.Count); - - if (staleEpisodes.Count > 0 && Configuration.DebugMode) - { - if (findSeriesInfoFromEpisodes == null) - { - throw new ArgumentNullException(nameof(findSeriesInfoFromEpisodes), "The method to find series information cannot be null."); - } - - List seriesInfoList = findSeriesInfoFromEpisodes(staleEpisodes); - - foreach (var seriesInfo in seriesInfoList) - { - _logger.LogInformation("Series Info: ID: {Id} | Series Name: {SeriesName} | Stale Seasons: {Seasons}", [seriesInfo.Id, seriesInfo.SeriesName, string.Join(", ", seriesInfo.Seasons)]); - } - } - - _logger.LogInformation("-------------------------------------------------"); - } - - public void PrintDebugDataForSeries(BaseItem item) - { - ArgumentNullException.ThrowIfNull(item); - - if (Configuration.DebugMode) - { - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Debug data for series: {SeriesName}", item.Name); - _logger.LogInformation("-------------------------------------------------"); - } - } - - public void PrintDebugSeasonInfo() - { - if (Configuration.DebugMode) - { - _logger.LogInformation("Season debug information:"); - } - } - - public void PrintDebugEpisodesWithUserData(IReadOnlyCollection episodesWithUserData) - { - if(Configuration.DebugMode){ - _logger.LogInformation("Episodes with user data: {EpisodesWithUserData}", episodesWithUserData); - _logger.LogInformation("-------------------------------------------------"); - } - } - - public void PrintDebugEpisodeCreationInfo(IReadOnlyCollection episodes) - { - ArgumentNullException.ThrowIfNull(episodes); - - if(Configuration.DebugMode){ - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Episode creation dates:"); - _logger.LogInformation("-------------------------------------------------"); - foreach(BaseItem episode in episodes) - { - _logger.LogInformation("Episode: {EpisodeName} | Date Created: {EpisodeDateCreated}", [episode.Name, episode.DateCreated]); - } - _logger.LogInformation("-------------------------------------------------"); - } - } } diff --git a/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs b/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs index 3793ad1..ec0eb8a 100644 --- a/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs +++ b/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs @@ -8,26 +8,18 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Plugin.MediaCleaner.Helpers; -public class MovieHelper +public class MovieHelper(ILogger logger) { - private readonly ILogger _logger; - - public MovieHelper(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - } + private readonly LoggingHelper _loggingHelper = new(logger); private static PluginConfiguration Configuration => Plugin.Instance!.Configuration; public bool IsMovieStale(BaseItem movie) { - if (Configuration.DebugMode) - { - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("Start of scanning for movie: {Movie}", movie); - _logger.LogInformation("-------------------------------------------------"); - } + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Start of scanning for movie: {Movie}", movie); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); bool movieIsStale = false; @@ -38,40 +30,30 @@ public class MovieHelper { var mostRecentUserData = movie.UserData.OrderByDescending(data => data.LastPlayedDate).First(data => data.LastPlayedDate != null); - if (Configuration.DebugMode){ - _logger.LogInformation("Most recent user data: {Movie}", movie); + _loggingHelper.LogDebugInformation("Most recent user data: {Movie}", movie); - foreach (var property in typeof(UserData).GetProperties()) - { - _logger.LogInformation("{PropertyName}: {PropertyValue}", property.Name, property.GetValue(mostRecentUserData)); - } - _logger.LogInformation("-------------------------------------------------"); + foreach (var property in typeof(UserData).GetProperties()) + { + _loggingHelper.LogDebugInformation("{PropertyName}: {PropertyValue}", property.Name, property.GetValue(mostRecentUserData)); } + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + if (mostRecentUserData.LastPlayedDate < DateTime.Now.AddDays(-Configuration.StaleMediaCutoff)) { - if (Configuration.DebugMode) - { - _logger.LogInformation("Most recent user data last played date is outside of cutoff. Adding {Movie} to stale movies.", movie); - } + _loggingHelper.LogDebugInformation("Most recent user data last played date is outside of cutoff. Adding {Movie} to stale movies.", movie); movieIsStale = true; } } else if (createdOutsideCutoff) { - if (Configuration.DebugMode) - { - _logger.LogInformation("Movie has no user data and was created outside of cutoff: {DateCreated}. Adding {Movie} to stale movies.", [movie.DateCreated, movie]); - } + _loggingHelper.LogDebugInformation("Movie has no user data and was created outside of cutoff: {DateCreated}. Adding {Movie} to stale movies.", [movie.DateCreated, movie]); movieIsStale = true; } - if (Configuration.DebugMode) - { - _logger.LogInformation("-------------------------------------------------"); - _logger.LogInformation("End of scanning for movie: {Movie}", movie); - _logger.LogInformation("-------------------------------------------------"); - } + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("End of scanning for movie: {Movie}", movie); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); return movieIsStale; } diff --git a/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs b/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs index f53630b..0090af0 100644 --- a/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs +++ b/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs @@ -11,71 +11,76 @@ using Microsoft.Extensions.Logging; namespace Jellyfin.Plugin.MediaCleaner.Helpers; -public class SeriesHelper +public class SeriesHelper(ILogger logger) { - private readonly ILogger _logger; - private readonly LoggingHelper _loggingHelper; - - public SeriesHelper(ILogger logger) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _loggingHelper = new LoggingHelper(logger); - } + private readonly LoggingHelper _loggingHelper = new(logger); private static PluginConfiguration Configuration => Plugin.Instance!.Configuration; - public bool IsSeasonUserDataStale(IReadOnlyList episodes) + private List ProcessEpisodes(IReadOnlyCollection episodes) { - bool seasonIsStale = false; - - List staleEpisodes = []; - - var episodesWithUserData = episodes.Where(episode => episode.UserData.Where(data => data.LastPlayedDate != null).ToList().Count > 0).ToList(); - - _loggingHelper.PrintDebugEpisodesWithUserData(episodesWithUserData); - - foreach (var episode in episodesWithUserData) + List staleEpisodes = [.. episodes + .Where(episode => { bool episodeIsStale = false; - var mostRecentUserData = episode.UserData.OrderByDescending(data => data.LastPlayedDate).First(data => data.LastPlayedDate != null); - var staleLastPlayedDate = mostRecentUserData.LastPlayedDate < DateTime.Now.AddDays(-Configuration.StaleMediaCutoff); var staleCreationDate = episode.DateCreated < DateTime.Now.AddDays(-Configuration.StaleMediaCutoff); + var hasUserDataWithLastPlayedDate = episode.UserData.Any(data => data.LastPlayedDate != null); + + if (staleCreationDate && !hasUserDataWithLastPlayedDate){ + _loggingHelper.LogInformation("Creation date is stale, and no user data for episode {Episode}.", episode); + episodeIsStale = true; + } + + if (hasUserDataWithLastPlayedDate){ + UserData mostRecentUserData = episode.UserData + .OrderByDescending(data => data.LastPlayedDate) + .First(); + + _loggingHelper.LogDebugInformation("User data for episode: {Episode}", episode); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); - if(Configuration.DebugMode){ - _logger.LogInformation("User data for episode: {Episode}", episode); - _logger.LogInformation("-------------------------------------------------"); foreach (var property in typeof(UserData).GetProperties()) { - _logger.LogInformation("{PropertyName}: {PropertyValue}", property.Name, property.GetValue(mostRecentUserData)); + _loggingHelper.LogDebugInformation("{PropertyName}: {PropertyValue}", property.Name, property.GetValue(mostRecentUserData)); } - _logger.LogInformation("-------------------------------------------------"); - } - if (staleLastPlayedDate && staleCreationDate) - { - episodeIsStale = true; - if(Configuration.DebugMode){ - _logger.LogInformation("Most recent user data has a last played date of: {LastPlayedDate}.", [mostRecentUserData.LastPlayedDate]); - _logger.LogInformation("And episode created {DateCreated}.", episode.DateCreated); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + + bool staleLastPlayedDate = mostRecentUserData.LastPlayedDate < DateTime.Now.AddDays(-Configuration.StaleMediaCutoff); + + if (staleLastPlayedDate && staleCreationDate) + { + episodeIsStale = true; + _loggingHelper.LogDebugInformation("Most recent user data has a last played date of: {LastPlayedDate}.", [mostRecentUserData.LastPlayedDate]); + _loggingHelper.LogDebugInformation("And episode created {DateCreated}.", episode.DateCreated); + _loggingHelper.LogDebugInformation("Episode is marked as stale."); } } - if (episodeIsStale) - { - staleEpisodes.Add(episode); - if(Configuration.DebugMode){ - _logger.LogInformation("Episode is stale."); - } - } + return episodeIsStale; + })]; + + return staleEpisodes; + } + + public bool IsSeasonDataStale(IReadOnlyList episodes) + { + if(episodes == null) + { + ArgumentNullException.ThrowIfNull(episodes); } + bool seasonIsStale = false; + + List staleEpisodes = ProcessEpisodes(episodes); + if(staleEpisodes.Count == episodes.Count) { seasonIsStale = true; - _logger.LogInformation("Stale episodes count matches all episode count. Season is stale."); - _logger.LogInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Stale episodes count matches season episode count. Season is stale."); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); } return seasonIsStale; diff --git a/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs b/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs index 1c232a3..2abb905 100644 --- a/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs +++ b/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs @@ -60,7 +60,10 @@ public sealed class StaleMediaTask : IScheduledTask Task IScheduledTask.ExecuteAsync(IProgress progress, CancellationToken cancellationToken) { - _loggingHelper.StartLogging(); + _loggingHelper.LogDebugInformation("--DEBUG MODE ACTIVE--"); + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Starting stale media scan..."); + _loggingHelper.LogInformation("-------------------------------------------------"); var query = new InternalItemsQuery { @@ -70,21 +73,51 @@ public sealed class StaleMediaTask : IScheduledTask List allItems = [.. _libraryManager.GetItemsResult(query).Items]; - _loggingHelper.PrintItemsInformation(allItems); + _loggingHelper.LogInformation("Total items: {ItemCount}", allItems.Count); + _loggingHelper.LogInformation("Stale items found: {AllItems}", allItems); List series = [.. allItems.Where(item => item.GetBaseItemKind() == BaseItemKind.Series)]; List movies = [.. allItems.Where(item => item.GetBaseItemKind() == BaseItemKind.Movie)]; - _loggingHelper.StartScanningSeriesItems(); + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Starting scan of series items."); + _loggingHelper.LogInformation("-------------------------------------------------"); + List staleEpisodes = [.. series.SelectMany(GetStaleEpisodes)]; - _loggingHelper.StartScanningMoviesItems(); + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Starting scan of movies items."); + _loggingHelper.LogInformation("-------------------------------------------------"); + List staleMovies = [.. GetStaleMovies(movies)]; - _loggingHelper.PrintStaleMoviesInformation(staleMovies); - _loggingHelper.PrintStaleEpisodesInformation(FindSeriesInfoFromEpisodes, staleEpisodes); + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Stale Movies found: {StaleMovies}", staleMovies.Count); - _loggingHelper.EndLogging(); + if (staleMovies.Count > 0 && Configuration.DebugMode) + { + foreach (var movieInfo in staleMovies) + { + _loggingHelper.LogDebugInformation("Movie Info: ID: {Id} | Movie Name: {MovieName}", [movieInfo.Id, movieInfo.Name]); + } + } + + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Stale Episodes found: {StaleEpisodes}", staleEpisodes.Count); + + if (staleEpisodes.Count > 0 && Configuration.DebugMode) + { + List seriesInfoList = FindSeriesInfoFromEpisodes(staleEpisodes); + + foreach (var seriesInfo in seriesInfoList) + { + _loggingHelper.LogDebugInformation("Series Info: ID: {Id} | Series Name: {SeriesName} | Stale Seasons: {Seasons}", [seriesInfo.Id, seriesInfo.SeriesName, string.Join(", ", seriesInfo.Seasons)]); + } + } + + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Ending stale media scan..."); + _loggingHelper.LogInformation("-------------------------------------------------"); return Task.CompletedTask; } @@ -101,7 +134,9 @@ public sealed class StaleMediaTask : IScheduledTask private List GetStaleEpisodes(BaseItem item) { - List staleEpisodes = []; + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Debug data for series: {SeriesName}", item.Name); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); // Gets each season in a show var seasons = _libraryManager.GetItemList(new InternalItemsQuery @@ -110,34 +145,21 @@ public sealed class StaleMediaTask : IScheduledTask Recursive = false }); - _loggingHelper.PrintDebugDataForSeries(item); - - foreach (var season in seasons) - { - // Gets each episode, to access user data. + List staleEpisodes = [ ..seasons + .Where(season => { var episodes = _libraryManager.GetItemList(new InternalItemsQuery { ParentId = season.Id, Recursive = false }); - _loggingHelper.PrintDebugSeasonInfo(); + _loggingHelper.LogDebugInformation("Season debug information for {SeasonNumber}:", season); - bool seasonHasUserData = episodes.Any(episode => episode.UserData.Count > 0); - bool seasonIsStale = seasonHasUserData && _seriesHelper.IsSeasonUserDataStale(episodes); + return _seriesHelper.IsSeasonDataStale(episodes); + })]; - if (seasonIsStale) - { - if (!seasonHasUserData) - { - _loggingHelper.PrintDebugEpisodeCreationInfo(episodes); - } - - staleEpisodes.AddRange(episodes); - } - } - - _loggingHelper.PrintDebugEndOfScanningForSeries(item); + _loggingHelper.LogDebugInformation("End of scanning for series: {Series}", item); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); return staleEpisodes; }