Skip to content

Commit

Permalink
feat: add release management missing episodes controller
Browse files Browse the repository at this point in the history
  • Loading branch information
revam committed Dec 14, 2024
1 parent fad746d commit b7f0356
Show file tree
Hide file tree
Showing 8 changed files with 237 additions and 48 deletions.
14 changes: 7 additions & 7 deletions Shoko.Server/API/v3/Controllers/ReleaseManagementController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,20 @@ public class ReleaseManagementController(ISettingsProvider settingsProvider) : B
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Series")]
public ActionResult<ListResult<Series.WithMultipleReleasesResult>> GetSeriesWithMultipleReleases(
public ActionResult<ListResult<Series.WithEpisodeCount>> GetSeriesWithMultipleReleases(
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool ignoreVariations = true,
[FromQuery] bool onlyFinishedSeries = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
IEnumerable<SVR_AnimeSeries> enumerable = RepoFactory.AnimeSeries.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeSeries.GetWithMultipleReleases(ignoreVariations);
if (onlyFinishedSeries) enumerable = enumerable.Where(a => a.AniDB_Anime.GetFinishedAiring());

return enumerable
.OrderBy(series => series.PreferredTitle)
.ThenBy(series => series.AniDB_ID)
.ToListResult(series => new Series.WithMultipleReleasesResult(series, User.JMMUserID, includeDataFrom, ignoreVariations), page, pageSize);
.ToListResult(series => new Series.WithEpisodeCount(RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID).Count(), series, User.JMMUserID, includeDataFrom), page, pageSize);
}

/// <summary>
Expand Down Expand Up @@ -81,7 +81,7 @@ public ActionResult<ListResult<Episode>> GetEpisodesForSeries(
if (!User.AllowedSeries(series))
return new ListResult<Episode>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
Expand Down Expand Up @@ -110,7 +110,7 @@ public ActionResult<ListResult<Episode>> GetEpisodes(
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
Expand All @@ -136,7 +136,7 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
if (!User.AllowedSeries(series))
return new List<int>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.SelectMany(episode =>
Expand All @@ -163,7 +163,7 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
[FromQuery] bool ignoreVariations = true
)
{
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);

return enumerable
.SelectMany(episode =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public ActionResult<List<FileIdSet>> GetFileIdsWithPreference()
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Series")]
public ActionResult<ListResult<Series.WithDuplicateFilesResult>> GetSeriesWithDuplicateFiles(
public ActionResult<ListResult<Series.WithEpisodeCount>> GetSeriesWithDuplicateFiles(
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool onlyFinishedSeries = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
Expand All @@ -96,7 +96,7 @@ public ActionResult<List<FileIdSet>> GetFileIdsWithPreference()
return enumerable
.OrderBy(series => series.PreferredTitle)
.ThenBy(series => series.AniDB_ID)
.ToListResult(series => new Series.WithDuplicateFilesResult(series, User.JMMUserID, includeDataFrom), page, pageSize);
.ToListResult(series => new Series.WithEpisodeCount(RepoFactory.AnimeEpisode.GetWithDuplicateFiles(series.AniDB_ID).Count(), series, User.JMMUserID, includeDataFrom), page, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Shoko.Commons.Extensions;
using Shoko.Server.API.Annotations;
using Shoko.Server.API.ModelBinders;
using Shoko.Server.API.v3.Helpers;
using Shoko.Server.API.v3.Models.Common;
using Shoko.Server.API.v3.Models.Shoko;
using Shoko.Server.Repositories;
using Shoko.Server.Settings;

#pragma warning disable CA1822
namespace Shoko.Server.API.v3.Controllers;

[ApiController]
[Route("/api/v{version:apiVersion}/ReleaseManagement/MissingEpisodes")]
[ApiV3]
public class ReleaseManagementMissingEpisodesController(ISettingsProvider settingsProvider) : BaseController(settingsProvider)
{
/// <summary>
/// Get missing episodes, be it collecting or otherwise.
/// </summary>
/// <param name="includeDataFrom">Include data from selected <see cref="DataSource"/>s.</param>
/// <param name="includeFiles">Include files with the episodes.</param>
/// <param name="includeMediaInfo">Include media info data.</param>
/// <param name="includeAbsolutePaths">Include absolute paths for the file locations.</param>
/// <param name="includeXRefs">Include file/episode cross-references with the episodes.</param>
/// <param name="collecting">Only show missing episodes from release groups we're collecting.</param>
/// <param name="pageSize">Limits the number of results per page. Set to 0 to disable the limit.</param>
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Episodes")]
public ActionResult<ListResult<Episode>> GetEpisodes(
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool includeFiles = true,
[FromQuery] bool includeMediaInfo = true,
[FromQuery] bool includeAbsolutePaths = false,
[FromQuery] bool includeXRefs = false,
[FromQuery] bool collecting = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
var enumerable = RepoFactory.AnimeEpisode.GetMissing(collecting);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
}

/// <summary>
/// Get series with missing episodes, collecting or otherwise.
/// </summary>
/// <param name="includeDataFrom">Include data from selected <see cref="DataSource"/>s.</param>
/// <param name="collecting">Only show series with missing episodes from release groups we're collecting.</param>
/// <param name="onlyFinishedSeries">Only show finished series.</param>
/// <param name="pageSize">Limits the number of results per page. Set to 0 to disable the limit.</param>
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Series")]
public ActionResult<ListResult<Series.WithEpisodeCount>> GetSeriesWithMultipleReleases(
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool collecting = false,
[FromQuery] bool onlyFinishedSeries = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
var enumerable = RepoFactory.AnimeSeries.GetWithMissingEpisodes(collecting);
if (onlyFinishedSeries)
enumerable = enumerable.Where(a => a.AniDB_Anime.GetFinishedAiring());

return enumerable
.OrderBy(series => series.PreferredTitle)
.ThenBy(series => series.AniDB_ID)
.ToListResult(series => new Series.WithEpisodeCount(collecting ? series.MissingEpisodeCountGroups : series.MissingEpisodeCount, series, User.JMMUserID, includeDataFrom), page, pageSize);
}

/// <summary>
/// Get missing episodes, be it collecting or otherwise, for a specific series.
/// </summary>
/// <param name="seriesID">Shoko Series ID</param>
/// <param name="includeDataFrom">Include data from selected <see cref="DataSource"/>s.</param>
/// <param name="includeFiles">Include files with the episodes.</param>
/// <param name="includeMediaInfo">Include media info data.</param>
/// <param name="includeAbsolutePaths">Include absolute paths for the file locations.</param>
/// <param name="includeXRefs">Include file/episode cross-references with the episodes.</param>
/// <param name="collecting">Only show missing episodes from release groups we're collecting.</param>
/// <param name="pageSize">Limits the number of results per page. Set to 0 to disable the limit.</param>
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Series/{seriesID}/Episodes")]
public ActionResult<ListResult<Episode>> GetEpisodesForSeries(
[FromRoute, Range(1, int.MaxValue)] int seriesID,
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool includeFiles = true,
[FromQuery] bool includeMediaInfo = true,
[FromQuery] bool includeAbsolutePaths = false,
[FromQuery] bool includeXRefs = false,
[FromQuery] bool collecting = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
var series = RepoFactory.AnimeSeries.GetByID(seriesID);
if (series == null)
return new ListResult<Episode>();

if (!User.AllowedSeries(series))
return new ListResult<Episode>();

var enumerable = RepoFactory.AnimeEpisode.GetMissing(collecting, series.AniDB_ID);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ActionResult<ListResult<Episode>> GetEpisodes(
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
Expand All @@ -61,7 +61,7 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
[FromQuery] bool ignoreVariations = true
)
{
IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations);

return enumerable
.SelectMany(episode =>
Expand All @@ -87,21 +87,21 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
/// <param name="page">Page number.</param>
/// <returns></returns>
[HttpGet("Series")]
public ActionResult<ListResult<Series.WithMultipleReleasesResult>> GetSeriesWithMultipleReleases(
public ActionResult<ListResult<Series.WithEpisodeCount>> GetSeriesWithMultipleReleases(
[FromQuery, ModelBinder(typeof(CommaDelimitedModelBinder))] HashSet<DataSource> includeDataFrom = null,
[FromQuery] bool ignoreVariations = true,
[FromQuery] bool onlyFinishedSeries = false,
[FromQuery, Range(0, 1000)] int pageSize = 100,
[FromQuery, Range(1, int.MaxValue)] int page = 1)
{
IEnumerable<SVR_AnimeSeries> enumerable = RepoFactory.AnimeSeries.GetWithMultipleReleases(ignoreVariations);
var enumerable = RepoFactory.AnimeSeries.GetWithMultipleReleases(ignoreVariations);
if (onlyFinishedSeries)
enumerable = enumerable.Where(a => a.AniDB_Anime.GetFinishedAiring());

return enumerable
.OrderBy(series => series.PreferredTitle)
.ThenBy(series => series.AniDB_ID)
.ToListResult(series => new Series.WithMultipleReleasesResult(series, User.JMMUserID, includeDataFrom, ignoreVariations), page, pageSize);
.ToListResult(series => new Series.WithEpisodeCount(RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID).Count(), series, User.JMMUserID, includeDataFrom), page, pageSize);
}

/// <summary>
Expand Down Expand Up @@ -136,7 +136,7 @@ public ActionResult<ListResult<Episode>> GetEpisodesForSeries(
if (!User.AllowedSeries(series))
return new ListResult<Episode>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.ToListResult(episode => new Episode(HttpContext, episode, includeDataFrom, includeFiles, includeMediaInfo, includeAbsolutePaths, includeXRefs), page, pageSize);
Expand All @@ -162,7 +162,7 @@ public ActionResult<List<int>> GetFileIdsWithPreference(
if (!User.AllowedSeries(series))
return new List<int>();

IEnumerable<SVR_AnimeEpisode> enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);
var enumerable = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, series.AniDB_ID);

return enumerable
.SelectMany(episode =>
Expand Down
23 changes: 3 additions & 20 deletions Shoko.Server/API/v3/Models/Shoko/Series.cs
Original file line number Diff line number Diff line change
Expand Up @@ -838,34 +838,17 @@ public SearchResult(SeriesSearch.SearchResult<SVR_AnimeSeries> result, int userI
/// <summary>
/// An extended model for use with the soft duplicate endpoint.
/// </summary>
public class WithMultipleReleasesResult : Series
public class WithEpisodeCount : Series
{
/// <summary>
/// Number of episodes in the series which have multiple releases.
/// </summary>
public int EpisodeCount { get; set; }

public WithMultipleReleasesResult(SVR_AnimeSeries ser, int userId = 0, HashSet<DataSource>? includeDataFrom = null, bool ignoreVariations = true)
public WithEpisodeCount(int episodeCount, SVR_AnimeSeries ser, int userId = 0, HashSet<DataSource>? includeDataFrom = null)
: base(ser, userId, false, includeDataFrom)
{
EpisodeCount = RepoFactory.AnimeEpisode.GetWithMultipleReleases(ignoreVariations, ser.AniDB_ID).Count;
}
}

/// <summary>
/// An extended model for use with the hard duplicate endpoint.
/// </summary>
public class WithDuplicateFilesResult : Series
{
/// <summary>
/// Number of episodes in the series which have duplicate files.
/// </summary>
public int EpisodeCount { get; set; }

public WithDuplicateFilesResult(SVR_AnimeSeries ser, int userId = 0, HashSet<DataSource>? includeDataFrom = null)
: base(ser, userId, false, includeDataFrom)
{
EpisodeCount = RepoFactory.AnimeEpisode.GetWithDuplicateFiles(ser.AniDB_ID).Count();
EpisodeCount = episodeCount;
}
}
}
Expand Down
Loading

0 comments on commit b7f0356

Please sign in to comment.