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