Resolve all remaining FIXMEs with credit detection
This commit is contained in:
parent
4bb978639c
commit
1966357e29
@ -60,7 +60,7 @@ public class Entrypoint : IServerEntryPoint
|
||||
// Enqueue all episodes at startup to ensure any FFmpeg errors appear as early as possible
|
||||
_logger.LogInformation("Running startup enqueue");
|
||||
var queueManager = new QueueManager(_loggerFactory.CreateLogger<QueueManager>(), _libraryManager);
|
||||
queueManager.EnqueueAllEpisodes();
|
||||
queueManager.GetMediaItems();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -3,6 +3,7 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
@ -37,10 +38,10 @@ public class QueueManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Iterates through all libraries on the server and queues all episodes for analysis.
|
||||
/// Gets all media items on the server.
|
||||
/// </summary>
|
||||
/// <returns>Queued media items.</returns>
|
||||
public ReadOnlyDictionary<Guid, List<QueuedEpisode>> EnqueueAllEpisodes()
|
||||
public ReadOnlyDictionary<Guid, List<QueuedEpisode>> GetMediaItems()
|
||||
{
|
||||
// Assert that ffmpeg with chromaprint is installed
|
||||
if (!FFmpegWrapper.CheckFFmpegVersion())
|
||||
@ -220,4 +221,51 @@ public class QueueManager
|
||||
|
||||
Plugin.Instance!.TotalQueued++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that a collection of queued media items still exist in Jellyfin and in storage.
|
||||
/// This is done to ensure that we don't analyze items that were deleted between the call to GetMediaItems() and popping them from the queue.
|
||||
/// </summary>
|
||||
/// <param name="candidates">Queued media items.</param>
|
||||
/// <param name="mode">Analysis mode.</param>
|
||||
/// <returns>Media items that have been verified to exist in Jellyfin and in storage.</returns>
|
||||
public (ReadOnlyCollection<QueuedEpisode> VerifiedItems, bool AnyUnanalyzed)
|
||||
VerifyQueue(ReadOnlyCollection<QueuedEpisode> candidates, AnalysisMode mode)
|
||||
{
|
||||
var unanalyzed = false;
|
||||
var verified = new List<QueuedEpisode>();
|
||||
|
||||
var timestamps = mode == AnalysisMode.Introduction ?
|
||||
Plugin.Instance!.Intros :
|
||||
Plugin.Instance!.Credits;
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = Plugin.Instance!.GetItemPath(candidate.EpisodeId);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
verified.Add(candidate);
|
||||
}
|
||||
|
||||
if (!timestamps.ContainsKey(candidate.EpisodeId))
|
||||
{
|
||||
unanalyzed = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Skipping {Mode} analysis of {Name} ({Id}): {Exception}",
|
||||
mode,
|
||||
candidate.Name,
|
||||
candidate.EpisodeId,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
return (verified.AsReadOnly(), unanalyzed);
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,6 @@ using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
||||
|
||||
#if !DEBUG
|
||||
#error Fix all FIXMEs introduced during initial credit implementation before release
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Analyze all television episodes for credits.
|
||||
/// </summary>
|
||||
@ -84,7 +80,7 @@ public class DetectCreditsTask : IScheduledTask
|
||||
_loggerFactory.CreateLogger<QueueManager>(),
|
||||
_libraryManager);
|
||||
|
||||
var queue = queueManager.EnqueueAllEpisodes();
|
||||
var queue = queueManager.GetMediaItems();
|
||||
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
@ -101,9 +97,11 @@ public class DetectCreditsTask : IScheduledTask
|
||||
// Analyze all episodes in the queue using the degrees of parallelism the user specified.
|
||||
Parallel.ForEach(queue, options, (season) =>
|
||||
{
|
||||
// TODO: FIXME: use VerifyEpisodes
|
||||
var episodes = season.Value.AsReadOnly();
|
||||
if (episodes.Count == 0)
|
||||
var (episodes, unanalyzed) = queueManager.VerifyQueue(
|
||||
season.Value.AsReadOnly(),
|
||||
AnalysisMode.Credits);
|
||||
|
||||
if (episodes.Count == 0 || unanalyzed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class DetectIntroductionsTask : IScheduledTask
|
||||
_loggerFactory.CreateLogger<QueueManager>(),
|
||||
_libraryManager);
|
||||
|
||||
var queue = queueManager.EnqueueAllEpisodes();
|
||||
var queue = queueManager.GetMediaItems();
|
||||
|
||||
if (queue.Count == 0)
|
||||
{
|
||||
@ -100,13 +100,15 @@ public class DetectIntroductionsTask : IScheduledTask
|
||||
MaxDegreeOfParallelism = Plugin.Instance!.Configuration.MaxParallelism
|
||||
};
|
||||
|
||||
// TODO: if the queue is modified while the task is running, the task will fail.
|
||||
// clone the queue before running the task to prevent this.
|
||||
|
||||
// Analyze all episodes in the queue using the degrees of parallelism the user specified.
|
||||
Parallel.ForEach(queue, options, (season) =>
|
||||
{
|
||||
var (episodes, unanalyzed) = VerifyEpisodes(season.Value.AsReadOnly());
|
||||
// Since the first run of the task can run for multiple hours, ensure that none
|
||||
// of the current media items were deleted from Jellyfin since the task was started.
|
||||
var (episodes, unanalyzed) = queueManager.VerifyQueue(
|
||||
season.Value.AsReadOnly(),
|
||||
AnalysisMode.Introduction);
|
||||
|
||||
if (episodes.Count == 0)
|
||||
{
|
||||
return;
|
||||
@ -178,51 +180,6 @@ public class DetectIntroductionsTask : IScheduledTask
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that all episodes in a season exist in Jellyfin and as a file in storage.
|
||||
/// TODO: FIXME: move to queue manager.
|
||||
/// </summary>
|
||||
/// <param name="candidates">QueuedEpisodes.</param>
|
||||
/// <returns>Verified QueuedEpisodes and a flag indicating if any episode in this season has not been analyzed yet.</returns>
|
||||
private (
|
||||
ReadOnlyCollection<QueuedEpisode> VerifiedEpisodes,
|
||||
bool AnyUnanalyzed)
|
||||
VerifyEpisodes(ReadOnlyCollection<QueuedEpisode> candidates)
|
||||
{
|
||||
var unanalyzed = false;
|
||||
var verified = new List<QueuedEpisode>();
|
||||
|
||||
foreach (var candidate in candidates)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Verify that the episode exists in Jellyfin and in storage
|
||||
var path = Plugin.Instance!.GetItemPath(candidate.EpisodeId);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
verified.Add(candidate);
|
||||
}
|
||||
|
||||
// Flag this season for analysis if the current episode hasn't been analyzed yet
|
||||
if (!Plugin.Instance.Intros.ContainsKey(candidate.EpisodeId))
|
||||
{
|
||||
unanalyzed = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(
|
||||
"Skipping analysis of {Name} ({Id}): {Exception}",
|
||||
candidate.Name,
|
||||
candidate.EpisodeId,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
return (verified.AsReadOnly(), unanalyzed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fingerprints all episodes in the provided season and stores the timestamps of all introductions.
|
||||
/// </summary>
|
||||
|
Loading…
x
Reference in New Issue
Block a user