mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
API: documenting watch items
This commit is contained in:
parent
7e4fab1ee1
commit
049f545d51
@ -200,10 +200,11 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// Get the resource by a filter function or null if it is not found.
|
/// Get the resource by a filter function or null if it is not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="where">The filter function.</param>
|
/// <param name="where">The filter function.</param>
|
||||||
|
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||||
/// <typeparam name="T">The type of the resource</typeparam>
|
/// <typeparam name="T">The type of the resource</typeparam>
|
||||||
/// <returns>The first resource found that match the where function</returns>
|
/// <returns>The first resource found that match the where function</returns>
|
||||||
[ItemCanBeNull]
|
[ItemCanBeNull]
|
||||||
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where)
|
Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T> sortBy = default)
|
||||||
where T : class, IResource;
|
where T : class, IResource;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -81,9 +81,10 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// Get the first resource that match the predicate or null if it is not found.
|
/// Get the first resource that match the predicate or null if it is not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="where">A predicate to filter the resource.</param>
|
/// <param name="where">A predicate to filter the resource.</param>
|
||||||
|
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||||
/// <returns>The resource found</returns>
|
/// <returns>The resource found</returns>
|
||||||
[ItemCanBeNull]
|
[ItemCanBeNull]
|
||||||
Task<T> GetOrDefault(Expression<Func<T, bool>> where);
|
Task<T> GetOrDefault(Expression<Func<T, bool>> where, Sort<T> sortBy = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Search for resources.
|
/// Search for resources.
|
||||||
@ -263,6 +264,8 @@ namespace Kyoo.Abstractions.Controllers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IEpisodeRepository : IRepository<Episode>
|
public interface IEpisodeRepository : IRepository<Episode>
|
||||||
{
|
{
|
||||||
|
// TODO replace the next methods with extension methods.
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
/// Get a episode from it's showID, it's seasonNumber and it's episode number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -158,36 +158,50 @@ namespace Kyoo.Abstractions.Models
|
|||||||
/// <returns>A new WatchItem representing the given episode.</returns>
|
/// <returns>A new WatchItem representing the given episode.</returns>
|
||||||
public static async Task<WatchItem> FromEpisode(Episode ep, ILibraryManager library)
|
public static async Task<WatchItem> FromEpisode(Episode ep, ILibraryManager library)
|
||||||
{
|
{
|
||||||
Episode previous = null;
|
|
||||||
Episode next = null;
|
|
||||||
|
|
||||||
await library.Load(ep, x => x.Show);
|
await library.Load(ep, x => x.Show);
|
||||||
await library.Load(ep, x => x.Tracks);
|
await library.Load(ep, x => x.Tracks);
|
||||||
|
|
||||||
if (!ep.Show.IsMovie && ep.SeasonNumber != null && ep.EpisodeNumber != null)
|
Episode previous = null;
|
||||||
|
Episode next = null;
|
||||||
|
if (!ep.Show.IsMovie)
|
||||||
{
|
{
|
||||||
if (ep.EpisodeNumber > 1)
|
if (ep.AbsoluteNumber != null)
|
||||||
previous = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value, ep.EpisodeNumber.Value - 1);
|
|
||||||
else if (ep.SeasonNumber > 1)
|
|
||||||
{
|
{
|
||||||
previous = (await library.GetAll(x => x.ShowID == ep.ShowID
|
previous = await library.GetOrDefault(
|
||||||
&& x.SeasonNumber == ep.SeasonNumber.Value - 1,
|
x => x.ShowID == ep.ShowID && x.AbsoluteNumber <= ep.AbsoluteNumber,
|
||||||
limit: 1,
|
new Sort<Episode>(x => x.AbsoluteNumber, true)
|
||||||
sort: new Sort<Episode>(x => x.EpisodeNumber, true))
|
);
|
||||||
).FirstOrDefault();
|
next = await library.GetOrDefault(
|
||||||
|
x => x.ShowID == ep.ShowID && x.AbsoluteNumber >= ep.AbsoluteNumber,
|
||||||
|
new Sort<Episode>(x => x.AbsoluteNumber)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
else if (ep.SeasonNumber != null && ep.EpisodeNumber != null)
|
||||||
|
{
|
||||||
|
previous = await library.GetOrDefault(
|
||||||
|
x => x.ShowID == ep.ShowID
|
||||||
|
&& x.SeasonNumber == ep.SeasonNumber
|
||||||
|
&& x.EpisodeNumber < ep.EpisodeNumber,
|
||||||
|
new Sort<Episode>(x => x.EpisodeNumber, true)
|
||||||
|
);
|
||||||
|
previous ??= await library.GetOrDefault(
|
||||||
|
x => x.ShowID == ep.ShowID
|
||||||
|
&& x.SeasonNumber == ep.SeasonNumber - 1,
|
||||||
|
new Sort<Episode>(x => x.EpisodeNumber, true)
|
||||||
|
);
|
||||||
|
|
||||||
if (ep.EpisodeNumber >= await library.GetCount<Episode>(x => x.SeasonID == ep.SeasonID))
|
next = await library.GetOrDefault(
|
||||||
next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value + 1, 1);
|
x => x.ShowID == ep.ShowID
|
||||||
else
|
&& x.SeasonNumber == ep.SeasonNumber
|
||||||
next = await library.GetOrDefault(ep.ShowID, ep.SeasonNumber.Value, ep.EpisodeNumber.Value + 1);
|
&& x.EpisodeNumber > ep.EpisodeNumber,
|
||||||
}
|
new Sort<Episode>(x => x.EpisodeNumber)
|
||||||
else if (!ep.Show.IsMovie && ep.AbsoluteNumber != null)
|
);
|
||||||
{
|
next ??= await library.GetOrDefault(
|
||||||
previous = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
x => x.ShowID == ep.ShowID
|
||||||
&& x.AbsoluteNumber == ep.EpisodeNumber + 1);
|
&& x.SeasonNumber == ep.SeasonNumber + 1,
|
||||||
next = await library.GetOrDefault<Episode>(x => x.ShowID == ep.ShowID
|
new Sort<Episode>(x => x.EpisodeNumber)
|
||||||
&& x.AbsoluteNumber == ep.AbsoluteNumber + 1);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WatchItem
|
return new WatchItem
|
||||||
|
@ -163,10 +163,10 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where)
|
public async Task<T> GetOrDefault<T>(Expression<Func<T, bool>> where, Sort<T> sortBy)
|
||||||
where T : class, IResource
|
where T : class, IResource
|
||||||
{
|
{
|
||||||
return await GetRepository<T>().GetOrDefault(where);
|
return await GetRepository<T>().GetOrDefault(where, sortBy);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -115,9 +115,12 @@ namespace Kyoo.Core.Controllers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual Task<T> GetOrDefault(Expression<Func<T, bool>> where)
|
public virtual Task<T> GetOrDefault(Expression<Func<T, bool>> where, Sort<T> sortBy = default)
|
||||||
{
|
{
|
||||||
return Database.Set<T>().FirstOrDefaultAsync(where);
|
IQueryable<T> query = Database.Set<T>();
|
||||||
|
Expression<Func<T, object>> sortKey = sortBy.Key ?? DefaultSort;
|
||||||
|
query = sortBy.Descendant ? query.OrderByDescending(sortKey) : query.OrderBy(sortKey);
|
||||||
|
return query.FirstOrDefaultAsync(where);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
|
@ -23,10 +23,6 @@ using System.Linq;
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Kyoo.Abstractions.Models;
|
using Kyoo.Abstractions.Models;
|
||||||
using Kyoo.Core.Models.Options;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using Microsoft.Extensions.Options;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Api
|
namespace Kyoo.Core.Api
|
||||||
{
|
{
|
||||||
|
@ -29,8 +29,8 @@ namespace Kyoo.Core.Api
|
|||||||
{
|
{
|
||||||
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
|
public class JsonPropertyIgnorer : CamelCasePropertyNamesContractResolver
|
||||||
{
|
{
|
||||||
private int _depth = -1;
|
|
||||||
private readonly Uri _host;
|
private readonly Uri _host;
|
||||||
|
private int _depth = -1;
|
||||||
|
|
||||||
public JsonPropertyIgnorer(Uri host)
|
public JsonPropertyIgnorer(Uri host)
|
||||||
{
|
{
|
||||||
|
83
src/Kyoo.Core/Views/Watch/WatchApi.cs
Normal file
83
src/Kyoo.Core/Views/Watch/WatchApi.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.Threading.Tasks;
|
||||||
|
using Kyoo.Abstractions.Controllers;
|
||||||
|
using Kyoo.Abstractions.Models;
|
||||||
|
using Kyoo.Abstractions.Models.Attributes;
|
||||||
|
using Kyoo.Abstractions.Models.Permissions;
|
||||||
|
using Kyoo.Abstractions.Models.Utils;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using static Kyoo.Abstractions.Models.Utils.Constants;
|
||||||
|
|
||||||
|
namespace Kyoo.Core.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve information of an <see cref="Episode"/> as a <see cref="WatchItem"/>.
|
||||||
|
/// A watch item is another representation of an episode in a form easier to read and display for playback.
|
||||||
|
/// It contains streams (video, audio, subtitles) information, chapters, next and previous episodes and a bit of
|
||||||
|
/// information of the show.
|
||||||
|
/// </summary>
|
||||||
|
[Route("api/watch")]
|
||||||
|
[Route("api/watchitem", Order = AlternativeRoute)]
|
||||||
|
[ApiController]
|
||||||
|
[ApiDefinition("Watch Items", Group = WatchGroup)]
|
||||||
|
public class WatchApi : ControllerBase
|
||||||
|
{
|
||||||
|
/// <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="WatchApi"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="libraryManager">
|
||||||
|
/// The library manager used to modify or retrieve information in the data store.
|
||||||
|
/// </param>
|
||||||
|
public WatchApi(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
_libraryManager = libraryManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a watch item
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Retrieve a watch item of an episode.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="identifier">The ID or slug of the <see cref="Episode"/>.</param>
|
||||||
|
/// <returns>A page of items.</returns>
|
||||||
|
/// <response code="404">No episode with the given ID or slug could be found.</response>
|
||||||
|
[HttpGet("{identifier:id}")]
|
||||||
|
[Permission("watch", Kind.Read)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult<WatchItem>> GetWatchItem(Identifier identifier)
|
||||||
|
{
|
||||||
|
Episode item = await identifier.Match(
|
||||||
|
id => _libraryManager.GetOrDefault<Episode>(id),
|
||||||
|
slug => _libraryManager.GetOrDefault<Episode>(slug)
|
||||||
|
);
|
||||||
|
if (item == null)
|
||||||
|
return NotFound();
|
||||||
|
return await WatchItem.FromEpisode(item, _libraryManager);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,54 +0,0 @@
|
|||||||
// 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.Threading.Tasks;
|
|
||||||
using Kyoo.Abstractions.Controllers;
|
|
||||||
using Kyoo.Abstractions.Models;
|
|
||||||
using Kyoo.Abstractions.Models.Exceptions;
|
|
||||||
using Kyoo.Abstractions.Models.Permissions;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace Kyoo.Core.Api
|
|
||||||
{
|
|
||||||
[Route("api/watch")]
|
|
||||||
[ApiController]
|
|
||||||
public class WatchApi : ControllerBase
|
|
||||||
{
|
|
||||||
private readonly ILibraryManager _libraryManager;
|
|
||||||
|
|
||||||
public WatchApi(ILibraryManager libraryManager)
|
|
||||||
{
|
|
||||||
_libraryManager = libraryManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet("{slug}")]
|
|
||||||
[Permission("video", Kind.Read)]
|
|
||||||
public async Task<ActionResult<WatchItem>> GetWatchItem(string slug)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Episode item = await _libraryManager.Get<Episode>(slug);
|
|
||||||
return await WatchItem.FromEpisode(item, _libraryManager);
|
|
||||||
}
|
|
||||||
catch (ItemNotFoundException)
|
|
||||||
{
|
|
||||||
return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user