diff --git a/Directory.Build.props b/Directory.Build.props index 12d33c7..6dc1a56 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 0.0.0.9 + 0.0.0.11 diff --git a/Jellyfin.Plugin.MediaCleaner/Controllers/StateController.cs b/Jellyfin.Plugin.MediaCleaner/Controllers/StateController.cs index c66c6be..5e3833b 100644 --- a/Jellyfin.Plugin.MediaCleaner/Controllers/StateController.cs +++ b/Jellyfin.Plugin.MediaCleaner/Controllers/StateController.cs @@ -1,22 +1,32 @@ using Jellyfin.Plugin.MediaCleaner.Data; +using Jellyfin.Plugin.MediaCleaner; using Jellyfin.Plugin.MediaCleaner.Models; using Microsoft.AspNetCore.Mvc; +using Jellyfin.Plugin.MediaCleaner.Configuration; namespace Jellyfin.Plugin.MediaCleaner.Controllers; [Route("mediacleaner/state")] -public class StateController : Controller +public class StateController(MediaCleanerState state) : Controller { - private readonly PluginState _state; - public StateController(PluginState state) => _state = state; + private readonly MediaCleanerState _state = state; + private static PluginConfiguration Configuration => + Plugin.Instance!.Configuration; - [HttpGet] - public IActionResult Get() => Ok(_state.GetSeriesInfo()); + [HttpGet("getSeriesInfo")] + public IActionResult GetSeriesInfo() => Ok(_state.GetSeriesInfo()); - [HttpPost("add")] - public IActionResult AddSeriesInfo([FromBody] SeriesInfo seriesInfo) - { - _state.AddSeriesInfo(seriesInfo); - return Ok(); - } + [HttpGet("getMovieInfo")] + public IActionResult GetMovieInfo() => Ok(_state.GetMovieInfo()); + + [HttpGet("updateState")] + public IActionResult GetUpdateState() => Ok(_state.UpdateState()); + + [HttpGet("getMoviesTitle")] + public IActionResult GetMoviesTitle() => + Ok($"Stale Movies (Unwatched for and created over {Configuration.StaleMediaCutoff} Days ago.)"); + + [HttpGet("getSeriesTitle")] + public IActionResult GetSeriesTitle() => + Ok($"Stale Series (Unwatched for and created over {Configuration.StaleMediaCutoff} Days ago.)"); } diff --git a/Jellyfin.Plugin.MediaCleaner/Data/MediaCleanerState.cs b/Jellyfin.Plugin.MediaCleaner/Data/MediaCleanerState.cs new file mode 100644 index 0000000..4c168df --- /dev/null +++ b/Jellyfin.Plugin.MediaCleaner/Data/MediaCleanerState.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Jellyfin.Database.Implementations.ModelConfiguration; +using Jellyfin.Plugin.MediaCleaner; +using Jellyfin.Plugin.MediaCleaner.Models; +using Jellyfin.Plugin.MediaCleaner.ScheduledTasks; +using MediaBrowser.Controller.Library; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Plugin.MediaCleaner.Data; + +public class MediaCleanerState(ILogger logger, ILibraryManager libraryManager) +{ + private readonly Lock _lock = new(); + private IEnumerable _mediaInfo = []; + private readonly StaleMediaScanner _staleMediaScanner = new(logger, libraryManager); + + public async Task UpdateState() + { + _mediaInfo = await _staleMediaScanner.ScanStaleMedia().ConfigureAwait(false); + } + + public IEnumerable GetSeriesInfo() + { + lock (_lock) + { + return _mediaInfo.OfType(); + } + } + + public IEnumerable GetMovieInfo() + { + lock (_lock) + { + return _mediaInfo.OfType(); + } + } +} diff --git a/Jellyfin.Plugin.MediaCleaner/Data/PluginState.cs b/Jellyfin.Plugin.MediaCleaner/Data/PluginState.cs deleted file mode 100644 index 53f038f..0000000 --- a/Jellyfin.Plugin.MediaCleaner/Data/PluginState.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Collections.Generic; -using Jellyfin.Plugin.MediaCleaner.Models; - -namespace Jellyfin.Plugin.MediaCleaner.Data; - -public class PluginState -{ - private readonly object _lock = new(); - private List _seriesInfo = new List - { - new SeriesInfo { SeriesName = "TestName", Id = System.Guid.NewGuid() } - }; - - public void AddSeriesInfo(SeriesInfo seriesInfo) - { - lock (_lock) - { - _seriesInfo.Add(seriesInfo); - } - } - - public IEnumerable GetSeriesInfo() - { - lock (_lock) - { - return _seriesInfo; - } - } -} diff --git a/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs b/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs index 429ed1c..86a9c06 100644 --- a/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs +++ b/Jellyfin.Plugin.MediaCleaner/Helpers/MovieHelper.cs @@ -17,7 +17,10 @@ public class MovieHelper(ILogger logger) public bool IsMovieStale(BaseItem movie) { - _loggingHelper.LogDebugInformation("Start of scanning for movie: {Movie}", movie); + ArgumentNullException.ThrowIfNull(movie, "IsMovieStale process recieved a null movie. Logic failure. Exception thrown."); + + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Scanning movie: {Movie}", movie); _loggingHelper.LogDebugInformation("-------------------------------------------------"); bool movieIsStale = false; @@ -47,13 +50,20 @@ public class MovieHelper(ILogger logger) movieIsStale = true; } } - else if (createdOutsideCutoff) + + if (createdOutsideCutoff && !hasUserData) { _loggingHelper.LogDebugInformation("Movie has no user data and was created outside of cutoff: {DateCreated}.", movie.DateCreated); _loggingHelper.LogDebugInformation("Adding {Movie} to stale movies.", movie); movieIsStale = true; } + if (!createdOutsideCutoff && !hasUserData) + { + _loggingHelper.LogDebugInformation("Movie has no user data and was not created outside of cutoff: {DateCreated}.", movie.DateCreated); + _loggingHelper.LogDebugInformation("Movie is not stale."); + } + _loggingHelper.LogDebugInformation("-------------------------------------------------"); _loggingHelper.LogDebugInformation("End of scanning for movie: {Movie}", movie); diff --git a/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs b/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs index 51d2950..cbd8c3d 100644 --- a/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs +++ b/Jellyfin.Plugin.MediaCleaner/Helpers/SeriesHelper.cs @@ -69,10 +69,7 @@ public class SeriesHelper(ILogger logger) public bool IsSeasonDataStale(IReadOnlyList episodes) { - if(episodes == null) - { - ArgumentNullException.ThrowIfNull(episodes); - } + ArgumentNullException.ThrowIfNull(episodes, "IsSeasonDataStale process recieved null episodes. Logic failure. Exception thrown."); bool seasonIsStale = false; diff --git a/Jellyfin.Plugin.MediaCleaner/Models/MediaInfo.cs b/Jellyfin.Plugin.MediaCleaner/Models/MediaInfo.cs new file mode 100644 index 0000000..7ae7881 --- /dev/null +++ b/Jellyfin.Plugin.MediaCleaner/Models/MediaInfo.cs @@ -0,0 +1,9 @@ +using System; + +namespace Jellyfin.Plugin.MediaCleaner.Models; + +public abstract class MediaInfo +{ + public required Guid Id { get; set; } + public required string Name { get; set; } +} diff --git a/Jellyfin.Plugin.MediaCleaner/Models/MovieInfo.cs b/Jellyfin.Plugin.MediaCleaner/Models/MovieInfo.cs new file mode 100644 index 0000000..c70717f --- /dev/null +++ b/Jellyfin.Plugin.MediaCleaner/Models/MovieInfo.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Jellyfin.Plugin.MediaCleaner; + +namespace Jellyfin.Plugin.MediaCleaner.Models; + +/// +/// Contains Movie information. +/// +public class MovieInfo : MediaInfo +{ + +} diff --git a/Jellyfin.Plugin.MediaCleaner/Models/SeriesInfo.cs b/Jellyfin.Plugin.MediaCleaner/Models/SeriesInfo.cs index 59ff805..1a49baa 100644 --- a/Jellyfin.Plugin.MediaCleaner/Models/SeriesInfo.cs +++ b/Jellyfin.Plugin.MediaCleaner/Models/SeriesInfo.cs @@ -1,26 +1,14 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using Jellyfin.Plugin.MediaCleaner; namespace Jellyfin.Plugin.MediaCleaner.Models; /// /// Contains series information. /// -public class SeriesInfo +public class SeriesInfo : MediaInfo { - /// - /// Gets or sets series identifier. - /// - public Guid Id { get; set; } - - /// - /// Gets or sets series name. - /// - public string SeriesName { get; set; } = string.Empty; - - /// - /// Gets or sets seasons. - /// public IEnumerable Seasons { get; set; } = []; } diff --git a/Jellyfin.Plugin.MediaCleaner/Pages/home.css b/Jellyfin.Plugin.MediaCleaner/Pages/home.css new file mode 100644 index 0000000..9409dd8 --- /dev/null +++ b/Jellyfin.Plugin.MediaCleaner/Pages/home.css @@ -0,0 +1,27 @@ +table { + border: 1px solid; + border-collapse: collapse; +} + +td, th { + border: 1px solid; + padding: 0.5rem 0.75rem; + text-align: left; +} + +.links { + background-color: #0f0f0f; + border: 1px solid; + padding: 0.8rem 1.8rem; + font-size: 1.2rem; + color: #ffffff; + text-decoration: none; + cursor: pointer; + line-height: inherit; + vertical-align: baseline; + transition: background-color 0.3s ease; +} + +.links:hover { + background-color: #2a2a2a; +} diff --git a/Jellyfin.Plugin.MediaCleaner/Pages/home.html b/Jellyfin.Plugin.MediaCleaner/Pages/home.html index e5971e0..d4abb88 100644 --- a/Jellyfin.Plugin.MediaCleaner/Pages/home.html +++ b/Jellyfin.Plugin.MediaCleaner/Pages/home.html @@ -1,21 +1,36 @@ -
+
-
- Home - Settings +
Loading...
+ -

Media Cleaner

- - - - - - - - -
IDSeries Name
diff --git a/Jellyfin.Plugin.MediaCleaner/Pages/home.js b/Jellyfin.Plugin.MediaCleaner/Pages/home.js new file mode 100644 index 0000000..ea248fd --- /dev/null +++ b/Jellyfin.Plugin.MediaCleaner/Pages/home.js @@ -0,0 +1,151 @@ +document.addEventListener('pageshow', async () => { + await fetchHomepageCSS(); + await updateMediaCleanerState(); + + var moviesTitle = document.getElementById("moviesTitle"); + var seriesTitle = document.getElementById("seriesTitle"); + + moviesTitle.innerHTML = await getMediaCleanerMoviesTitle(); + seriesTitle.innerHTML = await getMediaCleanerSeriesTitle(); + + await populateTables(); + addClickHandlersToLinks(); + finishLoading(); +}); + +const getMediaCleanerSeriesInfo = async () => { + const response = await fetch("/mediacleaner/state/getSeriesInfo"); + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`) + } + + return response.json(); +}; + +const getMediaCleanerMovieInfo = async () => { + const response = await fetch("/mediacleaner/state/getMovieInfo"); + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`) + } + + return response.json(); +}; + +const updateMediaCleanerState = async () => { + const response = await fetch("/mediacleaner/state/updateState"); + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`) + } + + return response.json(); +}; + +const getMediaCleanerSeriesTitle = async () => { + const response = await fetch("/mediacleaner/state/getSeriesTitle"); + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`); + } + + return response.json(); +}; + +const getMediaCleanerMoviesTitle = async () => { + const response = await fetch("/mediacleaner/state/getMoviesTitle"); + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`); + } + + return response.json(); +}; + +const populateTables = async () => { + var moviesInfo = await getMediaCleanerMovieInfo(); + var seriesInfo = await getMediaCleanerSeriesInfo(); + + var seriesTableBody = seriesTable.getElementsByTagName('tbody')[0]; + seriesTableBody.replaceChildren(); + + var moviesTableBody = moviesTable.getElementsByTagName('tbody')[0]; + moviesTableBody.replaceChildren(); + + if (moviesInfo.length > 0){ + for(let i = 0; i < moviesInfo.length; i++){ + var row = moviesTableBody.insertRow(-1); + var cell1 = row.insertCell(0); + var cell2 = row.insertCell(1); + cell1.innerHTML = moviesInfo[i].Name; + // Will need to be enabled once radarr and sonarr integration is enabled. + // Maybe change this to an element to remove hard coding. + cell2.innerHTML = ""; + } + } + else{ + var columnCount = moviesTable.tHead.rows[0].cells.length; + var row = moviesTableBody.insertRow(-1); + var cell1 = row.insertCell(0); + cell1.colSpan = columnCount; + cell1.innerHTML = "No stale movies found."; + } + + if(seriesInfo.length > 0){ + for(let i = 0; i < seriesInfo.length; i++){ + var row = seriesTableBody.insertRow(-1); + var cell1 = row.insertCell(0); + var cell2 = row.insertCell(1); + var cell3 = row.insertCell(2); + cell1.innerHTML = seriesInfo[i].Name; + cell2.innerHTML = seriesInfo[i].Seasons.map(season => season.replace("Season ", "")).join(", "); + // Will need to be enabled once radarr and sonarr integration is enabled. + // Maybe change this to an element to remove hard coding. + cell3.innerHTML = ""; + cell3.className = "actions-cell"; + } + } + else{ + var columnCount = seriesTable.tHead.rows[0].cells.length; + var row = seriesTableBody.insertRow(-1); + var cell1 = row.insertCell(0); + cell1.colSpan = columnCount; + cell1.innerHTML = "No stale series found."; + } +}; + +const addClickHandlersToLinks = () => { + const linkbtns = document.querySelectorAll("button.links") + linkbtns.forEach(btn => { + btn.addEventListener("click", () => { + const target = btn.dataset.target; + if (!target) return; + window.location.hash = target; + }) + }) +} + +const finishLoading = () => { + const loadingElement = document.getElementById("loading"); + + const homepage = document.getElementById("homepage"); + loadingElement.style.visibility = "hidden"; + homepage.style.visibility = "visible"; + + console.log("Loading element: ", loadingElement); + console.log("Homepage element: ", homepage); +} + +const fetchHomepageCSS = async () => { + const response = await fetch('/web/configurationpage?name=home.css') + + if(!response.ok){ + throw new Error(`Response status: ${response.status}`); + } + + const css = await response.text(); + const styles = document.createElement('style'); + styles.textContent = css; + document.head.appendChild(styles); +} diff --git a/Jellyfin.Plugin.MediaCleaner/Pages/media_cleaner_table.js b/Jellyfin.Plugin.MediaCleaner/Pages/media_cleaner_table.js deleted file mode 100644 index a56f7ba..0000000 --- a/Jellyfin.Plugin.MediaCleaner/Pages/media_cleaner_table.js +++ /dev/null @@ -1,27 +0,0 @@ -var table = document.getElementById("seriesTable"); - - - -const getMediaCleanerState = async () => { - const response = await fetch('/mediacleaner/state'); - - if(!response.ok){ - throw new Error(`Response status: ${response.status}`) - } - - return response.json(); -} - -var state = await getMediaCleanerState(); - -console.log("State: ", state); - -for(let i = 0; i < state.length; i++){ - var row = table.insertRow(-1); - var cell1 = row.insertCell(0); - var cell2 = row.insertCell(1); - var cell3 = row.insertCell(2); - cell1.innerHTML = state[i].Id; - cell2.innerHTML = state[i].SeriesName; - cell3.innerHTML = state[i].Seasons.length; -} diff --git a/Jellyfin.Plugin.MediaCleaner/Plugin.cs b/Jellyfin.Plugin.MediaCleaner/Plugin.cs index 5e4271d..0c29674 100644 --- a/Jellyfin.Plugin.MediaCleaner/Plugin.cs +++ b/Jellyfin.Plugin.MediaCleaner/Plugin.cs @@ -57,8 +57,13 @@ public class Plugin : BasePlugin, IHasWebPages }, new PluginPageInfo { - Name = "media_cleaner_table.js", - EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Pages.media_cleaner_table.js", GetType().Namespace), + Name = "home.js", + EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Pages.home.js", GetType().Namespace), + }, + new PluginPageInfo + { + Name = "home.css", + EmbeddedResourcePath = string.Format(CultureInfo.InvariantCulture, "{0}.Pages.home.css", GetType().Namespace), } ]; } diff --git a/Jellyfin.Plugin.MediaCleaner/PluginServiceRegistrator.cs b/Jellyfin.Plugin.MediaCleaner/PluginServiceRegistrator.cs index e5b2db9..079f689 100644 --- a/Jellyfin.Plugin.MediaCleaner/PluginServiceRegistrator.cs +++ b/Jellyfin.Plugin.MediaCleaner/PluginServiceRegistrator.cs @@ -8,6 +8,6 @@ public class PluginServiceRegistrator : IPluginServiceRegistrator { public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost) { - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); } } diff --git a/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs b/Jellyfin.Plugin.MediaCleaner/StaleMediaScanner.cs similarity index 62% rename from Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs rename to Jellyfin.Plugin.MediaCleaner/StaleMediaScanner.cs index 7c9f3d1..fde16f9 100644 --- a/Jellyfin.Plugin.MediaCleaner/ScheduledTasks/StaleMediaTask.cs +++ b/Jellyfin.Plugin.MediaCleaner/StaleMediaScanner.cs @@ -14,18 +14,20 @@ using Jellyfin.Database.Implementations.Entities; using Jellyfin.Database.Implementations.Entities.Libraries; using Jellyfin.Plugin.MediaCleaner.Configuration; using Jellyfin.Plugin.MediaCleaner.Helpers; +using Jellyfin.Plugin.MediaCleaner; using Jellyfin.Plugin.MediaCleaner.Models; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Tasks; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; -namespace Jellyfin.Plugin.MediaCleaner.ScheduledTasks; +namespace Jellyfin.Plugin.MediaCleaner; /// /// A task to scan media for stale files. /// -public sealed class StaleMediaTask : IScheduledTask +public sealed class StaleMediaScanner { private readonly ILogger _logger; private readonly ILibraryManager _libraryManager; @@ -38,7 +40,7 @@ public sealed class StaleMediaTask : IScheduledTask /// /// Logger for StaleMediaTask. /// Accesses jellyfin's library manager for media. - public StaleMediaTask(ILogger logger, ILibraryManager libraryManager) + public StaleMediaScanner(ILogger logger, ILibraryManager libraryManager) { _logger = logger; _libraryManager = libraryManager; @@ -47,18 +49,7 @@ public sealed class StaleMediaTask : IScheduledTask _seriesHelper = new SeriesHelper(_logger); } - private static PluginConfiguration Configuration => - Plugin.Instance!.Configuration; - - string IScheduledTask.Name => "Scan Stale Media"; - - string IScheduledTask.Key => "Stale Media"; - - string IScheduledTask.Description => "Scan Stale Media"; - - string IScheduledTask.Category => "Media"; - - Task IScheduledTask.ExecuteAsync(IProgress progress, CancellationToken cancellationToken) + public async Task> ScanStaleMedia() { _loggingHelper.LogDebugInformation("--DEBUG MODE ACTIVE--"); _loggingHelper.LogInformation("-------------------------------------------------"); @@ -73,59 +64,92 @@ public sealed class StaleMediaTask : IScheduledTask List allItems = [.. _libraryManager.GetItemsResult(query).Items]; - _loggingHelper.LogInformation("Total items: {ItemCount}", allItems.Count); - _loggingHelper.LogInformation("Stale items found: {AllItems}", allItems); + _loggingHelper.LogInformation("Total items to scan: {ItemCount}", allItems.Count); + _loggingHelper.LogDebugInformation("Items found: {AllItems}", allItems); List series = [.. allItems.Where(item => item.GetBaseItemKind() == BaseItemKind.Series)]; List movies = [.. allItems.Where(item => item.GetBaseItemKind() == BaseItemKind.Movie)]; - _loggingHelper.LogInformation("-------------------------------------------------"); - _loggingHelper.LogInformation("Starting scan of series items."); - _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Starting scan of series items."); List staleSeasons = [.. series.SelectMany(GetStaleSeasons)]; - _loggingHelper.LogInformation("Starting scan of movies items."); - _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("End of scan for series items."); + + _loggingHelper.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("Starting scan of movie items."); List staleMovies = [.. GetStaleMovies(movies)]; - _loggingHelper.LogInformation("-------------------------------------------------"); - _loggingHelper.LogInformation("Stale Movies found: {StaleMovies}", staleMovies.Count); - - 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.LogDebugInformation("-------------------------------------------------"); + _loggingHelper.LogDebugInformation("End of scan for movie items."); _loggingHelper.LogInformation("-------------------------------------------------"); _loggingHelper.LogInformation("Stale seasons found: {StaleSeasons}", staleSeasons.Count); - if (staleSeasons.Count > 0 && Configuration.DebugMode) - { - IEnumerable staleSeriesInfo = FindSeriesInfo(staleSeasons); + IEnumerable staleSeriesInfo = []; - foreach (var seriesInfo in staleSeriesInfo) + if (staleSeasons.Count > 0) + { + staleSeriesInfo = FindSeriesInfo(staleSeasons); + + foreach (SeriesInfo seriesInfo in staleSeriesInfo.Cast()) { - _loggingHelper.LogDebugInformation("Series Info: ID: {Id} | Series Name: {SeriesName} | Stale Seasons: {Seasons}", [seriesInfo.Id, seriesInfo.SeriesName, string.Join(", ", seriesInfo.Seasons)]); + _loggingHelper.LogInformation("Series Info: ID: {Id} | Series Name: {SeriesName} | Stale Seasons: {Seasons}", [seriesInfo.Id, seriesInfo.Name, string.Join(", ", seriesInfo.Seasons)]); } } + else + { + _loggingHelper.LogInformation("No stale seasons found!"); + } + + _loggingHelper.LogInformation("-------------------------------------------------"); + _loggingHelper.LogInformation("Stale Movies found: {StaleMovies}", staleMovies.Count); + + IEnumerable staleMoviesInfo = []; + + if (staleMovies.Count > 0) + { + staleMoviesInfo = staleMovies.Select(movie => new MovieInfo + { + Id = movie.Id, + Name = movie.Name + }); + + foreach (MovieInfo movieInfo in staleMoviesInfo.Cast()) + { + _loggingHelper.LogInformation("Movie Info: ID: {Id} | Movie Name: {MovieName}", [movieInfo.Id, movieInfo.Name]); + } + } + else + { + _loggingHelper.LogInformation("No stale movies found!"); + } _loggingHelper.LogInformation("-------------------------------------------------"); _loggingHelper.LogInformation("Ending stale media scan..."); _loggingHelper.LogInformation("-------------------------------------------------"); - return Task.CompletedTask; + IEnumerable mediaInfo = staleSeriesInfo.Concat(staleMoviesInfo); + + return mediaInfo; } private List GetStaleMovies(List movies) { List staleMovies = []; - staleMovies.AddRange(movies.Where(_movieHelper.IsMovieStale)); + try + { + staleMovies.AddRange(movies.Where(_movieHelper.IsMovieStale)); + } + catch (ArgumentNullException ex) + { + _loggingHelper.LogInformation("Arguement Null Exception in GetStaleMovies!"); + _loggingHelper.LogInformation(ex.Message); + } return staleMovies; } @@ -133,10 +157,10 @@ public sealed class StaleMediaTask : IScheduledTask private List GetStaleSeasons(BaseItem item) { + _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 { ParentId = item.Id, @@ -153,7 +177,17 @@ public sealed class StaleMediaTask : IScheduledTask _loggingHelper.LogDebugInformation("Season debug information for {SeasonNumber}:", season); - bool isSeasonDataStale = _seriesHelper.IsSeasonDataStale(episodes); + bool isSeasonDataStale = false; + + try + { + isSeasonDataStale = _seriesHelper.IsSeasonDataStale(episodes); + } + catch (ArgumentNullException ex) + { + _loggingHelper.LogInformation("Arguement Null Exception in GetStaleSeasons!"); + _loggingHelper.LogInformation(ex.Message); + } _loggingHelper.LogDebugInformation("End of season debug information for {SeasonNumber}.", season); @@ -163,12 +197,11 @@ public sealed class StaleMediaTask : IScheduledTask _loggingHelper.LogDebugInformation("-------------------------------------------------"); _loggingHelper.LogDebugInformation("End of scanning for series: {Series}", item); - _loggingHelper.LogDebugInformation("-------------------------------------------------"); return staleSeasons; } - private IEnumerable FindSeriesInfo(IReadOnlyCollection seasons) + private IEnumerable FindSeriesInfo(IReadOnlyCollection seasons) { Guid[] seriesIds = [.. seasons.Select(season => season.ParentId).Distinct()]; @@ -182,21 +215,11 @@ public sealed class StaleMediaTask : IScheduledTask return new SeriesInfo { Id = series.Id, - SeriesName = series.Name, + Name = series.Name, Seasons = [.. seasons.Where(season => season.ParentId == series.Id).Select(season => season.Name)] }; }); return seriesInfoList; } - - IEnumerable IScheduledTask.GetDefaultTriggers() - { - // Run this task every 24 hours - yield return new TaskTriggerInfo - { - Type = TaskTriggerInfoType.IntervalTrigger, - IntervalTicks = TimeSpan.FromHours(24).Ticks - }; - } }