Skip to content

Commit

Permalink
better special episode support #7
Browse files Browse the repository at this point in the history
  • Loading branch information
kookxiang committed Jun 19, 2022
1 parent 6fa481a commit 65ebd71
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
13 changes: 10 additions & 3 deletions Jellyfin.Plugin.Bangumi/BangumiApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public async Task<List<Subject>> SearchSubject(string keyword, CancellationToken
return Subject.SortBySimilarity(list, keyword);
}

public async Task<Subject?> GetSubject(int id, CancellationToken token)
{
return await GetSubject(id.ToString(), token);
}

public async Task<Subject?> GetSubject(string id, CancellationToken token)
{
var jsonString = await SendRequest($"https://api.bgm.tv/v0/subjects/{id}", token);
Expand All @@ -52,7 +57,7 @@ public async Task<List<Subject>> SearchSubject(string keyword, CancellationToken
return await GetSubjectEpisodeList(seriesId, EpisodeType.Normal, episodeNumber, token);
}

public async Task<List<Episode>?> GetSubjectEpisodeList(string seriesId, EpisodeType type, int episodeNumber, CancellationToken token)
public async Task<List<Episode>?> GetSubjectEpisodeList(string seriesId, EpisodeType? type, int episodeNumber, CancellationToken token)
{
var result = await GetSubjectEpisodeListWithOffset(seriesId, type, 0, token);
if (result == null)
Expand Down Expand Up @@ -98,9 +103,11 @@ public async Task<List<Subject>> SearchSubject(string keyword, CancellationToken
return result.Data;
}

public async Task<DataList<Episode>?> GetSubjectEpisodeListWithOffset(string seriesId, EpisodeType type, int offset, CancellationToken token)
public async Task<DataList<Episode>?> GetSubjectEpisodeListWithOffset(string seriesId, EpisodeType? type, int offset, CancellationToken token)
{
var url = $"https://api.bgm.tv/v0/episodes?subject_id={seriesId}&type={(int)type}&limit={PageSize}";
var url = $"https://api.bgm.tv/v0/episodes?subject_id={seriesId}&limit={PageSize}";
if (type != null)
url += $"&type={(int)type}";
if (offset > 0)
url += $"&offset={offset}";
var jsonString = await SendRequest(url, token);
Expand Down
2 changes: 1 addition & 1 deletion Jellyfin.Plugin.Bangumi/Model/Episode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class Episode
public double Index { get; set; }

[JsonPropertyName("airdate")]
public string? AirDate { get; set; }
public string AirDate { get; set; } = "";

public string? Duration { get; set; }

Expand Down
47 changes: 43 additions & 4 deletions Jellyfin.Plugin.Bangumi/Providers/EpisodeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.Bangumi.Model;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;

namespace Jellyfin.Plugin.Bangumi.Providers
{
Expand All @@ -34,7 +36,16 @@ public class EpisodeProvider : IRemoteMetadataProvider<Episode, EpisodeInfo>, IH
new(@"(\d{2,})")
};

private static readonly Regex[] SpecialEpisodeFileNameRegex = { new("Special"), new("OVA"), new("OAD") };
private static readonly Regex[] SpecialEpisodeFileNameRegex =
{
new("Special"),
new("OVA"),
new("OAD"),
new(@"SP\d+"),
new(@"PV\d+"),
new("(NC)?(OP|ED)")
};

private readonly BangumiApi _api;
private readonly ILibraryManager _libraryManager;
private readonly ILogger<EpisodeProvider> _log;
Expand All @@ -55,13 +66,23 @@ public EpisodeProvider(Plugin plugin, BangumiApi api, ILogger<EpisodeProvider> l
public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, CancellationToken token)
{
token.ThrowIfCancellationRequested();
EpisodeType? type = null;
Model.Episode? episode = null;
var result = new MetadataResult<Episode> { ResultLanguage = Constants.Language };

var fileName = Path.GetFileName(info.Path);
if (string.IsNullOrEmpty(fileName))
return result;

if (fileName.ToUpper().Contains("OP"))
type = EpisodeType.Opening;
else if (fileName.ToUpper().Contains("ED"))
type = EpisodeType.Ending;
else if (fileName.ToUpper().Contains("SP"))
type = EpisodeType.Special;
else if (fileName.ToUpper().Contains("PV"))
type = EpisodeType.Preview;

var seriesId = info.SeriesProviderIds?.GetValueOrDefault(Constants.ProviderName);

var parent = _libraryManager.FindByPath(Path.GetDirectoryName(info.Path), true);
Expand All @@ -80,7 +101,7 @@ public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, Cancell
{
episode = await _api.GetEpisode(episodeId, token);
if (episode != null)
if (!SpecialEpisodeFileNameRegex.Any(x => x.IsMatch(info.Path)))
if (episode.Type == EpisodeType.Normal && !SpecialEpisodeFileNameRegex.Any(x => x.IsMatch(info.Path)))
if ($"{episode.ParentId}" != seriesId)
{
_log.LogWarning("episode #{Episode} is not belong to series #{Series}, ignored", episodeId, seriesId);
Expand All @@ -101,10 +122,11 @@ public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, Cancell

if (episode == null)
{
var episodeListData = await _api.GetSubjectEpisodeList(seriesId, episodeIndex.Value, token);
var episodeListData = await _api.GetSubjectEpisodeList(seriesId, type, episodeIndex.Value, token);
if (episodeListData == null)
return result;
episodeIndex = GuessEpisodeNumber(episodeIndex, fileName, episodeListData.Max(episode => episode.Order));
if (type is null or EpisodeType.Normal)
episodeIndex = GuessEpisodeNumber(episodeIndex, fileName, episodeListData.Max(episode => episode.Order));
episode = episodeListData.Find(x => (int)x.Order == episodeIndex);
}

Expand All @@ -124,13 +146,30 @@ public async Task<MetadataResult<Episode>> GetMetadata(EpisodeInfo info, Cancell
result.Item.OriginalTitle = episode.OriginalName;
result.Item.IndexNumber = (int)episode.Order;
result.Item.Overview = episode.Description;
result.Item.ParentIndexNumber = 1;

if (parent is Season season)
{
result.Item.SeasonId = season.Id;
result.Item.ParentIndexNumber = season.IndexNumber;
}

if (episode.Type == EpisodeType.Normal)
return result;

// mark episode as special
result.Item.ParentIndexNumber = 0;

var series = await _api.GetSubject(episode.ParentId, token);
if (series == null)
return result;

var seasonNumber = parent is Season ? parent.IndexNumber : 1;
if (string.Compare(episode.AirDate, series.AirDate, StringComparison.Ordinal) < 0)
result.Item.AirsBeforeEpisodeNumber = seasonNumber;
else
result.Item.AirsAfterSeasonNumber = seasonNumber;

return result;
}

Expand Down

0 comments on commit 65ebd71

Please sign in to comment.