Skip to content

Commit

Permalink
refactor: let's start fixing stuff
Browse files Browse the repository at this point in the history
by first breaking it, then fixing it afterwards.

also, don't mind the code for the incomplete collection manager. I
still haven't finished the minute details yet.
  • Loading branch information
revam committed Mar 24, 2024
1 parent 5817893 commit db47d80
Show file tree
Hide file tree
Showing 18 changed files with 1,059 additions and 622 deletions.
21 changes: 16 additions & 5 deletions Shokofin/API/Info/ShowInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ public class ShowInfo
{
public string? Id;

public string? ParentId;

public string Name;

public bool IsStandalone;
public bool IsStandalone =>
Shoko == null;

public Group? Shoko;

public string[] Tags;

Expand All @@ -33,8 +38,8 @@ public class ShowInfo
public ShowInfo(Series series)
{
Id = null;
ParentId = series.IDs.ParentGroup.ToString();
Name = series.Name;
IsStandalone = true;
Tags = System.Array.Empty<string>();
Genres = System.Array.Empty<string>();
Studios = System.Array.Empty<string>();
Expand All @@ -48,7 +53,8 @@ public ShowInfo(Group group)
{
Id = group.IDs.Shoko.ToString();
Name = group.Name;
IsStandalone = false;
Shoko = group;
ParentId = group.IDs.ParentGroup?.ToString();
Tags = System.Array.Empty<string>();
Genres = System.Array.Empty<string>();
Studios = System.Array.Empty<string>();
Expand All @@ -68,8 +74,9 @@ public ShowInfo(SeasonInfo seasonInfo)
if (seasonInfo.OthersList.Count > 0)
seasonOrderDictionary.Add(++seasonNumberOffset, seasonInfo);

Id = null;
ParentId = seasonInfo.Shoko.IDs.ParentGroup.ToString();
Name = seasonInfo.Shoko.Name;
IsStandalone = true;
Tags = seasonInfo.Tags;
Genres = seasonInfo.Genres;
Studios = seasonInfo.Studios;
Expand Down Expand Up @@ -140,7 +147,8 @@ public ShowInfo(Group group, List<SeasonInfo> seriesList, Ordering.GroupFilterTy

Id = groupId;
Name = seriesList.Count > 0 ? seriesList[foundIndex].Shoko.Name : group.Name;
IsStandalone = false;
Shoko = group;
ParentId = group.IDs.ParentGroup?.ToString();
Tags = seriesList.SelectMany(s => s.Tags).Distinct().ToArray();
Genres = seriesList.SelectMany(s => s.Genres).Distinct().ToArray();
Studios = seriesList.SelectMany(s => s.Studios).Distinct().ToArray();
Expand All @@ -151,6 +159,9 @@ public ShowInfo(Group group, List<SeasonInfo> seriesList, Ordering.GroupFilterTy
}

public SeasonInfo? GetSeriesInfoBySeasonNumber(int seasonNumber) {
if (Plugin.Instance.Configuration.SeriesGrouping is Ordering.GroupType.Default && seasonNumber is 123 or 124)
return SeasonList.FirstOrDefault();

if (seasonNumber == 0 || !(SeasonOrderDictionary.TryGetValue(seasonNumber, out var seasonInfo) && seasonInfo != null))
return null;

Expand Down
2 changes: 0 additions & 2 deletions Shokofin/API/Models/Group.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ public class Group

public class GroupIDs : IDs
{
public int? DefaultSeries { get; set; }

public int MainSeries { get; set; }

public int? ParentGroup { get; set; }
Expand Down
5 changes: 3 additions & 2 deletions Shokofin/API/ShokoAPIClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,10 @@ public Task<List<File>> GetFileByPath(string path)
return Get<List<File>>($"/api/v3/File/PathEndsWith?path={Uri.EscapeDataString(path)}&includeDataFrom=AniDB&limit=1");
}

public Task<ListResult<File>> GetFilesForSeries(string seriesId)
public async Task<IReadOnlyList<File>> GetFilesForSeries(string seriesId)
{
return Get<ListResult<File>>($"/api/v3/Series/{seriesId}/File?pageSize=0&include=XRefs&includeDataFrom=AniDB");
var listResult = await Get<ListResult<File>>($"/api/v3/Series/{seriesId}/File?pageSize=0&include=XRefs&includeDataFrom=AniDB");
return listResult.List;
}

public async Task<IReadOnlyList<File>> GetFilesForImportFolder(int importFolderId)
Expand Down
111 changes: 89 additions & 22 deletions Shokofin/API/ShokoAPIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ public void Clear()
Logger.LogDebug("Clearing data…");
Dispose();
Logger.LogDebug("Initialising new cache…");
DataCache = (new MemoryCache((new MemoryCacheOptions() {
DataCache = new MemoryCache(new MemoryCacheOptions() {
ExpirationScanFrequency = ExpirationScanFrequency,
})));
});
Logger.LogDebug("Cleanup complete.");
}

Expand Down Expand Up @@ -302,7 +302,7 @@ public HashSet<string> GetLocalEpisodeIdsForSeries(string seriesId)

var pathSet = new HashSet<string>();
var episodeIds = new HashSet<string>();
foreach (var file in (await APIClient.GetFilesForSeries(seriesId) ?? new ()).List) {
foreach (var file in await APIClient.GetFilesForSeries(seriesId)) {
if (file.CrossReferences.Count == 1)
foreach (var fileLocation in file.Locations)
pathSet.Add((Path.GetDirectoryName(fileLocation.Path) ?? "") + Path.DirectorySeparatorChar);
Expand All @@ -318,17 +318,58 @@ public HashSet<string> GetLocalEpisodeIdsForSeries(string seriesId)
#endregion
#region File Info

public async Task<(FileInfo?, SeasonInfo?, ShowInfo?)> GetFileInfoByPath(string path, Ordering.GroupFilterType? filterGroupByType)
internal void AddFileLookupIds(string path, string fileId, string seriesId, IEnumerable<string> episodeIds)
{
PathToFileIdAndSeriesIdDictionary.TryAdd(path, (fileId, seriesId));
PathToEpisodeIdsDictionary.TryAdd(path, episodeIds.ToList());
}

public async Task<(FileInfo?, SeasonInfo?, ShowInfo?)> GetFileInfoByPath(string path, Ordering.GroupFilterType filterGroupByType)
{
// Use pointer for fast lookup.
if (PathToFileIdAndSeriesIdDictionary.ContainsKey(path)) {
var (fI, sI) = PathToFileIdAndSeriesIdDictionary[path];
var fileInfo = await GetFileInfo(fI, sI);
if (fileInfo == null)
return (null, null, null);

var seasonInfo = await GetSeasonInfoForSeries(sI);
var showInfo = filterGroupByType.HasValue ? await GetShowInfoForSeries(sI, filterGroupByType.Value) : null;
if (seasonInfo == null)
return (null, null, null);

var showInfo = await GetShowInfoForSeries(sI, filterGroupByType);
if (showInfo == null)
return (null, null, null);

return new(fileInfo, seasonInfo, showInfo);
}

// Fast-path for VFS.
if (path.StartsWith(Plugin.Instance.VirtualRoot + Path.DirectorySeparatorChar)) {
var (seriesSegment, fileSegment) = Path.GetFileNameWithoutExtension(path).Split('[').TakeLast(2).Select(a => a.Split(']').First()).ToList();
if (!int.TryParse(seriesSegment.Split('-').LastOrDefault(), out var seriesIdRaw))
return (null, null, null);
if (!int.TryParse(fileSegment.Split('-').LastOrDefault(), out var fileIdRaw))
return (null, null, null);

var sI = seriesIdRaw.ToString();
var fI = fileIdRaw.ToString();
var fileInfo = await GetFileInfo(fI, sI);
if (fileInfo == null)
return (null, null, null);

var seasonInfo = await GetSeasonInfoForSeries(sI);
if (seasonInfo == null)
return (null, null, null);

var showInfo = await GetShowInfoForSeries(sI, filterGroupByType);
if (showInfo == null)
return (null, null, null);

AddFileLookupIds(path, fI, sI, fileInfo.EpisodeList.Select(episode => episode.Id));
return (fileInfo, seasonInfo, showInfo);
}

// Strip the path and search for a match.
var partialPath = StripMediaFolder(path);
var result = await APIClient.GetFileByPath(partialPath);
Expand Down Expand Up @@ -366,12 +407,9 @@ public HashSet<string> GetLocalEpisodeIdsForSeries(string seriesId)
continue;

// Find the show info.
ShowInfo? showInfo = null;
if (filterGroupByType.HasValue) {
showInfo = await GetShowInfoForSeries(seriesId, filterGroupByType.Value);
if (showInfo == null)
return (null, null, null);
}
var showInfo = await GetShowInfoForSeries(seriesId, filterGroupByType);
if (showInfo == null || showInfo.SeasonList.Count == 0)
return (null, null, null);

// Find the season info.
var seasonInfo = await GetSeasonInfoForSeries(seriesId);
Expand All @@ -386,8 +424,7 @@ public HashSet<string> GetLocalEpisodeIdsForSeries(string seriesId)
EpisodeIdToEpisodePathDictionary.TryAdd(episodeInfo.Id, path);

// Add pointers for faster lookup.
PathToFileIdAndSeriesIdDictionary.TryAdd(path, (fileId, seriesId));
PathToEpisodeIdsDictionary.TryAdd(path, fileInfo.EpisodeList.Select(episode => episode.Id).ToList());
AddFileLookupIds(path, fileId, seriesId, fileInfo.EpisodeList.Select(episode => episode.Id));

// Return the result.
return new(fileInfo, seasonInfo, showInfo);
Expand Down Expand Up @@ -626,7 +663,7 @@ private async Task<SeasonInfo> CreateSeriesInfo(Series series, string seriesId)
seasonInfo = new SeasonInfo(series, episodes, cast, relations, genres, tags);

foreach (var episode in episodes)
EpisodeIdToSeriesIdDictionary[episode.Id] = seriesId;
EpisodeIdToSeriesIdDictionary.TryAdd(episode.Id, seriesId);
DataCache.Set<SeasonInfo>(cacheKey, seasonInfo, DefaultTimeSpan);
return seasonInfo;
}
Expand Down Expand Up @@ -688,6 +725,19 @@ public bool TryGetGroupIdForSeriesId(string seriesId, out string? groupId, out s
if (PathToSeriesIdDictionary.TryGetValue(path, out var seriesId))
return seriesId;

// Fast-path for VFS.
if (path.StartsWith(Plugin.Instance.VirtualRoot + Path.DirectorySeparatorChar)) {
var seriesSegment = Path.GetFileName(path).Split('[').Last().Split(']').First();
if (!int.TryParse(seriesSegment.Split('-').LastOrDefault(), out var seriesIdRaw))
return null;

seriesId = seriesIdRaw.ToString();
PathToSeriesIdDictionary[path] = seriesId;
SeriesIdToPathDictionary.TryAdd(seriesId, path);

return seriesId;
}

var partialPath = StripMediaFolder(path);
Logger.LogDebug("Looking for shoko series matching path {Path}", partialPath);
var result = await APIClient.GetSeriesPathEndsWith(partialPath);
Expand Down Expand Up @@ -720,7 +770,7 @@ public bool TryGetGroupIdForSeriesId(string seriesId, out string? groupId, out s
#endregion
#region Show Info

public async Task<ShowInfo?> GetShowInfoByPath(string path, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<ShowInfo?> GetShowInfoByPath(string path, Ordering.GroupFilterType filterByType)
{
if (PathToSeriesIdDictionary.TryGetValue(path, out var seriesId)) {
if (SeriesIdToGroupIdDictionary.TryGetValue(seriesId, out var tuple)) {
Expand All @@ -740,7 +790,24 @@ public bool TryGetGroupIdForSeriesId(string seriesId, out string? groupId, out s
return await GetShowInfoForSeries(seriesId, filterByType);
}

public async Task<ShowInfo?> GetShowInfoForSeries(string seriesId, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<ShowInfo?> GetShowInfoForEpisode(string episodeId, Ordering.GroupFilterType filterByType)
{
if (string.IsNullOrEmpty(episodeId))
return null;

if (EpisodeIdToSeriesIdDictionary.TryGetValue(episodeId, out var seriesId))
return await GetShowInfoForSeries(seriesId, filterByType);

var series = await APIClient.GetSeriesFromEpisode(episodeId);
if (series == null)
return null;

seriesId = series.IDs.Shoko.ToString();
EpisodeIdToSeriesIdDictionary.TryAdd(episodeId, seriesId);
return await GetShowInfoForSeries(seriesId, filterByType);
}

public async Task<ShowInfo?> GetShowInfoForSeries(string seriesId, Ordering.GroupFilterType filterByType)
{
if (string.IsNullOrEmpty(seriesId))
return null;
Expand All @@ -764,7 +831,7 @@ public bool TryGetGroupIdForSeriesId(string seriesId, out string? groupId, out s
return await CreateShowInfo(group, group.IDs.Shoko.ToString(), filterByType);
}

private async Task<ShowInfo?> GetShowInfoForGroup(string groupId, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
private async Task<ShowInfo?> GetShowInfoForGroup(string groupId, Ordering.GroupFilterType filterByType)
{
if (string.IsNullOrEmpty(groupId))
return null;
Expand Down Expand Up @@ -812,7 +879,7 @@ private async Task<ShowInfo> CreateShowInfo(Group group, string groupId, Orderin
return showInfo;
}

private async Task<ShowInfo?> GetOrCreateShowInfoForStandaloneSeries(string seriesId, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
private async Task<ShowInfo?> GetOrCreateShowInfoForStandaloneSeries(string seriesId, Ordering.GroupFilterType filterByType)
{
var cacheKey = $"show:{filterByType}:by-series-id:{seriesId}";
if (DataCache.TryGetValue<ShowInfo>(cacheKey, out var showInfo)) {
Expand Down Expand Up @@ -847,7 +914,7 @@ private async Task<ShowInfo> CreateShowInfo(Group group, string groupId, Orderin
#endregion
#region Collection Info

public async Task<CollectionInfo?> GetCollectionInfoByPath(string path, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<CollectionInfo?> GetCollectionInfoByPath(string path, Ordering.GroupFilterType filterByType)
{
if (PathToSeriesIdDictionary.TryGetValue(path, out var seriesId)) {
if (SeriesIdToCollectionIdDictionary.TryGetValue(seriesId, out var groupId)) {
Expand All @@ -867,7 +934,7 @@ private async Task<ShowInfo> CreateShowInfo(Group group, string groupId, Orderin
return await GetCollectionInfoForGroup(seriesId, filterByType);
}

public async Task<CollectionInfo?> GetCollectionInfoBySeriesName(string seriesName, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<CollectionInfo?> GetCollectionInfoBySeriesName(string seriesName, Ordering.GroupFilterType filterByType)
{
if (NameToSeriesIdDictionary.TryGetValue(seriesName, out var seriesId)) {
if (SeriesIdToCollectionIdDictionary.TryGetValue(seriesId, out var groupId)) {
Expand All @@ -887,7 +954,7 @@ private async Task<ShowInfo> CreateShowInfo(Group group, string groupId, Orderin
return await GetCollectionInfoForSeries(seriesId, filterByType);
}

public async Task<CollectionInfo?> GetCollectionInfoForGroup(string groupId, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<CollectionInfo?> GetCollectionInfoForGroup(string groupId, Ordering.GroupFilterType filterByType)
{
if (string.IsNullOrEmpty(groupId))
return null;
Expand All @@ -901,7 +968,7 @@ private async Task<ShowInfo> CreateShowInfo(Group group, string groupId, Orderin
return await CreateCollectionInfo(group, groupId, filterByType);
}

public async Task<CollectionInfo?> GetCollectionInfoForSeries(string seriesId, Ordering.GroupFilterType filterByType = Ordering.GroupFilterType.Default)
public async Task<CollectionInfo?> GetCollectionInfoForSeries(string seriesId, Ordering.GroupFilterType filterByType)
{
if (string.IsNullOrEmpty(seriesId))
return null;
Expand Down
Loading

0 comments on commit db47d80

Please sign in to comment.