Rework thumbnail manager to use images id

This commit is contained in:
Zoe Roux 2024-04-20 13:11:23 +02:00
parent e1c04bef51
commit d46e6eda64
No known key found for this signature in database
14 changed files with 139 additions and 257 deletions

View File

@ -23,56 +23,17 @@ using Kyoo.Abstractions.Models;
namespace Kyoo.Abstractions.Controllers;
/// <summary>
/// Download images and retrieve the path of those images for a resource.
/// </summary>
public interface IThumbnailsManager
{
/// <summary>
/// Download images of a specified item.
/// If no images is available to download, do nothing and silently return.
/// </summary>
/// <param name="item">
/// The item to cache images.
/// </param>
/// <typeparam name="T">The type of the item</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task DownloadImages<T>(T item)
where T : IThumbnails;
/// <summary>
/// Retrieve the local path of an image of the given item.
/// </summary>
/// <param name="item">The item to retrieve the poster from.</param>
/// <param name="image">The ID of the image.</param>
/// <param name="quality">The quality of the image</param>
/// <typeparam name="T">The type of the item</typeparam>
/// <returns>The path of the image for the given resource or null if it does not exists.</returns>
string GetImagePath<T>(T item, string image, ImageQuality quality)
where T : IThumbnails;
string GetImagePath(Guid imageId, ImageQuality quality);
/// <summary>
/// Delete images associated with the item.
/// </summary>
/// <param name="item">
/// The item with cached images.
/// </param>
/// <typeparam name="T">The type of the item</typeparam>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task DeleteImages<T>(T item)
where T : IThumbnails;
/// <summary>
/// Set the user's profile picture
/// </summary>
/// <param name="userId">The id of the user. </param>
/// <returns>The byte stream of the image. Null if no image exist.</returns>
Task<Stream> GetUserImage(Guid userId);
/// <summary>
/// Set the user's profile picture
/// </summary>
/// <param name="userId">The id of the user. </param>
/// <param name="image">The byte stream of the image. Null to delete the image.</param>
Task SetUserImage(Guid userId, Stream? image);
}

View File

@ -20,7 +20,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Utils;
using Kyoo.Postgresql;

View File

@ -42,8 +42,6 @@ public class ThumbnailsManager(
Lazy<IRepository<User>> users
) : IThumbnailsManager
{
private static readonly Dictionary<string, TaskCompletionSource<object>> _downloading = [];
private static async Task _WriteTo(SKBitmap bitmap, string path, int quality)
{
SKData data = bitmap.Encode(SKEncodedImageFormat.Webp, quality);
@ -52,12 +50,16 @@ public class ThumbnailsManager(
await reader.CopyToAsync(file);
}
private async Task _DownloadImage(Image? image, string localPath, string what)
private async Task _DownloadImage(Image? image, string what)
{
if (image == null)
return;
try
{
if (image.Id == Guid.Empty)
image.Id = new Guid();
string localPath = $"/metadata/{image.Id}";
logger.LogInformation("Downloading image {What}", what);
HttpClient client = clientFactory.CreateClient();
@ -119,86 +121,24 @@ public class ThumbnailsManager(
{
string name = item is IResource res ? res.Slug : "???";
string posterPath =
$"{_GetBaseImagePath(item, "poster")}.{ImageQuality.High.ToString().ToLowerInvariant()}.webp";
bool duplicated = false;
TaskCompletionSource<object>? sync = null;
try
{
lock (_downloading)
{
if (_downloading.ContainsKey(posterPath))
{
duplicated = true;
sync = _downloading.GetValueOrDefault(posterPath);
}
else
{
sync = new();
_downloading.Add(posterPath, sync);
}
}
if (duplicated)
{
object? dup = sync != null ? await sync.Task : null;
if (dup != null)
throw new DuplicatedItemException(dup);
}
await _DownloadImage(
item.Poster,
_GetBaseImagePath(item, "poster"),
$"The poster of {name}"
);
await _DownloadImage(
item.Thumbnail,
_GetBaseImagePath(item, "thumbnail"),
$"The poster of {name}"
);
await _DownloadImage(
item.Logo,
_GetBaseImagePath(item, "logo"),
$"The poster of {name}"
);
}
finally
{
if (!duplicated)
{
lock (_downloading)
{
_downloading.Remove(posterPath);
sync!.SetResult(item);
}
}
}
}
private static string _GetBaseImagePath<T>(T item, string image)
{
string directory = item switch
{
IResource res
=> Path.Combine("/metadata", item.GetType().Name.ToLowerInvariant(), res.Slug),
_ => Path.Combine("/metadata", typeof(T).Name.ToLowerInvariant())
};
Directory.CreateDirectory(directory);
return Path.Combine(directory, image);
await _DownloadImage(item.Poster, $"The poster of {name}");
await _DownloadImage(item.Thumbnail, $"The thumbnail of {name}");
await _DownloadImage(item.Logo, $"The logo of {name}");
}
/// <inheritdoc />
public string GetImagePath<T>(T item, string image, ImageQuality quality)
where T : IThumbnails
public string GetImagePath(Guid imageId, ImageQuality quality)
{
return $"{_GetBaseImagePath(item, image)}.{quality.ToString().ToLowerInvariant()}.webp";
return $"/metadata/{imageId}.{quality.ToString().ToLowerInvariant()}.webp";
}
/// <inheritdoc />
public Task DeleteImages<T>(T item)
where T : IThumbnails
{
IEnumerable<string> images = new[] { "poster", "thumbnail", "logo" }
.SelectMany(x => _GetBaseImagePath(item, x))
IEnumerable<string> images = new[] {item.Poster?.Id, item.Thumbnail?.Id, item.Logo?.Id}
.Where(x => x is not null)
.SelectMany(x => $"/metadata/{x}")
.SelectMany(x =>
new[]
{

View File

@ -0,0 +1,59 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.IO;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Core.Api;
[ApiController]
public class ThumbnailsApi(IThumbnailsManager thumbs) : BaseApi
{
/// <summary>
/// Get Image
/// </summary>
/// <remarks>
/// Get an image from it's id. You can select a specefic quality.
/// </remarks>
/// <param name="id">The ID of the image to retrive.</param>
/// <param name="quality">The quality of the image to retrieve.</param>
/// <returns>The image asked.</returns>
/// <response code="404">
/// The image does not exists on kyoo.
/// </response>
[HttpGet("{identifier:id}/poster")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public IActionResult GetPoster(Guid id, [FromQuery] ImageQuality? quality)
{
string path = thumbs.GetImagePath(id, quality ?? ImageQuality.High);
if (!System.IO.File.Exists(path))
return NotFound();
// Allow clients to cache the image for 6 month.
Response.Headers.CacheControl = $"public, max-age={60 * 60 * 24 * 31 * 6}";
return PhysicalFile(Path.GetFullPath(path), "image/webp", true);
}
}

View File

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System.IO;
using System;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@ -28,14 +28,8 @@ using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api;
/// <summary>
/// A base class to handle CRUD operations and services thumbnails for
/// a specific resource type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of resource to make CRUD and thumbnails apis for.</typeparam>
[ApiController]
public class CrudThumbsApi<T>(IRepository<T> repository, IThumbnailsManager thumbs)
: CrudApi<T>(repository)
public class CrudThumbsApi<T>(IRepository<T> repository) : CrudApi<T>(repository)
where T : class, IResource, IThumbnails, IQuery
{
private async Task<IActionResult> _GetImage(
@ -50,18 +44,18 @@ public class CrudThumbsApi<T>(IRepository<T> repository, IThumbnailsManager thum
);
if (resource == null)
return NotFound();
string path = thumbs.GetImagePath(resource, image, quality ?? ImageQuality.High);
if (!System.IO.File.Exists(path))
Image? img = image switch
{
"poster" => resource.Poster,
"thumbnail" => resource.Thumbnail,
"logo" => resource.Logo,
_ => throw new ArgumentException(nameof(image)),
};
if (img is null)
return NotFound();
if (!identifier.Match(id => false, slug => slug == "random"))
{
// Allow clients to cache the image for 6 month.
Response.Headers.CacheControl = $"public, max-age={60 * 60 * 24 * 31 * 6}";
}
else
Response.Headers.CacheControl = $"public, no-store";
return PhysicalFile(Path.GetFullPath(path), "image/webp", true);
return Redirect($"/thumbnails/{img.Id}");
}
/// <summary>
@ -78,7 +72,7 @@ public class CrudThumbsApi<T>(IRepository<T> repository, IThumbnailsManager thum
/// </response>
[HttpGet("{identifier:id}/poster")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public Task<IActionResult> GetPoster(Identifier identifier, [FromQuery] ImageQuality? quality)
{
@ -99,7 +93,7 @@ public class CrudThumbsApi<T>(IRepository<T> repository, IThumbnailsManager thum
/// </response>
[HttpGet("{identifier:id}/logo")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public Task<IActionResult> GetLogo(Identifier identifier, [FromQuery] ImageQuality? quality)
{
@ -120,6 +114,8 @@ public class CrudThumbsApi<T>(IRepository<T> repository, IThumbnailsManager thum
/// </response>
[HttpGet("{identifier:id}/thumbnail")]
[HttpGet("{identifier:id}/backdrop", Order = AlternativeRoute)]
[ProducesResponseType(StatusCodes.Status302Found)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public Task<IActionResult> GetBackdrop(Identifier identifier, [FromQuery] ImageQuality? quality)
{
return _GetImage(identifier, "thumbnail", quality);

View File

@ -35,8 +35,7 @@ public static class Transcoder
Environment.GetEnvironmentVariable("TRANSCODER_URL") ?? "http://transcoder:7666";
}
public abstract class TranscoderApi<T>(IRepository<T> repository, IThumbnailsManager thumbs)
: CrudThumbsApi<T>(repository, thumbs)
public abstract class TranscoderApi<T>(IRepository<T> repository) : CrudThumbsApi<T>(repository)
where T : class, IResource, IThumbnails, IQuery
{
private Task _Proxy(string route, (string path, string route) info)

View File

@ -40,25 +40,13 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission(nameof(Collection))]
[ApiDefinition("Collections", Group = ResourcesGroup)]
public class CollectionApi : CrudThumbsApi<Collection>
public class CollectionApi(
IRepository<Movie> movies,
IRepository<Show> shows,
CollectionRepository collections,
LibraryItemRepository items
) : CrudThumbsApi<Collection>(collections)
{
private readonly ILibraryManager _libraryManager;
private readonly CollectionRepository _collections;
private readonly LibraryItemRepository _items;
public CollectionApi(
ILibraryManager libraryManager,
CollectionRepository collections,
LibraryItemRepository items,
IThumbnailsManager thumbs
)
: base(libraryManager.Collections, thumbs)
{
_libraryManager = libraryManager;
_collections = collections;
_items = items;
}
/// <summary>
/// Add a movie
/// </summary>
@ -79,14 +67,14 @@ public class CollectionApi : CrudThumbsApi<Collection>
public async Task<ActionResult> AddMovie(Identifier identifier, Identifier movie)
{
Guid collectionId = await identifier.Match(
async id => (await _libraryManager.Collections.Get(id)).Id,
async slug => (await _libraryManager.Collections.Get(slug)).Id
async id => (await collections.Get(id)).Id,
async slug => (await collections.Get(slug)).Id
);
Guid movieId = await movie.Match(
async id => (await _libraryManager.Movies.Get(id)).Id,
async slug => (await _libraryManager.Movies.Get(slug)).Id
async id => (await movies.Get(id)).Id,
async slug => (await movies.Get(slug)).Id
);
await _collections.AddMovie(collectionId, movieId);
await collections.AddMovie(collectionId, movieId);
return NoContent();
}
@ -110,14 +98,14 @@ public class CollectionApi : CrudThumbsApi<Collection>
public async Task<ActionResult> AddShow(Identifier identifier, Identifier show)
{
Guid collectionId = await identifier.Match(
async id => (await _libraryManager.Collections.Get(id)).Id,
async slug => (await _libraryManager.Collections.Get(slug)).Id
async id => (await collections.Get(id)).Id,
async slug => (await collections.Get(slug)).Id
);
Guid showId = await show.Match(
async id => (await _libraryManager.Shows.Get(id)).Id,
async slug => (await _libraryManager.Shows.Get(slug)).Id
async id => (await shows.Get(id)).Id,
async slug => (await shows.Get(slug)).Id
);
await _collections.AddShow(collectionId, showId);
await collections.AddShow(collectionId, showId);
return NoContent();
}
@ -151,9 +139,9 @@ public class CollectionApi : CrudThumbsApi<Collection>
{
Guid collectionId = await identifier.Match(
id => Task.FromResult(id),
async slug => (await _libraryManager.Collections.Get(slug)).Id
async slug => (await collections.Get(slug)).Id
);
ICollection<ILibraryItem> resources = await _items.GetAllOfCollection(
ICollection<ILibraryItem> resources = await items.GetAllOfCollection(
collectionId,
filter,
sortBy == new Sort<ILibraryItem>.Default()
@ -165,8 +153,7 @@ public class CollectionApi : CrudThumbsApi<Collection>
if (
!resources.Any()
&& await _libraryManager.Collections.GetOrDefault(identifier.IsSame<Collection>())
== null
&& await collections.GetOrDefault(identifier.IsSame<Collection>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -200,7 +187,7 @@ public class CollectionApi : CrudThumbsApi<Collection>
[FromQuery] Include<Show>? fields
)
{
ICollection<Show> resources = await _libraryManager.Shows.GetAll(
ICollection<Show> resources = await shows.GetAll(
Filter.And(filter, identifier.IsContainedIn<Show, Collection>(x => x.Collections)),
sortBy == new Sort<Show>.Default() ? new Sort<Show>.By(x => x.AirDate) : sortBy,
fields,
@ -209,8 +196,7 @@ public class CollectionApi : CrudThumbsApi<Collection>
if (
!resources.Any()
&& await _libraryManager.Collections.GetOrDefault(identifier.IsSame<Collection>())
== null
&& await collections.GetOrDefault(identifier.IsSame<Collection>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -244,7 +230,7 @@ public class CollectionApi : CrudThumbsApi<Collection>
[FromQuery] Include<Movie>? fields
)
{
ICollection<Movie> resources = await _libraryManager.Movies.GetAll(
ICollection<Movie> resources = await movies.GetAll(
Filter.And(filter, identifier.IsContainedIn<Movie, Collection>(x => x.Collections)),
sortBy == new Sort<Movie>.Default() ? new Sort<Movie>.By(x => x.AirDate) : sortBy,
fields,
@ -253,8 +239,7 @@ public class CollectionApi : CrudThumbsApi<Collection>
if (
!resources.Any()
&& await _libraryManager.Collections.GetOrDefault(identifier.IsSame<Collection>())
== null
&& await collections.GetOrDefault(identifier.IsSame<Collection>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);

View File

@ -38,8 +38,8 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission(nameof(Episode))]
[ApiDefinition("Episodes", Group = ResourcesGroup)]
public class EpisodeApi(ILibraryManager libraryManager, IThumbnailsManager thumbnails)
: TranscoderApi<Episode>(libraryManager.Episodes, thumbnails)
public class EpisodeApi(ILibraryManager libraryManager)
: TranscoderApi<Episode>(libraryManager.Episodes)
{
/// <summary>
/// Get episode's show

View File

@ -34,23 +34,5 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission("LibraryItem")]
[ApiDefinition("Items", Group = ResourcesGroup)]
public class LibraryItemApi : CrudThumbsApi<ILibraryItem>
{
/// <summary>
/// The library item repository used to modify or retrieve information in the data store.
/// </summary>
private readonly IRepository<ILibraryItem> _libraryItems;
/// <summary>
/// Create a new <see cref="LibraryItemApi"/>.
/// </summary>
/// <param name="libraryItems">
/// The library item repository used to modify or retrieve information in the data store.
/// </param>
/// <param name="thumbs">Thumbnail manager to retrieve images.</param>
public LibraryItemApi(IRepository<ILibraryItem> libraryItems, IThumbnailsManager thumbs)
: base(libraryItems, thumbs)
{
_libraryItems = libraryItems;
}
}
public class LibraryItemApi(IRepository<ILibraryItem> libraryItems)
: CrudThumbsApi<ILibraryItem>(libraryItems) { }

View File

@ -40,8 +40,8 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission(nameof(Show))]
[ApiDefinition("Shows", Group = ResourcesGroup)]
public class MovieApi(ILibraryManager libraryManager, IThumbnailsManager thumbs)
: TranscoderApi<Movie>(libraryManager.Movies, thumbs)
public class MovieApi(ILibraryManager libraryManager)
: TranscoderApi<Movie>(libraryManager.Movies)
{
/// <summary>
/// Get studio that made the show

View File

@ -33,8 +33,4 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission("LibraryItem")]
[ApiDefinition("News", Group = ResourcesGroup)]
public class NewsApi : CrudThumbsApi<INews>
{
public NewsApi(IRepository<INews> news, IThumbnailsManager thumbs)
: base(news, thumbs) { }
}
public class NewsApi(IRepository<INews> news) : CrudThumbsApi<INews>(news) { }

View File

@ -38,26 +38,9 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission(nameof(Season))]
[ApiDefinition("Seasons", Group = ResourcesGroup)]
public class SeasonApi : CrudThumbsApi<Season>
public class SeasonApi(ILibraryManager libraryManager)
: CrudThumbsApi<Season>(libraryManager.Seasons)
{
/// <summary>
/// The library manager used to modify or retrieve information in the data store.
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Create a new <see cref="SeasonApi"/>.
/// </summary>
/// <param name="libraryManager">
/// The library manager used to modify or retrieve information in the data store.
/// </param>
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
public SeasonApi(ILibraryManager libraryManager, IThumbnailsManager thumbs)
: base(libraryManager.Seasons, thumbs)
{
_libraryManager = libraryManager;
}
/// <summary>
/// Get episodes in the season
/// </summary>
@ -86,7 +69,7 @@ public class SeasonApi : CrudThumbsApi<Season>
[FromQuery] Include<Episode> fields
)
{
ICollection<Episode> resources = await _libraryManager.Episodes.GetAll(
ICollection<Episode> resources = await libraryManager.Episodes.GetAll(
Filter.And(filter, identifier.Matcher<Episode>(x => x.SeasonId, x => x.Season!.Slug)),
sortBy,
fields,
@ -95,7 +78,7 @@ public class SeasonApi : CrudThumbsApi<Season>
if (
!resources.Any()
&& await _libraryManager.Seasons.GetOrDefault(identifier.IsSame<Season>()) == null
&& await libraryManager.Seasons.GetOrDefault(identifier.IsSame<Season>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -120,7 +103,7 @@ public class SeasonApi : CrudThumbsApi<Season>
[FromQuery] Include<Show> fields
)
{
Show? ret = await _libraryManager.Shows.GetOrDefault(
Show? ret = await libraryManager.Shows.GetOrDefault(
identifier.IsContainedIn<Show, Season>(x => x.Seasons!),
fields
);

View File

@ -40,26 +40,8 @@ namespace Kyoo.Core.Api;
[ApiController]
[PartialPermission(nameof(Show))]
[ApiDefinition("Shows", Group = ResourcesGroup)]
public class ShowApi : CrudThumbsApi<Show>
public class ShowApi(ILibraryManager libraryManager) : CrudThumbsApi<Show>(libraryManager.Shows)
{
/// <summary>
/// The library manager used to modify or retrieve information in the data store.
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Create a new <see cref="ShowApi"/>.
/// </summary>
/// <param name="libraryManager">
/// The library manager used to modify or retrieve information about the data store.
/// </param>
/// <param name="thumbs">The thumbnail manager used to retrieve images paths.</param>
public ShowApi(ILibraryManager libraryManager, IThumbnailsManager thumbs)
: base(libraryManager.Shows, thumbs)
{
_libraryManager = libraryManager;
}
/// <summary>
/// Get seasons of this show
/// </summary>
@ -88,7 +70,7 @@ public class ShowApi : CrudThumbsApi<Show>
[FromQuery] Include<Season> fields
)
{
ICollection<Season> resources = await _libraryManager.Seasons.GetAll(
ICollection<Season> resources = await libraryManager.Seasons.GetAll(
Filter.And(filter, identifier.Matcher<Season>(x => x.ShowId, x => x.Show!.Slug)),
sortBy,
fields,
@ -97,7 +79,7 @@ public class ShowApi : CrudThumbsApi<Show>
if (
!resources.Any()
&& await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
&& await libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -131,7 +113,7 @@ public class ShowApi : CrudThumbsApi<Show>
[FromQuery] Include<Episode> fields
)
{
ICollection<Episode> resources = await _libraryManager.Episodes.GetAll(
ICollection<Episode> resources = await libraryManager.Episodes.GetAll(
Filter.And(filter, identifier.Matcher<Episode>(x => x.ShowId, x => x.Show!.Slug)),
sortBy,
fields,
@ -140,7 +122,7 @@ public class ShowApi : CrudThumbsApi<Show>
if (
!resources.Any()
&& await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
&& await libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -165,7 +147,7 @@ public class ShowApi : CrudThumbsApi<Show>
[FromQuery] Include<Studio> fields
)
{
return await _libraryManager.Studios.Get(
return await libraryManager.Studios.Get(
identifier.IsContainedIn<Studio, Show>(x => x.Shows!),
fields
);
@ -199,7 +181,7 @@ public class ShowApi : CrudThumbsApi<Show>
[FromQuery] Include<Collection> fields
)
{
ICollection<Collection> resources = await _libraryManager.Collections.GetAll(
ICollection<Collection> resources = await libraryManager.Collections.GetAll(
Filter.And(filter, identifier.IsContainedIn<Collection, Show>(x => x.Shows!)),
sortBy,
fields,
@ -208,7 +190,7 @@ public class ShowApi : CrudThumbsApi<Show>
if (
!resources.Any()
&& await _libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
&& await libraryManager.Shows.GetOrDefault(identifier.IsSame<Show>()) == null
)
return NotFound();
return Page(resources, pagination.Limit);
@ -233,9 +215,9 @@ public class ShowApi : CrudThumbsApi<Show>
{
Guid id = await identifier.Match(
id => Task.FromResult(id),
async slug => (await _libraryManager.Shows.Get(slug)).Id
async slug => (await libraryManager.Shows.Get(slug)).Id
);
return await _libraryManager.WatchStatus.GetShowStatus(id, User.GetIdOrThrow());
return await libraryManager.WatchStatus.GetShowStatus(id, User.GetIdOrThrow());
}
/// <summary>
@ -260,9 +242,9 @@ public class ShowApi : CrudThumbsApi<Show>
{
Guid id = await identifier.Match(
id => Task.FromResult(id),
async slug => (await _libraryManager.Shows.Get(slug)).Id
async slug => (await libraryManager.Shows.Get(slug)).Id
);
return await _libraryManager.WatchStatus.SetShowStatus(id, User.GetIdOrThrow(), status);
return await libraryManager.WatchStatus.SetShowStatus(id, User.GetIdOrThrow(), status);
}
/// <summary>
@ -283,8 +265,8 @@ public class ShowApi : CrudThumbsApi<Show>
{
Guid id = await identifier.Match(
id => Task.FromResult(id),
async slug => (await _libraryManager.Shows.Get(slug)).Id
async slug => (await libraryManager.Shows.Get(slug)).Id
);
await _libraryManager.WatchStatus.DeleteShowStatus(id, User.GetIdOrThrow());
await libraryManager.WatchStatus.DeleteShowStatus(id, User.GetIdOrThrow());
}
}