diff --git a/back/src/Kyoo.Abstractions/Models/Page.cs b/back/src/Kyoo.Abstractions/Models/Page.cs
index 0acdb4a9..6c09e54a 100644
--- a/back/src/Kyoo.Abstractions/Models/Page.cs
+++ b/back/src/Kyoo.Abstractions/Models/Page.cs
@@ -16,7 +16,6 @@
// 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 Kyoo.Utils;
@@ -40,6 +39,11 @@ namespace Kyoo.Abstractions.Models
///
public string First { get; }
+ ///
+ /// The link of the previous page.
+ ///
+ public string Previous { get; }
+
///
/// The link of the next page.
///
@@ -60,12 +64,14 @@ namespace Kyoo.Abstractions.Models
///
/// The list of items in the page.
/// The link of the current page.
+ /// The link of the previous page.
/// The link of the next page.
/// The link of the first page.
- public Page(ICollection items, string @this, string next, string first)
+ public Page(ICollection items, string @this, string previous, string next, string first)
{
Items = items;
This = @this;
+ Previous = previous;
Next = next;
First = first;
}
@@ -85,6 +91,13 @@ namespace Kyoo.Abstractions.Models
Items = items;
This = url + query.ToQueryString();
+ if (items.Count > 0 && query.ContainsKey("afterID"))
+ {
+ query["afterID"] = items.First().ID.ToString();
+ query["reverse"] = "true";
+ Previous = url + query.ToQueryString();
+ }
+ query.Remove("reverse");
if (items.Count == limit && limit > 0)
{
query["afterID"] = items.Last().ID.ToString();
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs b/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
index 935393b3..8dee9b00 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
@@ -21,32 +21,42 @@ namespace Kyoo.Abstractions.Controllers
///
/// Information about the pagination. How many items should be displayed and where to start.
///
- public readonly struct Pagination
+ public class Pagination
{
///
/// The count of items to return.
///
- public int Count { get; }
+ public int Limit { get; set; }
///
/// Where to start? Using the given sort.
///
- public int? AfterID { get; }
+ public int? AfterID { get; set; }
///
/// Should the previous page be returned instead of the next?
///
- public bool Reverse { get; }
+ public bool Reverse { get; set; }
+
+ ///
+ /// Create a new with default values.
+ ///
+ public Pagination()
+ {
+ Limit = 20;
+ AfterID = null;
+ Reverse = false;
+ }
///
/// Create a new instance.
///
- /// Set the value
+ /// Set the value
/// Set the value. If not specified, it will start from the start
/// Should the previous page be returned instead of the next?
public Pagination(int count, int? afterID = null, bool reverse = false)
{
- Count = count;
+ Limit = count;
AfterID = afterID;
Reverse = reverse;
}
@@ -54,7 +64,7 @@ namespace Kyoo.Abstractions.Controllers
///
/// Implicitly create a new pagination from a limit number.
///
- /// Set the value
+ /// Set the value
/// A new instance
public static implicit operator Pagination(int limit) => new(limit);
}
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
index 4cafb788..5e8191b0 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
@@ -48,36 +48,13 @@ namespace Kyoo.Abstractions.Controllers
///
public By(Expression> key, bool desendant = false)
: this(Utility.GetPropertyName(key), desendant) { }
-
- ///
- /// Create a new instance from a key's name (case insensitive).
- ///
- /// A key name with an optional order specifier. Format: "key:asc", "key:desc" or "key".
- /// An invalid key or sort specifier as been given.
- /// A for the given string
- public static new By From(string sortBy)
- {
- string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
- string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
- bool desendant = order switch
- {
- "desc" => true,
- "asc" => false,
- null => false,
- _ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
- };
- PropertyInfo property = typeof(T).GetProperty(key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
- if (property == null)
- throw new ArgumentException("The given sort key is not valid.");
- return new By(property.Name, desendant);
- }
}
///
/// Sort by multiple keys.
///
/// The list of keys to sort by.
- public record Conglomerate(params By[] list) : Sort;
+ public record Conglomerate(params Sort[] list) : Sort;
/// The default sort method for the given type.
public record Default : Sort;
@@ -90,11 +67,24 @@ namespace Kyoo.Abstractions.Controllers
/// A for the given string
public static Sort From(string sortBy)
{
- if (string.IsNullOrEmpty(sortBy))
+ if (string.IsNullOrEmpty(sortBy) || sortBy == "default")
return new Default();
if (sortBy.Contains(','))
- return new Conglomerate(sortBy.Split(',').Select(By.From).ToArray());
- return By.From(sortBy);
+ return new Conglomerate(sortBy.Split(',').Select(From).ToArray());
+
+ string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
+ string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
+ bool desendant = order switch
+ {
+ "desc" => true,
+ "asc" => false,
+ null => false,
+ _ => throw new ArgumentException($"The sort order, if set, should be :asc or :desc but it was :{order}.")
+ };
+ PropertyInfo property = typeof(T).GetProperty(key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
+ if (property == null)
+ throw new ArgumentException("The given sort key is not valid.");
+ return new By(property.Name, desendant);
}
}
}
diff --git a/back/src/Kyoo.Abstractions/Models/WatchItem.cs b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
index 10bdfae4..c737839c 100644
--- a/back/src/Kyoo.Abstractions/Models/WatchItem.cs
+++ b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
@@ -163,47 +163,6 @@ namespace Kyoo.Abstractions.Models
await library.Load(ep, x => x.Show);
await library.Load(ep, x => x.Tracks);
- // if (!ep.Show.IsMovie)
- // {
- // if (ep.AbsoluteNumber != null)
- // {
- // previous = await library.GetOrDefault(
- // x => x.ShowID == ep.ShowID && x.AbsoluteNumber < ep.AbsoluteNumber,
- // new Sort(x => x.AbsoluteNumber, true)
- // );
- // next = await library.GetOrDefault(
- // x => x.ShowID == ep.ShowID && x.AbsoluteNumber > ep.AbsoluteNumber,
- // new Sort(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(x => x.EpisodeNumber, true)
- // );
- // previous ??= await library.GetOrDefault(
- // x => x.ShowID == ep.ShowID
- // && x.SeasonNumber == ep.SeasonNumber - 1,
- // new Sort(x => x.EpisodeNumber, true)
- // );
- //
- // next = await library.GetOrDefault(
- // x => x.ShowID == ep.ShowID
- // && x.SeasonNumber == ep.SeasonNumber
- // && x.EpisodeNumber > ep.EpisodeNumber,
- // new Sort(x => x.EpisodeNumber)
- // );
- // next ??= await library.GetOrDefault(
- // x => x.ShowID == ep.ShowID
- // && x.SeasonNumber == ep.SeasonNumber + 1,
- // new Sort(x => x.EpisodeNumber)
- // );
- // }
- // }
-
return new WatchItem
{
EpisodeID = ep.ID,
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
index 515f9ad0..835218bd 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
@@ -72,31 +72,38 @@ namespace Kyoo.Core.Controllers
{
sortBy ??= DefaultSort;
- IOrderedQueryable _Sort(IQueryable query, Sort sortBy)
+ IOrderedQueryable _SortBy(IQueryable qr, Expression> sort, bool desc, bool then)
+ {
+ if (then && qr is IOrderedQueryable qro)
+ {
+ return desc
+ ? qro.ThenByDescending(sort)
+ : qro.ThenBy(sort);
+ }
+ return desc
+ ? qr.OrderByDescending(sort)
+ : qr.OrderBy(sort);
+ }
+
+ IOrderedQueryable _Sort(IQueryable query, Sort sortBy, bool then)
{
switch (sortBy)
{
case Sort.Default:
- return Sort(query, DefaultSort);
+ return _Sort(query, DefaultSort, then);
case Sort.By(var key, var desc):
- return desc
- ? query.OrderByDescending(x => EF.Property