From 1dbeb724fc9e5c1497a6286bc8b1d90d3f0370ed Mon Sep 17 00:00:00 2001 From: oceans2alaska Date: Mon, 23 Mar 2026 00:18:34 -0700 Subject: [PATCH] Update README.md --- Api/NewReleasesController.cs | 27 ++++++++++++++++ Jellyfin.Plugin.NewReleases.csproj | 17 ++++++++++ Models/NewReleaseMovieDto.cs | 10 ++++++ Models/NewReleasesResponse.cs | 8 +++++ Plugin.cs | 22 +++++++++++++ PluginConfiguration.cs | 10 ++++++ Services/NewReleasesService.cs | 52 ++++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+) create mode 100644 Api/NewReleasesController.cs create mode 100644 Jellyfin.Plugin.NewReleases.csproj create mode 100644 Models/NewReleaseMovieDto.cs create mode 100644 Models/NewReleasesResponse.cs create mode 100644 Plugin.cs create mode 100644 PluginConfiguration.cs create mode 100644 Services/NewReleasesService.cs diff --git a/Api/NewReleasesController.cs b/Api/NewReleasesController.cs new file mode 100644 index 0000000..d18955f --- /dev/null +++ b/Api/NewReleasesController.cs @@ -0,0 +1,27 @@ +using Jellyfin.Plugin.NewReleases.Models; +using Jellyfin.Plugin.NewReleases.Services; +using MediaBrowser.Controller.Library; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Plugin.NewReleases.Api; + +[ApiController] +[Route("Plugins/NewReleases")] +public sealed class NewReleasesController : ControllerBase +{ + private readonly NewReleasesService _newReleasesService; + + public NewReleasesController(ILibraryManager libraryManager) + { + _newReleasesService = new NewReleasesService(libraryManager); + } + + [HttpGet("Movies")] + [ProducesResponseType(typeof(NewReleasesResponse), StatusCodes.Status200OK)] + public ActionResult GetNewlyReleasedMovies() + { + var response = _newReleasesService.GetNewlyReleasedMovies(); + return Ok(response); + } +} diff --git a/Jellyfin.Plugin.NewReleases.csproj b/Jellyfin.Plugin.NewReleases.csproj new file mode 100644 index 0000000..570eda3 --- /dev/null +++ b/Jellyfin.Plugin.NewReleases.csproj @@ -0,0 +1,17 @@ + + + net8.0 + enable + enable + latest + false + + + + + + + + + + diff --git a/Models/NewReleaseMovieDto.cs b/Models/NewReleaseMovieDto.cs new file mode 100644 index 0000000..5f46ccc --- /dev/null +++ b/Models/NewReleaseMovieDto.cs @@ -0,0 +1,10 @@ +namespace Jellyfin.Plugin.NewReleases.Models; + +public sealed class NewReleaseMovieDto +{ + public string Id { get; set; } = string.Empty; + + public string Name { get; set; } = string.Empty; + + public DateTime PremiereDate { get; set; } +} diff --git a/Models/NewReleasesResponse.cs b/Models/NewReleasesResponse.cs new file mode 100644 index 0000000..3402437 --- /dev/null +++ b/Models/NewReleasesResponse.cs @@ -0,0 +1,8 @@ +namespace Jellyfin.Plugin.NewReleases.Models; + +public sealed class NewReleasesResponse +{ + public int TotalRecordCount { get; set; } + + public List Items { get; set; } = []; +} diff --git a/Plugin.cs b/Plugin.cs new file mode 100644 index 0000000..c0de4ad --- /dev/null +++ b/Plugin.cs @@ -0,0 +1,22 @@ +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Plugins; +using MediaBrowser.Model.Serialization; + +namespace Jellyfin.Plugin.NewReleases; + +public sealed class Plugin : BasePlugin +{ + public static Plugin? Instance { get; private set; } + + public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer) + : base(applicationPaths, xmlSerializer) + { + Instance = this; + } + + public override string Name => "Jellyfin New Releases"; + + public override Guid Id => new("cc3f7cd7-e910-4f09-bf89-e9c7ba7fca77"); + + public override string Description => "Provides newly released movies based on PremiereDate."; +} diff --git a/PluginConfiguration.cs b/PluginConfiguration.cs new file mode 100644 index 0000000..3ecb737 --- /dev/null +++ b/PluginConfiguration.cs @@ -0,0 +1,10 @@ +using MediaBrowser.Model.Plugins; + +namespace Jellyfin.Plugin.NewReleases; + +public sealed class PluginConfiguration : BasePluginConfiguration +{ + public int MaxItems { get; set; } = 20; + + public int ReleaseWindowDays { get; set; } = 365; +} diff --git a/Services/NewReleasesService.cs b/Services/NewReleasesService.cs new file mode 100644 index 0000000..9e8694b --- /dev/null +++ b/Services/NewReleasesService.cs @@ -0,0 +1,52 @@ +using Jellyfin.Plugin.NewReleases.Models; +using Jellyfin.Data.Enums; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; + +namespace Jellyfin.Plugin.NewReleases.Services; + +public sealed class NewReleasesService +{ + private const int DefaultMaxItems = 20; + private const int DefaultReleaseWindowDays = 365; + + private readonly ILibraryManager _libraryManager; + + public NewReleasesService(ILibraryManager libraryManager) + { + _libraryManager = libraryManager; + } + + public NewReleasesResponse GetNewlyReleasedMovies() + { + var configuration = Plugin.Instance?.Configuration ?? new PluginConfiguration(); + var maxItems = configuration.MaxItems > 0 ? configuration.MaxItems : DefaultMaxItems; + var releaseWindowDays = configuration.ReleaseWindowDays > 0 ? configuration.ReleaseWindowDays : DefaultReleaseWindowDays; + var cutoffUtc = DateTime.UtcNow.AddDays(-releaseWindowDays); + + var query = new InternalItemsQuery + { + IncludeItemTypes = [BaseItemKind.Movie], + Recursive = true + }; + + var items = _libraryManager.GetItemList(query) + .Where(x => x.PremiereDate.HasValue) + .Where(x => x.PremiereDate!.Value.ToUniversalTime() >= cutoffUtc) + .OrderByDescending(x => x.PremiereDate!.Value) + .Take(maxItems) + .Select(x => new NewReleaseMovieDto + { + Id = x.Id.ToString("N"), + Name = x.Name, + PremiereDate = x.PremiereDate!.Value.ToUniversalTime() + }) + .ToList(); + + return new NewReleasesResponse + { + TotalRecordCount = items.Count, + Items = items + }; + } +}