diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs index c3c414c..e42540b 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Configuration/PluginConfiguration.cs @@ -1,23 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; + using MediaBrowser.Model.Plugins; namespace ConfusedPolarBear.Plugin.IntroSkipper.Configuration; -/// -/// The configuration options. -/// -public enum SomeOptions -{ - /// - /// Option one. - /// - OneOption, - - /// - /// Second option. - /// - AnotherOption -} - /// /// Plugin configuration. /// @@ -28,30 +16,38 @@ public class PluginConfiguration : BasePluginConfiguration /// public PluginConfiguration() { - // set default options here - Options = SomeOptions.AnotherOption; - TrueFalseSetting = true; - AnInteger = 2; - AString = "string"; + AnalysisResults = new Collection(); } /// - /// Gets or sets a value indicating whether some true or false setting is enabled.. + /// Save timestamps to disk. /// - public bool TrueFalseSetting { get; set; } + public void SaveTimestamps() + { + AnalysisResults.Clear(); + + foreach (var intro in Plugin.Instance!.Intros) + { + AnalysisResults.Add(intro.Value); + } + + Plugin.Instance!.SaveConfiguration(); + } /// - /// Gets or sets an integer setting. + /// Restore previous analysis results from disk. /// - public int AnInteger { get; set; } + public void RestoreTimestamps() + { + // Since dictionaries can't be easily serialized, analysis results are stored on disk as a list. + foreach (var intro in AnalysisResults) + { + Plugin.Instance!.Intros[intro.EpisodeId] = intro; + } + } /// - /// Gets or sets a string setting. + /// Previous analysis results. /// - public string AString { get; set; } - - /// - /// Gets or sets an enum option. - /// - public SomeOptions Options { get; set; } + public Collection AnalysisResults { get; private set; } } diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs index 43f9f1c..e917e11 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Controllers/SkipIntroController.cs @@ -1,17 +1,7 @@ using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; using System.Net.Mime; -using System.Text.Json; -using Jellyfin.Data.Entities; -using Jellyfin.Extensions.Json; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Dto; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; namespace ConfusedPolarBear.Plugin.IntroSkipper.Controllers; @@ -33,18 +23,18 @@ public class SkipIntroController : ControllerBase /// /// Returns the timestamps of the introduction in a television episode. /// - /// ID of the episode. Required. + /// ID of the episode. Required. /// Episode contains an intro. /// Failed to find an intro in the provided episode. [HttpGet("Episode/{id}/IntroTimestamps")] - public ActionResult GetIntroTimestamps([FromRoute] Guid episodeId) + public ActionResult GetIntroTimestamps([FromRoute] Guid id) { - if (!Plugin.Instance!.Intros.ContainsKey(episodeId)) + if (!Plugin.Instance!.Intros.ContainsKey(id)) { return NotFound(); } - var intro = Plugin.Instance!.Intros[episodeId]; + var intro = Plugin.Instance!.Intros[id]; // Check that the episode was analyzed successfully. if (!intro.Valid) diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs index d6302fd..d3f8bbd 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Data/Intro.cs @@ -6,8 +6,12 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper; /// Result of fingerprinting and analyzing two episodes in a season. /// All times are measured in seconds relative to the beginning of the media file. /// -[Serializable] public class Intro { + /// + /// Episode ID. + /// + public Guid EpisodeId { get; set; } + /// /// If this introduction is valid or not. Invalid results should not be returned through the API. /// diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs index b015dea..94e4b08 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/Plugin.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.ObjectModel; using System.Collections.Generic; using System.Globalization; using ConfusedPolarBear.Plugin.IntroSkipper.Configuration; @@ -11,10 +10,25 @@ using MediaBrowser.Model.Serialization; namespace ConfusedPolarBear.Plugin.IntroSkipper; /// -/// The main plugin. +/// Intro skipper plugin. Uses audio analysis to find common sequences of audio shared between episodes. /// public class Plugin : BasePlugin, IHasWebPages { + /// + /// Initializes a new instance of the class. + /// + /// Instance of the interface. + /// Instance of the interface. + public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) + : base(applicationPaths, xmlSerializer) + { + Intros = new Dictionary(); + AnalysisQueue = new Dictionary>(); + Instance = this; + + Configuration.RestoreTimestamps(); + } + /// /// Results of fingerprinting all episodes. /// @@ -30,29 +44,13 @@ public class Plugin : BasePlugin, IHasWebPages /// public int TotalQueued { get; set; } - /// - /// Initializes a new instance of the class. - /// - /// Instance of the interface. - /// Instance of the interface. - public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) - : base(applicationPaths, xmlSerializer) - { - Intros = new Dictionary(); - AnalysisQueue = new Dictionary>(); - - Instance = this; - } - /// public override string Name => "Intro Skipper"; /// public override Guid Id => Guid.Parse("c83d86bb-a1e0-4c35-a113-e2101cf4ee6b"); - /// - /// Gets the current plugin instance. - /// + /// public static Plugin? Instance { get; private set; } /// diff --git a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs index 184cc3c..d1b0501 100644 --- a/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs +++ b/ConfusedPolarBear.Plugin.IntroSkipper/ScheduledTasks/FingerprinterTask.cs @@ -119,7 +119,7 @@ public class FingerprinterTask : IScheduledTask { } } - // TODO: after every season completes, serialize fingerprints to disk somewhere + Plugin.Instance!.Configuration.SaveTimestamps(); } return Task.CompletedTask; @@ -248,10 +248,11 @@ public class FingerprinterTask : IScheduledTask { // and that it disappears 10 seconds after the intro begins. Plugin.Instance!.Intros[episode] = new Intro() { + EpisodeId = episode, Valid = (introStart > 0) && (introEnd > 0), IntroStart = introStart, IntroEnd = introEnd, - ShowSkipPromptAt = Math.Min(0, introStart - 5), + ShowSkipPromptAt = Math.Max(0, introStart - 5), HideSkipPromptAt = introStart + 10 }; }