// 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 .
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Utils;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Core.Api
{
///
/// A common API containing custom methods to help inheritors.
///
public abstract class BaseApi : ControllerBase
{
///
/// Construct and return a page from an api.
///
/// The list of resources that should be included in the current page.
///
/// The max number of items that should be present per page. This should be the same as in the request,
/// it is used to calculate if this is the last page and so on.
///
/// The type of items on the page.
/// A Page representing the response.
protected Page Page(ICollection resources, int limit)
where TResult : IResource
{
Dictionary query = Request
.Query
.ToDictionary(
x => x.Key,
x => x.Value.ToString(),
StringComparer.InvariantCultureIgnoreCase
);
// If the query was sorted randomly, add the seed to the url to get reproducible links (next,prev,first...)
if (query.ContainsKey("sortBy"))
{
object seed = HttpContext.Items["seed"]!;
query["sortBy"] = Regex.Replace(query["sortBy"], "random(?!:)", $"random:{seed}");
}
return new Page(resources, Request.Path, query, limit);
}
protected SearchPage SearchPage(SearchPage.SearchResult result)
where TResult : IResource
{
Dictionary query = Request
.Query
.ToDictionary(
x => x.Key,
x => x.Value.ToString(),
StringComparer.InvariantCultureIgnoreCase
);
string self = Request.Path + query.ToQueryString();
string? previous = null;
string? next = null;
string first;
int limit = query.TryGetValue("limit", out string? limitStr)
? int.Parse(limitStr)
: new SearchPagination().Limit;
int? skip = query.TryGetValue("skip", out string? skipStr) ? int.Parse(skipStr) : null;
if (skip != null)
{
query["skip"] = Math.Max(0, skip.Value - limit).ToString();
previous = Request.Path + query.ToQueryString();
}
if (result.Items.Count == limit && limit > 0)
{
int newSkip = skip.HasValue ? skip.Value + limit : limit;
query["skip"] = newSkip.ToString();
next = Request.Path + query.ToQueryString();
}
query.Remove("skip");
first = Request.Path + query.ToQueryString();
return new SearchPage(result, self, previous, next, first);
}
}
}