Skip to content

Commit

Permalink
add subject && episode relation for archive
Browse files Browse the repository at this point in the history
  • Loading branch information
kookxiang committed Oct 24, 2024
1 parent 198461c commit a9ba280
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 3 deletions.
3 changes: 3 additions & 0 deletions Jellyfin.Plugin.Bangumi/Archive/ArchiveData.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.IO;
using Jellyfin.Plugin.Bangumi.Archive.Data;
using Jellyfin.Plugin.Bangumi.Archive.Relation;
using MediaBrowser.Common.Configuration;

namespace Jellyfin.Plugin.Bangumi.Archive;
Expand All @@ -26,4 +27,6 @@ public class ArchiveData(IApplicationPaths paths)
public ArchiveStore<Episode> Episode => new(BasePath, "episode.jsonlines");

public ArchiveStore<Person> Person => new(BasePath, "person.jsonlines");

public SubjectEpisodeRelation SubjectEpisode => new(this);
}
18 changes: 18 additions & 0 deletions Jellyfin.Plugin.Bangumi/Archive/ArchiveStore.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -106,6 +107,23 @@ public IArchiveStore Fork(string newBasePath, string newFileName)
return new ArchiveStore<T>(newBasePath, newFileName);
}

public IEnumerable<T> Enumerate()
{
if (!Exists())
yield break;

using var reader = new StreamReader(FilePath, Encoding.UTF8);
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (line == null)
continue;
if (!LineIdRegex().IsMatch(line))
continue;
yield return JsonSerializer.Deserialize<T>(line, Constants.JsonSerializerOptions)!;
}
}

public async Task<T?> FindById(int id)
{
if (!Exists())
Expand Down
90 changes: 90 additions & 0 deletions Jellyfin.Plugin.Bangumi/Archive/Relation/SubjectEpisodeRelation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Jellyfin.Plugin.Bangumi.Archive.Data;

namespace Jellyfin.Plugin.Bangumi.Archive.Relation;

public class SubjectEpisodeRelation(ArchiveData archive)
{
private const string FileName = "subject_episode.map";

private readonly Dictionary<int, List<int>> _mapping = new();

private bool _initialized;

private string FilePath => Path.Join(archive.BasePath, FileName);

public async Task GenerateIndex(CancellationToken token)
{
foreach (var episode in archive.Episode.Enumerate())
{
token.ThrowIfCancellationRequested();
if (!_mapping.ContainsKey(episode.ParentId))
_mapping[episode.ParentId] = [];
_mapping[episode.ParentId].Add(episode.Id);
}

await Save();
}

public async Task<bool> Ready()
{
await Load();
return _mapping.Count > 0;
}

public async Task<List<Episode>> GetEpisodes(int subjectId)
{
await Load();
if (!_mapping.TryGetValue(subjectId, out var idList)) return [];
var list = new List<Episode>();
foreach (var id in idList)
{
var episode = await archive.Episode.FindById(id);
if (episode != null)
list.Add(episode);
}

return list;
}

private async Task Load()
{
if (_initialized) return;
_initialized = true;

if (!File.Exists(FilePath)) return;
await using var fileStream = File.OpenRead(FilePath);
using var reader = new BinaryReader(fileStream);
while (reader.BaseStream.Position < reader.BaseStream.Length)
{
var subjectId = reader.ReadInt32();
var episodeCount = reader.ReadUInt16();
var episodeIdList = new List<int>(episodeCount);
for (var i = 0; i < episodeCount; i++)
episodeIdList.Add(reader.ReadInt32());
_mapping[subjectId] = episodeIdList;
}
}

private async Task Save()
{
var tempFileName = Path.GetRandomFileName();
var tempFilePath = Path.Join(archive.TempPath, tempFileName);
await using var outStream = File.OpenWrite(tempFilePath);
await using var writer = new BinaryWriter(outStream);
foreach (var (subjectId, episodeIdList) in _mapping)
{
writer.Write(subjectId);
writer.Write((ushort)episodeIdList.Count);
foreach (var episodeId in episodeIdList)
writer.Write(episodeId);
}

writer.Flush();
await outStream.FlushAsync();
File.Move(tempFilePath, FilePath, true);
}
}
18 changes: 16 additions & 2 deletions Jellyfin.Plugin.Bangumi/Providers/EpisodeProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,22 @@ private static bool IsSpecial(string filePath, bool checkParent = true)
}

SkipBangumiId:
log.LogInformation("searching episode in series episode list");
var episodeListData = await api.GetSubjectEpisodeList(seriesId, type, episodeIndex.Value, token);
List<Model.Episode>? episodeListData = null;
if (await archive.SubjectEpisode.Ready())
{
log.LogInformation("load subject {SubjectID} episode list from archive", seriesId);
episodeListData = (await archive.SubjectEpisode.GetEpisodes(seriesId))
.Where(x => x.Type == type || type == null)
.Select(x => x.ToEpisode())
.ToList();
}

if (episodeListData == null)
{
log.LogInformation("searching episode in series episode list");
episodeListData ??= await api.GetSubjectEpisodeList(seriesId, type, episodeIndex.Value, token);
}

if (episodeListData == null)
{
log.LogWarning("search failed: no episode found in episode");
Expand Down
4 changes: 3 additions & 1 deletion Jellyfin.Plugin.Bangumi/ScheduledTask/ArchiveDownloadTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ public async Task ExecuteAsync(IProgress<double> progress, CancellationToken tok
progress.Report(65D + 30D * ++completed / archive.Stores.Count);
}

await archive.SubjectEpisode.GenerateIndex(token);

log.LogInformation("update completed. cleaning up temp files");
Directory.Delete(archive.TempPath, true);
}
Expand All @@ -116,7 +118,7 @@ private async Task<ArchiveReleaseMeta> GetLatestArchiveMeta(CancellationToken to
using var response = await httpClient.GetAsync(ArchiveReleaseUrl, token);
response.EnsureSuccessStatusCode();
var jsonString = await response.Content.ReadAsStringAsync(token);
return JsonSerializer.Deserialize<ArchiveReleaseMeta>(jsonString)!;
return JsonSerializer.Deserialize<ArchiveReleaseMeta>(jsonString, Constants.JsonSerializerOptions)!;
}

public class ArchiveReleaseMeta
Expand Down

0 comments on commit a9ba280

Please sign in to comment.