Add chaining and logs to chapter analyzer
This commit is contained in:
parent
bfb821f311
commit
7439720b3a
@ -51,7 +51,7 @@ public class TestChapterAnalyzer
|
|||||||
config.ChapterAnalyzerIntroductionPattern :
|
config.ChapterAnalyzerIntroductionPattern :
|
||||||
config.ChapterAnalyzerEndCreditsPattern;
|
config.ChapterAnalyzerEndCreditsPattern;
|
||||||
|
|
||||||
return analyzer.FindMatchingChapter(Guid.Empty, 2000, chapters, expression, mode);
|
return analyzer.FindMatchingChapter(new() { Duration = 2000 }, chapters, expression, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<ChapterInfo> CreateChapters(string name, AnalysisMode mode)
|
private Collection<ChapterInfo> CreateChapters(string name, AnalysisMode mode)
|
||||||
|
@ -3,6 +3,7 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -30,7 +31,9 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
AnalysisMode mode,
|
AnalysisMode mode,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
|
var unsuccessful = new List<QueuedEpisode>();
|
||||||
var skippableRanges = new Dictionary<Guid, Intro>();
|
var skippableRanges = new Dictionary<Guid, Intro>();
|
||||||
|
|
||||||
var expression = mode == AnalysisMode.Introduction ?
|
var expression = mode == AnalysisMode.Introduction ?
|
||||||
Plugin.Instance!.Configuration.ChapterAnalyzerIntroductionPattern :
|
Plugin.Instance!.Configuration.ChapterAnalyzerIntroductionPattern :
|
||||||
Plugin.Instance!.Configuration.ChapterAnalyzerEndCreditsPattern;
|
Plugin.Instance!.Configuration.ChapterAnalyzerEndCreditsPattern;
|
||||||
@ -43,14 +46,14 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
}
|
}
|
||||||
|
|
||||||
var skipRange = FindMatchingChapter(
|
var skipRange = FindMatchingChapter(
|
||||||
episode.EpisodeId,
|
episode,
|
||||||
episode.Duration,
|
|
||||||
new(Plugin.Instance!.GetChapters(episode.EpisodeId)),
|
new(Plugin.Instance!.GetChapters(episode.EpisodeId)),
|
||||||
expression,
|
expression,
|
||||||
mode);
|
mode);
|
||||||
|
|
||||||
if (skipRange is null)
|
if (skipRange is null)
|
||||||
{
|
{
|
||||||
|
unsuccessful.Add(episode);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,22 +62,20 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
|
|
||||||
Plugin.Instance!.UpdateTimestamps(skippableRanges, mode);
|
Plugin.Instance!.UpdateTimestamps(skippableRanges, mode);
|
||||||
|
|
||||||
return analysisQueue;
|
return unsuccessful.AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Searches a list of chapter names for one that matches the provided regular expression.
|
/// Searches a list of chapter names for one that matches the provided regular expression.
|
||||||
/// Only public to allow for unit testing.
|
/// Only public to allow for unit testing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">Item id.</param>
|
/// <param name="episode">Episode.</param>
|
||||||
/// <param name="duration">Duration of media file in seconds.</param>
|
|
||||||
/// <param name="chapters">Media item chapters.</param>
|
/// <param name="chapters">Media item chapters.</param>
|
||||||
/// <param name="expression">Regular expression pattern.</param>
|
/// <param name="expression">Regular expression pattern.</param>
|
||||||
/// <param name="mode">Analysis mode.</param>
|
/// <param name="mode">Analysis mode.</param>
|
||||||
/// <returns>Intro object containing skippable time range, or null if no chapter matched.</returns>
|
/// <returns>Intro object containing skippable time range, or null if no chapter matched.</returns>
|
||||||
public Intro? FindMatchingChapter(
|
public Intro? FindMatchingChapter(
|
||||||
Guid id,
|
QueuedEpisode episode,
|
||||||
int duration,
|
|
||||||
Collection<ChapterInfo> chapters,
|
Collection<ChapterInfo> chapters,
|
||||||
string expression,
|
string expression,
|
||||||
AnalysisMode mode)
|
AnalysisMode mode)
|
||||||
@ -82,6 +83,7 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
Intro? matchingChapter = null;
|
Intro? matchingChapter = null;
|
||||||
|
|
||||||
var config = Plugin.Instance?.Configuration ?? new Configuration.PluginConfiguration();
|
var config = Plugin.Instance?.Configuration ?? new Configuration.PluginConfiguration();
|
||||||
|
|
||||||
var minDuration = config.MinimumIntroDuration;
|
var minDuration = config.MinimumIntroDuration;
|
||||||
int maxDuration = mode == AnalysisMode.Introduction ?
|
int maxDuration = mode == AnalysisMode.Introduction ?
|
||||||
config.MaximumIntroDuration :
|
config.MaximumIntroDuration :
|
||||||
@ -91,28 +93,38 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
{
|
{
|
||||||
// Since the ending credits chapter may be the last chapter in the file, append a virtual
|
// Since the ending credits chapter may be the last chapter in the file, append a virtual
|
||||||
// chapter at the very end of the file.
|
// chapter at the very end of the file.
|
||||||
chapters.Add(new ChapterInfo()
|
chapters.Add(new()
|
||||||
{
|
{
|
||||||
StartPositionTicks = TimeSpan.FromSeconds(duration).Ticks
|
StartPositionTicks = TimeSpan.FromSeconds(episode.Duration).Ticks
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check all chapters
|
// Check all chapters
|
||||||
for (int i = 0; i < chapters.Count - 1; i++)
|
for (int i = 0; i < chapters.Count - 1; i++)
|
||||||
{
|
{
|
||||||
// Calculate chapter position and duration
|
|
||||||
var current = chapters[i];
|
var current = chapters[i];
|
||||||
var next = chapters[i + 1];
|
var next = chapters[i + 1];
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(current.Name))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
var currentRange = new TimeRange(
|
var currentRange = new TimeRange(
|
||||||
TimeSpan.FromTicks(current.StartPositionTicks).TotalSeconds,
|
TimeSpan.FromTicks(current.StartPositionTicks).TotalSeconds,
|
||||||
TimeSpan.FromTicks(next.StartPositionTicks).TotalSeconds);
|
TimeSpan.FromTicks(next.StartPositionTicks).TotalSeconds);
|
||||||
|
|
||||||
// Skip chapters with that don't have a name or are too short/long
|
var baseMessage = string.Format(
|
||||||
if (string.IsNullOrEmpty(current.Name) ||
|
CultureInfo.InvariantCulture,
|
||||||
currentRange.Duration < minDuration ||
|
"{0}: Chapter \"{1}\" ({2} - {3})",
|
||||||
currentRange.Duration > maxDuration)
|
episode.Path,
|
||||||
|
current.Name,
|
||||||
|
currentRange.Start,
|
||||||
|
currentRange.End);
|
||||||
|
|
||||||
|
if (currentRange.Duration < minDuration || currentRange.Duration > maxDuration)
|
||||||
{
|
{
|
||||||
|
_logger.LogTrace("{Base}: ignoring (invalid duration)", baseMessage);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,10 +138,12 @@ public class ChapterAnalyzer : IMediaFileAnalyzer
|
|||||||
|
|
||||||
if (!match)
|
if (!match)
|
||||||
{
|
{
|
||||||
|
_logger.LogTrace("{Base}: ignoring (does not match regular expression)", baseMessage);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
matchingChapter = new Intro(id, currentRange);
|
matchingChapter = new(episode.EpisodeId, currentRange);
|
||||||
|
_logger.LogTrace("{Base}: okay", baseMessage);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ public class DetectIntroductionsTask : IScheduledTask
|
|||||||
|
|
||||||
// Chapter analyzer
|
// Chapter analyzer
|
||||||
var chapter = new ChapterAnalyzer(_loggerFactory.CreateLogger<ChapterAnalyzer>());
|
var chapter = new ChapterAnalyzer(_loggerFactory.CreateLogger<ChapterAnalyzer>());
|
||||||
chapter.AnalyzeMediaFiles(episodes, AnalysisMode.Introduction, cancellationToken);
|
episodes = chapter.AnalyzeMediaFiles(episodes, AnalysisMode.Introduction, cancellationToken);
|
||||||
|
|
||||||
// Analyze the season with Chromaprint
|
// Analyze the season with Chromaprint
|
||||||
var chromaprint = new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>());
|
var chromaprint = new ChromaprintAnalyzer(_loggerFactory.CreateLogger<ChromaprintAnalyzer>());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user