Skip to content

Commit

Permalink
Add cancellation of automatic tasks from scheduled tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
rlauuzo committed Apr 13, 2024
1 parent 2e45949 commit 0a9394b
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 49 deletions.
127 changes: 87 additions & 40 deletions ConfusedPolarBear.Plugin.IntroSkipper/Entrypoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class Entrypoint : IServerEntryPoint
private readonly ILoggerFactory _loggerFactory;
private Timer _queueTimer;
private bool _analyzeAgain;
private static CancellationTokenSource? _cancellationTokenSource;
private static ManualResetEventSlim _autoTaskCompletEvent = new ManualResetEventSlim(false);

/// <summary>
/// Initializes a new instance of the <see cref="Entrypoint"/> class.
Expand Down Expand Up @@ -56,6 +58,24 @@ public class Entrypoint : IServerEntryPoint
Timeout.InfiniteTimeSpan);
}

/// <summary>
/// Gets State of the automatic task.
/// </summary>
public static TaskState AutomaticTaskState
{
get
{
if (_cancellationTokenSource is not null)
{
return _cancellationTokenSource.IsCancellationRequested
? TaskState.Cancelling
: TaskState.Running;
}

return TaskState.Idle;
}
}

/// <summary>
/// Registers event handler.
/// </summary>
Expand Down Expand Up @@ -208,50 +228,54 @@ private void PerformAnalysis()
_logger.LogInformation("Timer elapsed - start analyzing");
Plugin.Instance!.AnalyzerTaskIsRunning = true;

var progress = new Progress<double>();
var cancellationToken = new CancellationToken(false);

if (Plugin.Instance!.Configuration.AutoDetectIntros && Plugin.Instance!.Configuration.AutoDetectCredits)
{
// This is where we can optimize a single scan
var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosCreditsTask>(),
_loggerFactory,
_libraryManager);

baseIntroAnalyzer.AnalyzeItems(progress, cancellationToken);

var baseCreditAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Credits,
_loggerFactory.CreateLogger<DetectIntrosCreditsTask>(),
_loggerFactory,
_libraryManager);

baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken);
}
else if (Plugin.Instance!.Configuration.AutoDetectIntros)
{
var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosTask>(),
_loggerFactory,
_libraryManager);

baseIntroAnalyzer.AnalyzeItems(progress, cancellationToken);
}
else if (Plugin.Instance!.Configuration.AutoDetectCredits)
using (_cancellationTokenSource = new CancellationTokenSource())
{
var baseCreditAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Credits,
_loggerFactory.CreateLogger<DetectCreditsTask>(),
_loggerFactory,
_libraryManager);

baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken);
var progress = new Progress<double>();
var cancellationToken = _cancellationTokenSource.Token;

if (Plugin.Instance!.Configuration.AutoDetectIntros && Plugin.Instance!.Configuration.AutoDetectCredits)
{
// This is where we can optimize a single scan
var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosCreditsTask>(),
_loggerFactory,
_libraryManager);

baseIntroAnalyzer.AnalyzeItems(progress, cancellationToken);

var baseCreditAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Credits,
_loggerFactory.CreateLogger<DetectIntrosCreditsTask>(),
_loggerFactory,
_libraryManager);

baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken);
}
else if (Plugin.Instance!.Configuration.AutoDetectIntros)
{
var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosTask>(),
_loggerFactory,
_libraryManager);

baseIntroAnalyzer.AnalyzeItems(progress, cancellationToken);
}
else if (Plugin.Instance!.Configuration.AutoDetectCredits)
{
var baseCreditAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Credits,
_loggerFactory.CreateLogger<DetectCreditsTask>(),
_loggerFactory,
_libraryManager);

baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken);
}
}

Plugin.Instance!.AnalyzerTaskIsRunning = false;
_autoTaskCompletEvent.Set();

// New item detected, start timer again
if (_analyzeAgain)
Expand All @@ -262,6 +286,23 @@ private void PerformAnalysis()
}
}

/// <summary>
/// Method to cancel the automatic task.
/// </summary>
public static void CancelAutomaticTask()
{
if (_cancellationTokenSource != null)
{
_cancellationTokenSource.Cancel();

_autoTaskCompletEvent.Wait(); // Wait for the signal
_autoTaskCompletEvent.Reset(); // Reset for the next task

_cancellationTokenSource.Dispose(); // Now safe to dispose
_cancellationTokenSource = null;
}
}

/// <summary>
/// Dispose.
/// </summary>
Expand All @@ -283,6 +324,12 @@ protected virtual void Dispose(bool dispose)
_libraryManager.ItemUpdated -= OnItemModified;
_taskManager.TaskCompleted -= OnLibraryRefresh;

if (_cancellationTokenSource != null) // Null Check
{
_cancellationTokenSource.Dispose();
_cancellationTokenSource = null;
}

_queueTimer.Dispose();

return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,19 @@ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellat
}

// abort if analyzer is already running
if (Plugin.Instance!.AnalyzerTaskIsRunning)
if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle)
{
return Task.CompletedTask;
}
else
else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running)
{
Plugin.Instance!.AnalyzerTaskIsRunning = true;
_logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState);
Entrypoint.CancelAutomaticTask();
}

_logger.LogInformation("Scheduled Task is starting");
Plugin.Instance!.AnalyzerTaskIsRunning = true;

var baseCreditAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Credits,
_loggerFactory.CreateLogger<DetectCreditsTask>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
/// </summary>
public class DetectIntrosCreditsTask : IScheduledTask
{
private readonly ILogger<DetectIntrosCreditsTask> _logger;

private readonly ILoggerFactory _loggerFactory;

private readonly ILibraryManager _libraryManager;
Expand All @@ -22,10 +24,13 @@ public class DetectIntrosCreditsTask : IScheduledTask
/// </summary>
/// <param name="loggerFactory">Logger factory.</param>
/// <param name="libraryManager">Library manager.</param>
/// <param name="logger">Logger.</param>
public DetectIntrosCreditsTask(
ILogger<DetectIntrosCreditsTask> logger,
ILoggerFactory loggerFactory,
ILibraryManager libraryManager)
{
_logger = logger;
_loggerFactory = loggerFactory;
_libraryManager = libraryManager;
}
Expand Down Expand Up @@ -64,15 +69,19 @@ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellat
}

// abort if analyzer is already running
if (Plugin.Instance!.AnalyzerTaskIsRunning)
if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle)
{
return Task.CompletedTask;
}
else
else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running)
{
Plugin.Instance!.AnalyzerTaskIsRunning = true;
_logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState);
Entrypoint.CancelAutomaticTask();
}

_logger.LogInformation("Scheduled Task is starting");
Plugin.Instance!.AnalyzerTaskIsRunning = true;

var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosCreditsTask>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,19 @@ public Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellat
}

// abort if analyzer is already running
if (Plugin.Instance!.AnalyzerTaskIsRunning)
if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle)
{
return Task.CompletedTask;
}
else
else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running)
{
Plugin.Instance!.AnalyzerTaskIsRunning = true;
_logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState);
Entrypoint.CancelAutomaticTask();
}

_logger.LogInformation("Scheduled Task is starting");
Plugin.Instance!.AnalyzerTaskIsRunning = true;

var baseIntroAnalyzer = new BaseItemAnalyzerTask(
AnalysisMode.Introduction,
_loggerFactory.CreateLogger<DetectIntrosTask>(),
Expand Down

0 comments on commit 0a9394b

Please sign in to comment.