diff --git a/back/.editorconfig b/back/.editorconfig
index 985604f6..5f7f01a5 100644
--- a/back/.editorconfig
+++ b/back/.editorconfig
@@ -16,6 +16,7 @@ dotnet_diagnostic.IDE0058.severity = none
dotnet_diagnostic.IDE0046.severity = none
dotnet_diagnostic.CA1848.severity = none
dotnet_diagnostic.CA2007.severity = none
+dotnet_diagnostic.CA1716.severity = none
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
csharp_using_directive_placement = outside_namespace:warning
diff --git a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
index 3b1a1b7f..624f72eb 100644
--- a/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/ILibraryManager.cs
@@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
@@ -256,7 +255,7 @@ namespace Kyoo.Abstractions.Controllers
/// The type of the source object
/// The related resource's type
/// The param
- ///
+ ///
///
///
Task Load([NotNull] T obj, Expression> member, bool force = false)
@@ -274,7 +273,7 @@ namespace Kyoo.Abstractions.Controllers
/// The type of the source object
/// The related resource's type
/// The param
- ///
+ ///
///
///
Task Load([NotNull] T obj, Expression>> member, bool force = false)
@@ -291,8 +290,8 @@ namespace Kyoo.Abstractions.Controllers
///
/// The type of the source object
/// The param
- ///
- ///
+ ///
+ ///
///
Task Load([NotNull] T obj, string memberName, bool force = false)
where T : class, IResource;
@@ -305,8 +304,8 @@ namespace Kyoo.Abstractions.Controllers
///
/// true if you want to load the relation even if it is not null, false otherwise.
///
- ///
- ///
+ ///
+ ///
///
/// A representing the asynchronous operation.
Task Load([NotNull] IResource obj, string memberName, bool force = false);
@@ -325,21 +324,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get items (A wrapper around shows or collections) from a library.
- ///
- /// The ID of the library
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No library exist with the given ID.
- /// A list of items that match every filters
- Task> GetItemsFromLibrary(int id,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetItemsFromLibrary(id, where, new Sort(sort), limit);
-
///
/// Get items (A wrapper around shows or collections) from a library.
///
@@ -354,21 +338,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get items (A wrapper around shows or collections) from a library.
- ///
- /// The slug of the library
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No library exist with the given slug.
- /// A list of items that match every filters
- Task> GetItemsFromLibrary(string slug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetItemsFromLibrary(slug, where, new Sort(sort), limit);
-
///
/// Get people's roles from a show.
///
@@ -383,21 +352,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a show.
- ///
- /// The ID of the show
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given ID.
- /// A list of items that match every filters
- Task> GetPeopleFromShow(int showID,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetPeopleFromShow(showID, where, new Sort(sort), limit);
-
///
/// Get people's roles from a show.
///
@@ -412,21 +366,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a show.
- ///
- /// The slug of the show
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given slug.
- /// A list of items that match every filters
- Task> GetPeopleFromShow(string showSlug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetPeopleFromShow(showSlug, where, new Sort(sort), limit);
-
///
/// Get people's roles from a person.
///
@@ -441,21 +380,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a person.
- ///
- /// The id of the person
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given ID.
- /// A list of items that match every filters
- Task> GetRolesFromPeople(int id,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetRolesFromPeople(id, where, new Sort(sort), limit);
-
///
/// Get people's roles from a person.
///
@@ -470,21 +394,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a person.
- ///
- /// The slug of the person
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given slug.
- /// A list of items that match every filters
- Task> GetRolesFromPeople(string slug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetRolesFromPeople(slug, where, new Sort(sort), limit);
-
///
/// Setup relations between a show, a library and a collection
///
@@ -516,22 +425,6 @@ namespace Kyoo.Abstractions.Controllers
Pagination limit = default)
where T : class, IResource;
- ///
- /// Get all resources with filters
- ///
- /// A filter function
- /// A sort by function
- /// How many items to return and where to start
- /// The type of resources to load
- /// A list of resources that match every filters
- Task> GetAll([Optional] Expression> where,
- Expression> sort,
- Pagination limit = default)
- where T : class, IResource
- {
- return GetAll(where, new Sort(sort), limit);
- }
-
///
/// Get the count of resources that match the filter
///
diff --git a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
index 1d996e97..229fc4ce 100644
--- a/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
+++ b/back/src/Kyoo.Abstractions/Controllers/IRepository.cs
@@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
-using System.Runtime.InteropServices;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
@@ -106,19 +105,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get every resources that match all filters
- ///
- /// A filter predicate
- /// A sort by predicate. The order is ascending.
- /// How pagination should be done (where to start and how many to return)
- /// A list of resources that match every filters
- [ItemNotNull]
- Task> GetAll([Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetAll(where, new Sort(sort), limit);
-
///
/// Get the number of resources that match the filter's predicate.
///
@@ -352,21 +338,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get items (A wrapper around shows or collections) from a library.
- ///
- /// The ID of the library
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No library exist with the given ID.
- /// A list of items that match every filters
- public Task> GetFromLibrary(int id,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromLibrary(id, where, new Sort(sort), limit);
-
///
/// Get items (A wrapper around shows or collections) from a library.
///
@@ -380,21 +351,6 @@ namespace Kyoo.Abstractions.Controllers
Expression> where = null,
Sort sort = default,
Pagination limit = default);
-
- ///
- /// Get items (A wrapper around shows or collections) from a library.
- ///
- /// The slug of the library
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No library exist with the given slug.
- /// A list of items that match every filters
- public Task> GetFromLibrary(string slug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromLibrary(slug, where, new Sort(sort), limit);
}
///
@@ -431,21 +387,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a show.
- ///
- /// The ID of the show
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given ID.
- /// A list of items that match every filters
- Task> GetFromShow(int showID,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromShow(showID, where, new Sort(sort), limit);
-
///
/// Get people's roles from a show.
///
@@ -460,21 +401,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a show.
- ///
- /// The slug of the show
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given slug.
- /// A list of items that match every filters
- Task> GetFromShow(string showSlug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromShow(showSlug, where, new Sort(sort), limit);
-
///
/// Get people's roles from a person.
///
@@ -489,21 +415,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default);
- ///
- /// Get people's roles from a person.
- ///
- /// The id of the person
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given ID.
- /// A list of items that match every filters
- Task> GetFromPeople(int id,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromPeople(id, where, new Sort(sort), limit);
-
///
/// Get people's roles from a person.
///
@@ -517,21 +428,6 @@ namespace Kyoo.Abstractions.Controllers
Expression> where = null,
Sort sort = default,
Pagination limit = default);
-
- ///
- /// Get people's roles from a person.
- ///
- /// The slug of the person
- /// A filter function
- /// A sort by method
- /// How many items to return and where to start
- /// No exist with the given slug.
- /// A list of items that match every filters
- Task> GetFromPeople(string slug,
- [Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- ) => GetFromPeople(slug, where, new Sort(sort), limit);
}
///
@@ -551,21 +447,6 @@ namespace Kyoo.Abstractions.Controllers
Sort sort = default,
Pagination limit = default)
where T : class, IMetadata;
-
- ///
- /// Get a list of external ids that match all filters
- ///
- /// A predicate to add arbitrary filter
- /// A sort by expression
- /// Pagination information (where to start and how many to get)
- /// The type of metadata to retrieve
- /// A filtered list of external ids.
- Task> GetMetadataID([Optional] Expression> where,
- Expression> sort,
- Pagination limit = default
- )
- where T : class, IMetadata
- => GetMetadataID(where, new Sort(sort), limit);
}
///
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs b/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
index 7ded5348..0c56b2b1 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Identifier.cs
@@ -113,7 +113,7 @@ namespace Kyoo.Abstractions.Models.Utils
///
/// A matcher overload for nullable IDs. See
- ///
+ ///
/// for more details.
///
/// An expression to retrieve an ID from the type .
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs b/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
index 233b317d..935393b3 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Pagination.cs
@@ -33,15 +33,22 @@ namespace Kyoo.Abstractions.Controllers
///
public int? AfterID { get; }
+ ///
+ /// Should the previous page be returned instead of the next?
+ ///
+ public bool Reverse { get; }
+
///
/// Create a new instance.
///
/// Set the value
/// Set the value. If not specified, it will start from the start
- public Pagination(int count, int? afterID = null)
+ /// Should the previous page be returned instead of the next?
+ public Pagination(int count, int? afterID = null, bool reverse = false)
{
Count = count;
AfterID = afterID;
+ Reverse = reverse;
}
///
diff --git a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
index 1aa88673..4cafb788 100644
--- a/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
+++ b/back/src/Kyoo.Abstractions/Models/Utils/Sort.cs
@@ -17,7 +17,9 @@
// along with Kyoo. If not, see .
using System;
+using System.Linq;
using System.Linq.Expressions;
+using System.Reflection;
using Kyoo.Utils;
namespace Kyoo.Abstractions.Controllers
@@ -26,63 +28,73 @@ namespace Kyoo.Abstractions.Controllers
/// Information about how a query should be sorted. What factor should decide the sort and in which order.
///
/// For witch type this sort applies
- public readonly struct Sort
+ public record Sort
{
///
- /// The sort key. This member will be used to sort the results.
+ /// Sort by a specific key
///
- public Expression> Key { get; }
-
- ///
+ /// The sort keys. This members will be used to sort the results.
+ ///
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
- ///
- public bool Descendant { get; }
+ ///
+ public record By(string key, bool desendant = false) : Sort
+ {
+ ///
+ /// Sort by a specific key
+ ///
+ /// The sort keys. This members will be used to sort the results.
+ ///
+ /// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
+ ///
+ 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);
+ }
+ }
///
- /// Create a new instance.
+ /// Sort by multiple keys.
///
- /// The sort key given. It is assigned to .
- /// Should this be in descendant order? The default is false.
- /// If the given key is not a member.
- public Sort(Expression> key, bool descendant = false)
- {
- Key = key;
- Descendant = descendant;
+ /// The list of keys to sort by.
+ public record Conglomerate(params By[] list) : Sort;
- if (!Utility.IsPropertyExpression(Key))
- throw new ArgumentException("The given sort key is not valid.");
- }
+ /// The default sort method for the given type.
+ public record Default : Sort;
///
/// 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.
- public Sort(string sortBy)
+ /// A for the given string
+ public static Sort From(string sortBy)
{
if (string.IsNullOrEmpty(sortBy))
- {
- Key = null;
- Descendant = false;
- return;
- }
-
- string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
- string order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
-
- ParameterExpression param = Expression.Parameter(typeof(T), "x");
- MemberExpression property = Expression.Property(param, key);
- Key = property.Type.IsValueType
- ? Expression.Lambda>(Expression.Convert(property, typeof(object)), param)
- : Expression.Lambda>(property, param);
-
- Descendant = 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}.")
- };
+ return new Default();
+ if (sortBy.Contains(','))
+ return new Conglomerate(sortBy.Split(',').Select(By.From).ToArray());
+ return By.From(sortBy);
}
}
}
diff --git a/back/src/Kyoo.Abstractions/Models/WatchItem.cs b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
index bded4aec..10bdfae4 100644
--- a/back/src/Kyoo.Abstractions/Models/WatchItem.cs
+++ b/back/src/Kyoo.Abstractions/Models/WatchItem.cs
@@ -163,48 +163,46 @@ namespace Kyoo.Abstractions.Models
await library.Load(ep, x => x.Show);
await library.Load(ep, x => x.Tracks);
- Episode previous = null;
- Episode next = null;
- 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)
- );
- }
- }
+ // 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
{
@@ -225,8 +223,12 @@ namespace Kyoo.Abstractions.Models
Audios = ep.Tracks.Where(x => x.Type == StreamType.Audio).ToArray(),
Subtitles = ep.Tracks.Where(x => x.Type == StreamType.Subtitle).ToArray(),
Fonts = await transcoder.ListFonts(ep),
- PreviousEpisode = previous,
- NextEpisode = next,
+ PreviousEpisode = ep.Show.IsMovie
+ ? null
+ : (await library.GetAll(limit: new Pagination(1, ep.ID, true))).FirstOrDefault(),
+ NextEpisode = ep.Show.IsMovie
+ ? null
+ : (await library.GetAll(limit: new Pagination(1, ep.ID))).FirstOrDefault(),
Chapters = await _GetChapters(ep, fs),
IsMovie = ep.Show.IsMovie
};
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
index f105c6da..ab54d442 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/CollectionRepository.cs
@@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -44,7 +43,7 @@ namespace Kyoo.Core.Controllers
private readonly IProviderRepository _providers;
///
- protected override Expression> DefaultSort => x => x.Name;
+ protected override Sort DefaultSort => new Sort.By(nameof(Collection.Name));
///
/// Create a new .
@@ -61,11 +60,11 @@ namespace Kyoo.Core.Controllers
///
public override async Task> Search(string query)
{
- return await _database.Collections
- .Where(_database.Like(x => x.Name + " " + x.Slug, $"%{query}%"))
- .OrderBy(DefaultSort)
- .Take(20)
- .ToListAsync();
+ return await Sort(
+ _database.Collections
+ .Where(_database.Like(x => x.Name + " " + x.Slug, $"%{query}%"))
+ .Take(20)
+ ).ToListAsync();
}
///
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
index 4a139a33..6040b1d2 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/EpisodeRepository.cs
@@ -19,7 +19,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Linq.Expressions;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -51,7 +50,12 @@ namespace Kyoo.Core.Controllers
private readonly ITrackRepository _tracks;
///
- protected override Expression> DefaultSort => x => x.EpisodeNumber;
+ // Use absolute numbers by default and fallback to season/episodes if it does not exists.
+ protected override Sort DefaultSort => new Sort.Conglomerate(
+ new Sort.By(x => x.AbsoluteNumber),
+ new Sort.By(x => x.SeasonNumber),
+ new Sort.By(x => x.EpisodeNumber)
+ );
///
/// Create a new .
@@ -120,11 +124,12 @@ namespace Kyoo.Core.Controllers
///
public override async Task> Search(string query)
{
- List ret = await _database.Episodes
- .Include(x => x.Show)
- .Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null)
- .Where(_database.Like(x => x.Title, $"%{query}%"))
- .OrderBy(DefaultSort)
+ List ret = await Sort(
+ _database.Episodes
+ .Include(x => x.Show)
+ .Where(x => x.EpisodeNumber != null || x.AbsoluteNumber != null)
+ .Where(_database.Like(x => x.Title, $"%{query}%"))
+ )
.Take(20)
.ToListAsync();
foreach (Episode ep in ret)
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs
index eb12a4c4..de104312 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/GenreRepository.cs
@@ -39,7 +39,7 @@ namespace Kyoo.Core.Controllers
private readonly DatabaseContext _database;
///
- protected override Expression> DefaultSort => x => x.Slug;
+ protected override Sort DefaultSort => new Sort.By(x => x.Slug);
///
/// Create a new .
@@ -54,9 +54,10 @@ namespace Kyoo.Core.Controllers
///
public override async Task> Search(string query)
{
- return await _database.Genres
- .Where(_database.Like(x => x.Name, $"%{query}%"))
- .OrderBy(DefaultSort)
+ return await Sort(
+ _database.Genres
+ .Where(_database.Like(x => x.Name, $"%{query}%"))
+ )
.Take(20)
.ToListAsync();
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs
index 833a06cc..4ec4781e 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryItemRepository.cs
@@ -45,7 +45,7 @@ namespace Kyoo.Core.Controllers
private readonly Lazy _libraries;
///
- protected override Expression> DefaultSort => x => x.Title;
+ protected override Sort DefaultSort => new Sort.By(x => x.Title);
///
/// Create a new .
@@ -92,9 +92,10 @@ namespace Kyoo.Core.Controllers
///
public override async Task> Search(string query)
{
- return await _database.LibraryItems
- .Where(_database.Like(x => x.Title, $"%{query}%"))
- .OrderBy(DefaultSort)
+ return await Sort(
+ _database.LibraryItems
+ .Where(_database.Like(x => x.Title, $"%{query}%"))
+ )
.Take(20)
.ToListAsync();
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs
index 494273ff..76bd2858 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LibraryRepository.cs
@@ -45,7 +45,7 @@ namespace Kyoo.Core.Controllers
private readonly IProviderRepository _providers;
///
- protected override Expression> DefaultSort => x => x.ID;
+ protected override Sort DefaultSort => new Sort.By(x => x.ID);
///
/// Create a new instance.
@@ -62,9 +62,10 @@ namespace Kyoo.Core.Controllers
///
public override async Task> Search(string query)
{
- return await _database.Libraries
- .Where(_database.Like(x => x.Name + " " + x.Slug, $"%{query}%"))
- .OrderBy(DefaultSort)
+ return await Sort(
+ _database.Libraries
+ .Where(_database.Like(x => x.Name + " " + x.Slug, $"%{query}%"))
+ )
.Take(20)
.ToListAsync();
}
diff --git a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
index 59928d02..0cb0600e 100644
--- a/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
+++ b/back/src/Kyoo.Core/Controllers/Repositories/LocalRepository.cs
@@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
@@ -47,7 +48,7 @@ namespace Kyoo.Core.Controllers
///
/// The default sort order that will be used for this resource's type.
///
- protected abstract Expression> DefaultSort { get; }
+ protected abstract Sort DefaultSort { get; }
///
/// Create a new base with the given database handle.
@@ -61,6 +62,206 @@ namespace Kyoo.Core.Controllers
///
public Type RepositoryType => typeof(T);
+ ///
+ /// Sort the given query.
+ ///
+ /// The query to sort.
+ /// How to sort the query
+ /// The newly sorted query.
+ protected IOrderedQueryable Sort(IQueryable query, Sort sortBy = null)
+ {
+ sortBy ??= DefaultSort;
+
+ switch (sortBy)
+ {
+ case Sort.Default:
+ return Sort(query, DefaultSort);
+ case Sort.By(var key, var desc):
+ return desc
+ ? query.OrderByDescending(x => EF.Property