Refactor Jellyfin plugin: integrate UI components and implement backend contract.

- Integrated "Recommend Film" button and Rating UI into Jellyfin web interface via MutationObserver.
- Implemented full library sync (metadata + user state) in MovieNightSyncService.
- Updated MovieNightBackendClient to support sync, recommendations, ratings, and viewed status.
- Added proxy endpoints to MovieNightController for frontend-backend communication.
- Refined sync logic to handle large libraries and ensured .NET 9.0 compatibility.

Co-authored-by: devitq <118541411+devitq@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-05-20 17:35:48 +00:00
co-authored by devitq
parent 73b8e4ee02
commit 0a90c3eadf
10 changed files with 344 additions and 11 deletions
@@ -1,6 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Jellyfin.Data.Enums;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -11,19 +19,17 @@ namespace Jellyfin.Plugin.MovieNight.Services;
/// </summary>
public sealed class MovieNightPeriodicSyncService : BackgroundService
{
private readonly MovieNightBackendClient _backendClient;
private readonly MovieNightSyncService _syncService;
private readonly ILogger<MovieNightPeriodicSyncService> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="MovieNightPeriodicSyncService"/> class.
/// </summary>
/// <param name="backendClient">Backend client.</param>
/// <param name="logger">Logger.</param>
public MovieNightPeriodicSyncService(
MovieNightBackendClient backendClient,
MovieNightSyncService syncService,
ILogger<MovieNightPeriodicSyncService> logger)
{
_backendClient = backendClient;
_syncService = syncService;
_logger = logger;
}
@@ -41,7 +47,7 @@ public sealed class MovieNightPeriodicSyncService : BackgroundService
continue;
}
await _backendClient.TriggerSyncAsync(stoppingToken).ConfigureAwait(false);
await _syncService.PerformSyncAsync(stoppingToken).ConfigureAwait(false);
}
catch (OperationCanceledException) when (stoppingToken.IsCancellationRequested)
{