Server side works

This commit is contained in:
ConfusedPolarBear 2022-05-01 01:24:57 -05:00
parent a1862d0e2f
commit 98f73c3dba
5 changed files with 57 additions and 68 deletions

View File

@ -1,23 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
namespace ConfusedPolarBear.Plugin.IntroSkipper.Configuration; namespace ConfusedPolarBear.Plugin.IntroSkipper.Configuration;
/// <summary>
/// The configuration options.
/// </summary>
public enum SomeOptions
{
/// <summary>
/// Option one.
/// </summary>
OneOption,
/// <summary>
/// Second option.
/// </summary>
AnotherOption
}
/// <summary> /// <summary>
/// Plugin configuration. /// Plugin configuration.
/// </summary> /// </summary>
@ -28,30 +16,38 @@ public class PluginConfiguration : BasePluginConfiguration
/// </summary> /// </summary>
public PluginConfiguration() public PluginConfiguration()
{ {
// set default options here AnalysisResults = new Collection<Intro>();
Options = SomeOptions.AnotherOption;
TrueFalseSetting = true;
AnInteger = 2;
AString = "string";
} }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether some true or false setting is enabled.. /// Save timestamps to disk.
/// </summary> /// </summary>
public bool TrueFalseSetting { get; set; } public void SaveTimestamps()
{
AnalysisResults.Clear();
foreach (var intro in Plugin.Instance!.Intros)
{
AnalysisResults.Add(intro.Value);
}
Plugin.Instance!.SaveConfiguration();
}
/// <summary> /// <summary>
/// Gets or sets an integer setting. /// Restore previous analysis results from disk.
/// </summary> /// </summary>
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;
}
}
/// <summary> /// <summary>
/// Gets or sets a string setting. /// Previous analysis results.
/// </summary> /// </summary>
public string AString { get; set; } public Collection<Intro> AnalysisResults { get; private set; }
/// <summary>
/// Gets or sets an enum option.
/// </summary>
public SomeOptions Options { get; set; }
} }

View File

@ -1,17 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Net.Mime; 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.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
namespace ConfusedPolarBear.Plugin.IntroSkipper.Controllers; namespace ConfusedPolarBear.Plugin.IntroSkipper.Controllers;
@ -33,18 +23,18 @@ public class SkipIntroController : ControllerBase
/// <summary> /// <summary>
/// Returns the timestamps of the introduction in a television episode. /// Returns the timestamps of the introduction in a television episode.
/// </summary> /// </summary>
/// <param name="episodeId">ID of the episode. Required.</param> /// <param name="id">ID of the episode. Required.</param>
/// <response code="200">Episode contains an intro.</response> /// <response code="200">Episode contains an intro.</response>
/// <response code="404">Failed to find an intro in the provided episode.</response> /// <response code="404">Failed to find an intro in the provided episode.</response>
[HttpGet("Episode/{id}/IntroTimestamps")] [HttpGet("Episode/{id}/IntroTimestamps")]
public ActionResult<Intro> GetIntroTimestamps([FromRoute] Guid episodeId) public ActionResult<Intro> GetIntroTimestamps([FromRoute] Guid id)
{ {
if (!Plugin.Instance!.Intros.ContainsKey(episodeId)) if (!Plugin.Instance!.Intros.ContainsKey(id))
{ {
return NotFound(); return NotFound();
} }
var intro = Plugin.Instance!.Intros[episodeId]; var intro = Plugin.Instance!.Intros[id];
// Check that the episode was analyzed successfully. // Check that the episode was analyzed successfully.
if (!intro.Valid) if (!intro.Valid)

View File

@ -6,8 +6,12 @@ namespace ConfusedPolarBear.Plugin.IntroSkipper;
/// Result of fingerprinting and analyzing two episodes in a season. /// Result of fingerprinting and analyzing two episodes in a season.
/// All times are measured in seconds relative to the beginning of the media file. /// All times are measured in seconds relative to the beginning of the media file.
/// </summary> /// </summary>
[Serializable]
public class Intro { public class Intro {
/// <summary>
/// Episode ID.
/// </summary>
public Guid EpisodeId { get; set; }
/// <summary> /// <summary>
/// If this introduction is valid or not. Invalid results should not be returned through the API. /// If this introduction is valid or not. Invalid results should not be returned through the API.
/// </summary> /// </summary>

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.ObjectModel;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using ConfusedPolarBear.Plugin.IntroSkipper.Configuration; using ConfusedPolarBear.Plugin.IntroSkipper.Configuration;
@ -11,10 +10,25 @@ using MediaBrowser.Model.Serialization;
namespace ConfusedPolarBear.Plugin.IntroSkipper; namespace ConfusedPolarBear.Plugin.IntroSkipper;
/// <summary> /// <summary>
/// The main plugin. /// Intro skipper plugin. Uses audio analysis to find common sequences of audio shared between episodes.
/// </summary> /// </summary>
public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
{ {
/// <summary>
/// Initializes a new instance of the <see cref="Plugin"/> class.
/// </summary>
/// <param name="applicationPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
/// <param name="xmlSerializer">Instance of the <see cref="IXmlSerializer"/> interface.</param>
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
: base(applicationPaths, xmlSerializer)
{
Intros = new Dictionary<Guid, Intro>();
AnalysisQueue = new Dictionary<Guid, List<QueuedEpisode>>();
Instance = this;
Configuration.RestoreTimestamps();
}
/// <summary> /// <summary>
/// Results of fingerprinting all episodes. /// Results of fingerprinting all episodes.
/// </summary> /// </summary>
@ -30,29 +44,13 @@ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
/// </summary> /// </summary>
public int TotalQueued { get; set; } public int TotalQueued { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="Plugin"/> class.
/// </summary>
/// <param name="applicationPaths">Instance of the <see cref="IApplicationPaths"/> interface.</param>
/// <param name="xmlSerializer">Instance of the <see cref="IXmlSerializer"/> interface.</param>
public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
: base(applicationPaths, xmlSerializer)
{
Intros = new Dictionary<Guid, Intro>();
AnalysisQueue = new Dictionary<Guid, List<QueuedEpisode>>();
Instance = this;
}
/// <inheritdoc /> /// <inheritdoc />
public override string Name => "Intro Skipper"; public override string Name => "Intro Skipper";
/// <inheritdoc /> /// <inheritdoc />
public override Guid Id => Guid.Parse("c83d86bb-a1e0-4c35-a113-e2101cf4ee6b"); public override Guid Id => Guid.Parse("c83d86bb-a1e0-4c35-a113-e2101cf4ee6b");
/// <summary> /// <inheritdoc />
/// Gets the current plugin instance.
/// </summary>
public static Plugin? Instance { get; private set; } public static Plugin? Instance { get; private set; }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -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; return Task.CompletedTask;
@ -248,10 +248,11 @@ public class FingerprinterTask : IScheduledTask {
// and that it disappears 10 seconds after the intro begins. // and that it disappears 10 seconds after the intro begins.
Plugin.Instance!.Intros[episode] = new Intro() Plugin.Instance!.Intros[episode] = new Intro()
{ {
EpisodeId = episode,
Valid = (introStart > 0) && (introEnd > 0), Valid = (introStart > 0) && (introEnd > 0),
IntroStart = introStart, IntroStart = introStart,
IntroEnd = introEnd, IntroEnd = introEnd,
ShowSkipPromptAt = Math.Min(0, introStart - 5), ShowSkipPromptAt = Math.Max(0, introStart - 5),
HideSkipPromptAt = introStart + 10 HideSkipPromptAt = introStart + 10
}; };
} }