Increase accuracy
This commit is contained in:
parent
9c4b62ff5e
commit
b9612f83c1
@ -244,17 +244,19 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
{
|
{
|
||||||
Plugin.Instance!.Intros[intro.Key] = intro.Value;
|
Plugin.Instance!.Intros[intro.Key] = intro.Value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only run the second pass if the user hasn't requested cancellation and we found an intro
|
||||||
|
if (!cancellationToken.IsCancellationRequested && everFoundIntro)
|
||||||
|
{
|
||||||
|
// Run a second pass over this season to remove outliers and fix episodes that failed in the first pass.
|
||||||
|
RunSecondPass(season.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_introsLock)
|
||||||
|
{
|
||||||
Plugin.Instance!.SaveTimestamps();
|
Plugin.Instance!.SaveTimestamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cancellationToken.IsCancellationRequested || !everFoundIntro)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reanalyze this season to check for (and hopefully correct) outliers and failed episodes.
|
|
||||||
CheckSeason(season.Value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -478,7 +480,7 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
/// Looks for and fixes intro durations that were either not found or are statistical outliers.
|
/// Looks for and fixes intro durations that were either not found or are statistical outliers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="episodes">List of episodes that was just analyzed.</param>
|
/// <param name="episodes">List of episodes that was just analyzed.</param>
|
||||||
private void CheckSeason(List<QueuedEpisode> episodes)
|
private void RunSecondPass(List<QueuedEpisode> episodes)
|
||||||
{
|
{
|
||||||
var intros = Plugin.Instance!.Intros;
|
var intros = Plugin.Instance!.Intros;
|
||||||
|
|
||||||
@ -539,9 +541,8 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the most frequently seen bucket has a majority
|
// Ensure that the most frequently seen bucket has a majority
|
||||||
// TODO: change to debug
|
|
||||||
percentValid = (maxBucket.Count * 100) / validCount;
|
percentValid = (maxBucket.Count * 100) / validCount;
|
||||||
_logger.LogInformation(
|
_logger.LogDebug(
|
||||||
"Intro duration {Duration} appeared {Frequency} times ({Percent}%)",
|
"Intro duration {Duration} appeared {Frequency} times ({Percent}%)",
|
||||||
maxDuration,
|
maxDuration,
|
||||||
maxBucket.Count,
|
maxBucket.Count,
|
||||||
@ -552,22 +553,29 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Reanalyzing {Count} episodes", totalCount - maxBucket.Count);
|
_logger.LogDebug("Second pass is processing {Count} episodes", totalCount - maxBucket.Count);
|
||||||
|
|
||||||
// TODO: pick two episodes at random
|
// Calculate a range of intro durations that are most likely to be correct.
|
||||||
var lhs = episodes.Find(x => x.EpisodeId == maxBucket.Episodes[1]);
|
var maxEpisode = episodes.Find(x => x.EpisodeId == maxBucket.Episodes[0]);
|
||||||
if (lhs is null)
|
if (maxEpisode is null)
|
||||||
{
|
{
|
||||||
_logger.LogError("Reanalysis failed to get episode from bucket");
|
_logger.LogError("Second pass failed to get episode from bucket");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lhsFingerprint = _fingerprintCache[lhs.EpisodeId];
|
var lhsDuration = GetIntroDuration(maxEpisode.EpisodeId);
|
||||||
var lhsDuration = GetIntroDuration(lhs.EpisodeId);
|
|
||||||
var (lowTargetDuration, highTargetDuration) = (
|
var (lowTargetDuration, highTargetDuration) = (
|
||||||
lhsDuration - ReanalysisTolerance,
|
lhsDuration - ReanalysisTolerance,
|
||||||
lhsDuration + ReanalysisTolerance);
|
lhsDuration + ReanalysisTolerance);
|
||||||
|
|
||||||
|
// TODO: add limit and make it customizable
|
||||||
|
var count = maxBucket.Episodes.Count - 1;
|
||||||
|
var goodFingerprints = new List<ReadOnlyCollection<uint>>();
|
||||||
|
foreach (var id in maxBucket.Episodes)
|
||||||
|
{
|
||||||
|
goodFingerprints.Add(_fingerprintCache[id]);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var episode in episodes)
|
foreach (var episode in episodes)
|
||||||
{
|
{
|
||||||
// Don't reanalyze episodes from the max bucket
|
// Don't reanalyze episodes from the max bucket
|
||||||
@ -584,7 +592,7 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
// If the episode's intro duration is close enough to the targeted bucket, leave it alone.
|
// If the episode's intro duration is close enough to the targeted bucket, leave it alone.
|
||||||
if (Math.Abs(lhsDuration - oldDuration) <= ReanalysisTolerance)
|
if (Math.Abs(lhsDuration - oldDuration) <= ReanalysisTolerance)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
_logger.LogDebug(
|
||||||
"Not reanalyzing episode {Path} (intro is {Initial}, target is {Max})",
|
"Not reanalyzing episode {Path} (intro is {Initial}, target is {Max})",
|
||||||
shortPath,
|
shortPath,
|
||||||
Math.Round(oldDuration, 2),
|
Math.Round(oldDuration, 2),
|
||||||
@ -600,8 +608,10 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
maxDuration);
|
maxDuration);
|
||||||
|
|
||||||
// Analyze the episode again, ignoring whatever is returned for the known good episode.
|
// Analyze the episode again, ignoring whatever is returned for the known good episode.
|
||||||
|
foreach (var lhsFingerprint in goodFingerprints)
|
||||||
|
{
|
||||||
var (_, newRhs) = FingerprintEpisodes(
|
var (_, newRhs) = FingerprintEpisodes(
|
||||||
lhs.EpisodeId,
|
maxEpisode.EpisodeId,
|
||||||
lhsFingerprint,
|
lhsFingerprint,
|
||||||
episode.EpisodeId,
|
episode.EpisodeId,
|
||||||
_fingerprintCache[episode.EpisodeId]);
|
_fingerprintCache[episode.EpisodeId]);
|
||||||
@ -610,7 +620,7 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
var newDuration = Math.Round(newRhs.IntroEnd - newRhs.IntroStart, 2);
|
var newDuration = Math.Round(newRhs.IntroEnd - newRhs.IntroStart, 2);
|
||||||
if (newDuration < oldDuration || newDuration < lowTargetDuration || newDuration > highTargetDuration)
|
if (newDuration < oldDuration || newDuration < lowTargetDuration || newDuration > highTargetDuration)
|
||||||
{
|
{
|
||||||
_logger.LogInformation(
|
_logger.LogDebug(
|
||||||
"Ignoring reanalysis for {Path} (was {Initial}, now is {New})",
|
"Ignoring reanalysis for {Path} (was {Initial}, now is {New})",
|
||||||
shortPath,
|
shortPath,
|
||||||
oldDuration,
|
oldDuration,
|
||||||
@ -630,6 +640,9 @@ public class FingerprinterTask : IScheduledTask
|
|||||||
{
|
{
|
||||||
Plugin.Instance!.Intros[episode.EpisodeId] = newRhs;
|
Plugin.Instance!.Intros[episode.EpisodeId] = newRhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user