diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Entrypoint.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Entrypoint.cs index 245cc8e..7df8547 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Entrypoint.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Entrypoint.cs @@ -220,11 +220,11 @@ public class Entrypoint : IServerEntryPoint /// private void StartTimer() { - if (Plugin.Instance!.AnalyzerTaskIsRunning) + if (Entrypoint.AutomaticTaskState == TaskState.Running) { _analyzeAgain = true; // Items added during a scan will be included later. } - else + else if (ScheduledTaskSemaphore.CurrentCount > 0) { _logger.LogInformation("Media Library changed, analyzis will start soon!"); _queueTimer.Change(TimeSpan.FromMilliseconds(20000), Timeout.InfiniteTimeSpan); @@ -252,7 +252,7 @@ public class Entrypoint : IServerEntryPoint private void PerformAnalysis() { _logger.LogInformation("Timer elapsed - start analyzing"); - Plugin.Instance!.AnalyzerTaskIsRunning = true; + _autoTaskCompletEvent.Reset(); using (_cancellationTokenSource = new CancellationTokenSource()) { @@ -303,6 +303,7 @@ public class Entrypoint : IServerEntryPoint Plugin.Instance!.Configuration.PathRestrictions.Clear(); Plugin.Instance!.AnalyzerTaskIsRunning = false; _autoTaskCompletEvent.Set(); + _cancellationTokenSource = null; // New item detected, start timer again if (_analyzeAgain) @@ -316,18 +317,18 @@ public class Entrypoint : IServerEntryPoint /// /// Method to cancel the automatic task. /// - public static void CancelAutomaticTask() + /// Cancellation token. + public static void CancelAutomaticTask(CancellationToken cancellationToken) { if (_cancellationTokenSource != null) { - Plugin.Instance!.Configuration.PathRestrictions.Clear(); - _cancellationTokenSource.Cancel(); + if (!_cancellationTokenSource.IsCancellationRequested) + { + Plugin.Instance!.Configuration.PathRestrictions.Clear(); + _cancellationTokenSource.Cancel(); + } - _autoTaskCompletEvent.Wait(); // Wait for the signal - _autoTaskCompletEvent.Reset(); // Reset for the next task - - _cancellationTokenSource.Dispose(); // Now safe to dispose - _cancellationTokenSource = null; + _autoTaskCompletEvent.Wait(TimeSpan.FromSeconds(60), cancellationToken); // Wait for the signal } } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs index bd7d4ab..2b297da 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs @@ -149,11 +149,6 @@ public class Plugin : BasePlugin, IHasWebPages /// public event EventHandler? AutoSkipCreditsChanged; - /// - /// Gets or sets a value indicating whether analysis is running. - /// - public bool AnalyzerTaskIsRunning { get; set; } = false; - /// /// Gets the results of fingerprinting all episodes. /// diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectCreditsTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectCreditsTask.cs index bacb457..2f43939 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectCreditsTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectCreditsTask.cs @@ -69,19 +69,22 @@ public class DetectCreditsTask : IScheduledTask throw new InvalidOperationException("Library manager was null"); } - // abort if analyzer is already running - if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle) - { - return Task.CompletedTask; - } - else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running) + // abort automatic analyzer if running + if (Entrypoint.AutomaticTaskState == TaskState.Running || Entrypoint.AutomaticTaskState == TaskState.Cancelling) { _logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState); - Entrypoint.CancelAutomaticTask(); + Entrypoint.CancelAutomaticTask(cancellationToken); + } + + ScheduledTaskSemaphore.Wait(-1, cancellationToken); + + if (cancellationToken.IsCancellationRequested) + { + ScheduledTaskSemaphore.Release(); + return Task.CompletedTask; } _logger.LogInformation("Scheduled Task is starting"); - Plugin.Instance!.AnalyzerTaskIsRunning = true; var baseCreditAnalyzer = new BaseItemAnalyzerTask( AnalysisMode.Credits, @@ -91,8 +94,7 @@ public class DetectCreditsTask : IScheduledTask baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken); - Plugin.Instance!.AnalyzerTaskIsRunning = false; - + ScheduledTaskSemaphore.Release(); return Task.CompletedTask; } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosCreditsTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosCreditsTask.cs index f58472c..2b465c5 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosCreditsTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosCreditsTask.cs @@ -68,19 +68,22 @@ public class DetectIntrosCreditsTask : IScheduledTask throw new InvalidOperationException("Library manager was null"); } - // abort if analyzer is already running - if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle) - { - return Task.CompletedTask; - } - else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running) + // abort automatic analyzer if running + if (Entrypoint.AutomaticTaskState == TaskState.Running || Entrypoint.AutomaticTaskState == TaskState.Cancelling) { _logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState); - Entrypoint.CancelAutomaticTask(); + Entrypoint.CancelAutomaticTask(cancellationToken); + } + + ScheduledTaskSemaphore.Wait(-1, cancellationToken); + + if (cancellationToken.IsCancellationRequested) + { + ScheduledTaskSemaphore.Release(); + return Task.CompletedTask; } _logger.LogInformation("Scheduled Task is starting"); - Plugin.Instance!.AnalyzerTaskIsRunning = true; var baseIntroAnalyzer = new BaseItemAnalyzerTask( AnalysisMode.Introduction, @@ -98,8 +101,7 @@ public class DetectIntrosCreditsTask : IScheduledTask baseCreditAnalyzer.AnalyzeItems(progress, cancellationToken); - Plugin.Instance!.AnalyzerTaskIsRunning = false; - + ScheduledTaskSemaphore.Release(); return Task.CompletedTask; } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosTask.cs index c92f800..c1f4f57 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/DetectIntrosTask.cs @@ -68,19 +68,22 @@ public class DetectIntrosTask : IScheduledTask throw new InvalidOperationException("Library manager was null"); } - // abort if analyzer is already running - if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Idle) - { - return Task.CompletedTask; - } - else if (Plugin.Instance!.AnalyzerTaskIsRunning && Entrypoint.AutomaticTaskState == TaskState.Running) + // abort automatic analyzer if running + if (Entrypoint.AutomaticTaskState == TaskState.Running || Entrypoint.AutomaticTaskState == TaskState.Cancelling) { _logger.LogInformation("Automatic Task is {0} and will be canceled.", Entrypoint.AutomaticTaskState); - Entrypoint.CancelAutomaticTask(); + Entrypoint.CancelAutomaticTask(cancellationToken); + } + + ScheduledTaskSemaphore.Wait(-1, cancellationToken); + + if (cancellationToken.IsCancellationRequested) + { + ScheduledTaskSemaphore.Release(); + return Task.CompletedTask; } _logger.LogInformation("Scheduled Task is starting"); - Plugin.Instance!.AnalyzerTaskIsRunning = true; var baseIntroAnalyzer = new BaseItemAnalyzerTask( AnalysisMode.Introduction, @@ -90,8 +93,7 @@ public class DetectIntrosTask : IScheduledTask baseIntroAnalyzer.AnalyzeItems(progress, cancellationToken); - Plugin.Instance!.AnalyzerTaskIsRunning = false; - + ScheduledTaskSemaphore.Release(); return Task.CompletedTask; } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/ScheduledTaskSemaphore.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/ScheduledTaskSemaphore.cs new file mode 100644 index 0000000..67b41a2 --- /dev/null +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/ScheduledTaskSemaphore.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading; + +namespace ConfusedPolarBear.Plugin.IntroSkipper; + +internal sealed class ScheduledTaskSemaphore : IDisposable +{ + private static readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1); + + private ScheduledTaskSemaphore() + { + } + + public static int CurrentCount => _semaphore.CurrentCount; + + public static bool Wait(int timeout, CancellationToken cancellationToken) + { + return _semaphore.Wait(timeout, cancellationToken); + } + + public static int Release() + { + return _semaphore.Release(); + } + + /// + /// Dispose. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Protected dispose. + /// + /// Dispose. + private void Dispose(bool disposing) + { + if (!disposing) + { + return; + } + + _semaphore.Dispose(); + } +}