Основные изменения: укрупнены use case-интерфейсы, контроллеры переведены на цельные зависимости, логика доступных фильмов перенесена в FilmLibraryService, добавлены проверки существования фильма и улучшена обработка ошибок API. Метрики: FilmService больше не зависит напрямую от Micrometer для counters, используется BusinessMetricsPort; добавлены TimedAspect и duration-метрики через @Timed для create/edit/delete фильмов. Jellyfin: event handling переведен на транзакционную модель, sync учитывает runtime-ошибки, добавлены plugin-token/web-url настройки, webhook и sync endpoints защищены X-MovieNight-Plugin-Token. Плагин: добавлен Jellyfin plugin в plugins/jellyfin, backend принимает push-sync payload, sync-state доступен плагину, pull-sync вынесен в /api/integrations/jellyfin/pull-sync, README описывает фактический контракт. API и DTO: добавлены RecommendationResponse, ContentTypeParser, validation annotations, обработка validation errors и ResponseStatusException, endpoint /api/users/me. БД: добавлена V7 cleanup-миграция для legacy ratings/jellyfin_id объектов; V4/V5 в этот коммит не включались. Проверка: .\gradlew.bat check --stacktrace проходит полностью.
MovieNight Jellyfin Plugin
Thin Jellyfin server plugin for bridging Jellyfin playback/sync signals to the MovieNight backend.
Build
cd plugins/jellyfin/Jellyfin.Plugin.MovieNight
dotnet publish -c Release
Install the published net9.0 plugin files into the Jellyfin data directory under plugins/MovieNight/, then restart Jellyfin. This build targets Jellyfin 10.11.x.
Backend Contract Used
Current implemented calls:
POST /api/integrations/jellyfin/syncGET /api/integrations/jellyfin/sync-statePOST /api/integrations/jellyfin/events
Event requests use JSON with:
event_idevent_typeoccurred_atjellyfin_user_iditem_idpayload_versionpayload
The plugin sends X-MovieNight-Plugin-Token when configured. Completed Jellyfin playback stop events are sent as playback.stopped. Transient event push failures are retried three times with the same event_id.
The config page test action posts a small synthetic event to /api/integrations/jellyfin/events and treats 200 as success and 401 as token/config failure.
Sync requests use JSON with:
itemsitems[].jellyfinItemIditems[].titleitems[].descriptionitems[].yearitems[].genresitems[].imdbIditems[].userStatesitems[].userStates[].jellyfinUserIditems[].userStates[].isVieweditems[].userStates[].lastPlayedAt