From 761e0e981638f82d0c13d04719d5fa289a873188 Mon Sep 17 00:00:00 2001 From: kookxiang Date: Mon, 23 Dec 2024 21:49:28 +0800 Subject: [PATCH] use archive data for nsfw check --- Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs | 103 ++++++------------- 1 file changed, 33 insertions(+), 70 deletions(-) diff --git a/Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs b/Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs index 7282621..1f34c38 100644 --- a/Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs +++ b/Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs @@ -10,46 +10,25 @@ using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Globalization; using Microsoft.Extensions.Hosting; using CollectionType = Jellyfin.Plugin.Bangumi.Model.CollectionType; namespace Jellyfin.Plugin.Bangumi; -public class PlaybackScrobbler : IHostedService +public class PlaybackScrobbler(IUserDataManager userDataManager, OAuthStore store, BangumiApi api, Logger log) + : IHostedService { - // https://github.com/jellyfin/jellyfin/blob/master/Emby.Server.Implementations/Localization/Ratings/jp.csv - // https://github.com/jellyfin/jellyfin/blob/master/Emby.Server.Implementations/Localization/Ratings/us.csv - private const int RatingNSFW = 10; - - private readonly BangumiApi _api; - private readonly ILocalizationManager _localizationManager; - private readonly Logger _log; - - private readonly OAuthStore _store; - private readonly IUserDataManager _userDataManager; - - public PlaybackScrobbler(IUserDataManager userDataManager, ILocalizationManager localizationManager, OAuthStore store, BangumiApi api, - Logger log) - { - _userDataManager = userDataManager; - _localizationManager = localizationManager; - _store = store; - _api = api; - _log = log; - } - private static PluginConfiguration Configuration => Plugin.Instance!.Configuration; public Task StopAsync(CancellationToken token) { - _userDataManager.UserDataSaved -= OnUserDataSaved; + userDataManager.UserDataSaved -= OnUserDataSaved; return Task.CompletedTask; } public Task StartAsync(CancellationToken token) { - _userDataManager.UserDataSaved += OnUserDataSaved; + userDataManager.UserDataSaved += OnUserDataSaved; return Task.CompletedTask; } @@ -79,22 +58,22 @@ private async Task ReportPlaybackStatus(BaseItem item, Guid userId, bool played) var localConfiguration = await LocalConfiguration.ForPath(item.Path); if (!int.TryParse(item.GetProviderId(Constants.ProviderName), out var episodeId)) { - _log.Info("item {Name} (#{Id}) doesn't have bangumi id, ignored", item.Name, item.Id); + log.Info("item {Name} (#{Id}) doesn't have bangumi id, ignored", item.Name, item.Id); return; } if (!int.TryParse(item.GetParent()?.GetProviderId(Constants.ProviderName), out var subjectId)) - _log.Warn("parent of item {Name} (#{Id}) doesn't have bangumi subject id", item.Name, item.Id); + log.Warn("parent of item {Name} (#{Id}) doesn't have bangumi subject id", item.Name, item.Id); if (!localConfiguration.Report) { - _log.Info("playback report is disabled via local configuration"); + log.Info("playback report is disabled via local configuration"); return; } if (item is Audio) { - _log.Info("audio playback report is not supported by bgm.tv, ignored"); + log.Info("audio playback report is not supported by bgm.tv, ignored"); return; } @@ -102,22 +81,22 @@ private async Task ReportPlaybackStatus(BaseItem item, Guid userId, bool played) { subjectId = (subjectId == 0) ? episodeId : subjectId; // jellyfin only have subject id for movie, so we need to get episode id from bangumi api - var episodeList = await _api.GetSubjectEpisodeListWithOffset(subjectId, EpisodeType.Normal, 0, CancellationToken.None); + var episodeList = await api.GetSubjectEpisodeListWithOffset(subjectId, EpisodeType.Normal, 0, CancellationToken.None); if (episodeList?.Data.Count > 0) episodeId = episodeList.Data.First().Id; } - _store.Load(); - var user = _store.Get(userId); + store.Load(); + var user = store.Get(userId); if (user == null) { - _log.Info("access token for user #{User} not found, ignored", userId); + log.Info("access token for user #{User} not found, ignored", userId); return; } if (user.Expired) { - _log.Info("access token for user #{User} expired, ignored", userId); + log.Info("access token for user #{User} expired, ignored", userId); return; } @@ -125,72 +104,56 @@ private async Task ReportPlaybackStatus(BaseItem item, Guid userId, bool played) { if (item is Book) { - _log.Info("report subject #{Subject} status {Status} to bangumi", episodeId, CollectionType.Watched); - await _api.UpdateCollectionStatus(user.AccessToken, episodeId, played ? CollectionType.Watched : CollectionType.Watching, + log.Info("report subject #{Subject} status {Status} to bangumi", episodeId, CollectionType.Watched); + await api.UpdateCollectionStatus(user.AccessToken, episodeId, played ? CollectionType.Watched : CollectionType.Watching, CancellationToken.None); } else { if (subjectId == 0) { - var episode = await _api.GetEpisode(episodeId, CancellationToken.None); + var episode = await api.GetEpisode(episodeId, CancellationToken.None); if (episode != null) subjectId = episode.ParentId; } - var ratingLevel = item.OfficialRating is null ? null : _localizationManager.GetRatingLevel(item.OfficialRating); - if (ratingLevel == null) - foreach (var parent in item.GetParents()) - { - if (parent.OfficialRating == null) continue; - - if (int.TryParse(parent.OfficialRating, out int digitalRating)) - { - // Brazil rating has digital rating level, up to 18 is not NSFW - ratingLevel = digitalRating >= 18 ? RatingNSFW : 0; - break; - } - - ratingLevel = _localizationManager.GetRatingLevel(parent.OfficialRating); - if (ratingLevel != null) break; - } - - if (ratingLevel != null && ratingLevel >= RatingNSFW && Configuration.SkipNSFWPlaybackReport) + var subject = await api.GetSubject(subjectId, CancellationToken.None); + if (subject?.IsNSFW == true && Configuration.SkipNSFWPlaybackReport) { - _log.Info("item #{Name} marked as NSFW, skipped", item.Name); + log.Info("item #{Name} marked as NSFW, skipped", item.Name); return; } - var episodeStatus = await _api.GetEpisodeStatus(user.AccessToken, episodeId, CancellationToken.None); + var episodeStatus = await api.GetEpisodeStatus(user.AccessToken, episodeId, CancellationToken.None); if (episodeStatus?.Type == EpisodeCollectionType.Watched) { - _log.Info("item {Name} (#{Id}) has been marked as watched before, ignored", item.Name, + log.Info("item {Name} (#{Id}) has been marked as watched before, ignored", item.Name, item.Id); return; } - _log.Info("report episode #{Episode} status {Status} to bangumi", episodeId, + log.Info("report episode #{Episode} status {Status} to bangumi", episodeId, played ? EpisodeCollectionType.Watched : EpisodeCollectionType.Default); - await _api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, + await api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, played ? EpisodeCollectionType.Watched : EpisodeCollectionType.Default, CancellationToken.None); } - _log.Info("report completed"); + log.Info("report completed"); } catch (Exception e) { if (played && e.Message == "Bad Request: you need to add subject to your collection first") { - _log.Info("report subject #{Subject} status {Status} to bangumi", subjectId, CollectionType.Watching); - await _api.UpdateCollectionStatus(user.AccessToken, subjectId, CollectionType.Watching, CancellationToken.None); + log.Info("report subject #{Subject} status {Status} to bangumi", subjectId, CollectionType.Watching); + await api.UpdateCollectionStatus(user.AccessToken, subjectId, CollectionType.Watching, CancellationToken.None); - _log.Info("report episode #{Episode} status {Status} to bangumi", episodeId, EpisodeCollectionType.Watched); - await _api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, + log.Info("report episode #{Episode} status {Status} to bangumi", episodeId, EpisodeCollectionType.Watched); + await api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, played ? EpisodeCollectionType.Watched : EpisodeCollectionType.Default, CancellationToken.None); } else { - _log.Error("report playback status failed: {Error}", e); + log.Error("report playback status failed: {Error}", e); } } @@ -198,11 +161,11 @@ await _api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, if (played && item is not Book) { // skip if episode type not normal - var episode = await _api.GetEpisode(episodeId, CancellationToken.None); + var episode = await api.GetEpisode(episodeId, CancellationToken.None); if (episode is { Type: EpisodeType.Normal }) { // check each episode status - var epList = await _api.GetEpisodeCollectionInfo(user.AccessToken, subjectId, (int)EpisodeType.Normal, + var epList = await api.GetEpisodeCollectionInfo(user.AccessToken, subjectId, (int)EpisodeType.Normal, CancellationToken.None); if (epList is { Total: > 0 }) { @@ -213,8 +176,8 @@ await _api.UpdateEpisodeStatus(user.AccessToken, subjectId, episodeId, }); if (subjectPlayed) { - _log.Info("report subject #{Subject} status {Status} to bangumi", subjectId, CollectionType.Watched); - await _api.UpdateCollectionStatus(user.AccessToken, subjectId, CollectionType.Watched, CancellationToken.None); + log.Info("report subject #{Subject} status {Status} to bangumi", subjectId, CollectionType.Watched); + await api.UpdateCollectionStatus(user.AccessToken, subjectId, CollectionType.Watched, CancellationToken.None); } } }