diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbbd0b5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin/ +obj/ \ No newline at end of file diff --git a/JellyfinSkippers.csproj b/JellyfinSkippers.csproj new file mode 100644 index 0000000..c197f8a --- /dev/null +++ b/JellyfinSkippers.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0e9d915 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 RICHARD Dorian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/Controllers/SkipsController.cs b/RichardDorian.Plugin.Skippers/Controllers/SkipsController.cs new file mode 100644 index 0000000..81dfc71 --- /dev/null +++ b/RichardDorian.Plugin.Skippers/Controllers/SkipsController.cs @@ -0,0 +1,35 @@ +using System.Net.Mime; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using RichardDorian.Plugin.Skippers.Data; + +namespace RichardDorian.Plugin.Skippers.Controllers; + +[Authorize] +[ApiController] +[Produces(MediaTypeNames.Application.Json)] +public class SkipsController : ControllerBase +{ + public SkipsController() + { + } + + [HttpGet("Item/{id}/Skips")] + public ActionResult> GetSkips([FromRoute] Guid id) + { + var skips = GetSkipsFromGuid(id); + + if (skips is null) + { + return NotFound(); + } + + return skips; + } + + private static List? GetSkipsFromGuid(Guid id) + { + Plugin.Instance!.Skippers.TryGetValue(id, out var skips); + return skips; + } +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/Data/Skip.cs b/RichardDorian.Plugin.Skippers/Data/Skip.cs new file mode 100644 index 0000000..ee8104a --- /dev/null +++ b/RichardDorian.Plugin.Skippers/Data/Skip.cs @@ -0,0 +1,29 @@ +namespace RichardDorian.Plugin.Skippers.Data; + +public class Skip +{ + public SkipType Type { get; set; } + public double Start { get; set; } + public double End { get; set; } + + public Skip(SkipType type, double start, double end) + { + Type = type; + Start = start; + End = end; + } + + internal Skip() + { + } + + public double ShowPromptAt + { + get => Start + .5f; + } + + public double HidePromptAt + { + get => Math.Round(Start + (End - Start) / 3, 1); + } +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/Data/SkipType.cs b/RichardDorian.Plugin.Skippers/Data/SkipType.cs new file mode 100644 index 0000000..4453e3c --- /dev/null +++ b/RichardDorian.Plugin.Skippers/Data/SkipType.cs @@ -0,0 +1,8 @@ +namespace RichardDorian.Plugin.Skippers.Data; + +public enum SkipType : ushort +{ + Other = 0, + Intro = 1, + PostCreditScene = 2 +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/Data/Skipper.cs b/RichardDorian.Plugin.Skippers/Data/Skipper.cs new file mode 100644 index 0000000..90f9dfc --- /dev/null +++ b/RichardDorian.Plugin.Skippers/Data/Skipper.cs @@ -0,0 +1,19 @@ +namespace RichardDorian.Plugin.Skippers.Data; + +public class Skipper +{ + public Guid Id; + public List Skips; + + public Skipper(Guid id, List skips) + { + Id = id; + Skips = skips; + } + + internal Skipper() + { + Id = Guid.Empty; + Skips = new(); + } +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/Plugin.cs b/RichardDorian.Plugin.Skippers/Plugin.cs new file mode 100644 index 0000000..6cdded3 --- /dev/null +++ b/RichardDorian.Plugin.Skippers/Plugin.cs @@ -0,0 +1,48 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Plugins; +using MediaBrowser.Model.Serialization; +using RichardDorian.Plugin.Skippers.Data; + +namespace RichardDorian.Plugin.Skippers; + +public class Plugin : BasePlugin +{ + private readonly string SkippersPath; + + public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) : base(applicationPaths, xmlSerializer) + { + Instance = this; + + SkippersPath = Path.Join(applicationPaths.PluginConfigurationsPath, "RichardDorian.Plugin.Skippers.xml"); + RestoreSkippersFromDisk(); + } + + public override string Name => "Skippers"; + public override Guid Id => Guid.Parse("b9650cbc-83f5-4e1f-bb54-4dffc66c2033"); + public Dictionary> Skippers { get; set; } = new(); + + public static Plugin? Instance { get; private set; } + + public void RestoreSkippersFromDisk() + { + if (File.Exists(SkippersPath)) + { + var skipsList = (List)XmlSerializer.DeserializeFromFile( + typeof(List), + SkippersPath + ); + + foreach (var skips in skipsList) + { + Skippers[skips.Id] = skips.Skips; + } + } + else + { + XmlSerializer.SerializeToFile( + new List(), + SkippersPath + ); + } + } +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/PluginConfiguration.cs b/RichardDorian.Plugin.Skippers/PluginConfiguration.cs new file mode 100644 index 0000000..8e84190 --- /dev/null +++ b/RichardDorian.Plugin.Skippers/PluginConfiguration.cs @@ -0,0 +1,10 @@ +using MediaBrowser.Model.Plugins; + +namespace RichardDorian.Plugin.Skippers; + +public class PluginConfiguration : BasePluginConfiguration +{ + public PluginConfiguration() + { + } +} \ No newline at end of file diff --git a/RichardDorian.Plugin.Skippers/ScheduledTasks/UpdateSkippers.cs b/RichardDorian.Plugin.Skippers/ScheduledTasks/UpdateSkippers.cs new file mode 100644 index 0000000..8a93b42 --- /dev/null +++ b/RichardDorian.Plugin.Skippers/ScheduledTasks/UpdateSkippers.cs @@ -0,0 +1,25 @@ +using MediaBrowser.Model.Tasks; + +namespace RichardDorian.Plugin.Skippers.ScheduledTasks; + +public class UpdateSkippersTask : IScheduledTask +{ + public string Name => "Update Skippers"; + public string Category => "Skippers"; + public string Description => "Update skippers from disk"; + public string Key => "RichardDorianSkippersUpdate"; + + public Task ExecuteAsync( + IProgress progress, + CancellationToken cancellationToken + ) + { + Plugin.Instance!.RestoreSkippersFromDisk(); + return Task.CompletedTask; + } + + public IEnumerable GetDefaultTriggers() + { + return Array.Empty(); + } +} \ No newline at end of file