Skip to content

Commit

Permalink
use archive data for nsfw check
Browse files Browse the repository at this point in the history
  • Loading branch information
kookxiang committed Dec 23, 2024
1 parent bd74b24 commit 761e0e9
Showing 1 changed file with 33 additions and 70 deletions.
103 changes: 33 additions & 70 deletions Jellyfin.Plugin.Bangumi/PlaybackScrobbler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PlaybackScrobbler> 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<PlaybackScrobbler> _log;

private readonly OAuthStore _store;
private readonly IUserDataManager _userDataManager;

public PlaybackScrobbler(IUserDataManager userDataManager, ILocalizationManager localizationManager, OAuthStore store, BangumiApi api,
Logger<PlaybackScrobbler> 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;
}

Expand Down Expand Up @@ -79,130 +58,114 @@ 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;
}

if (item is Movie)
{
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;
}

try
{
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);
}
}

// report subject status watched
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 })
{
Expand All @@ -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);
}
}
}
Expand Down

0 comments on commit 761e0e9

Please sign in to comment.