mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-05-24 02:02:29 -04:00
parent
a123a2cb22
commit
07f07ba6bc
@ -7,11 +7,8 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@ -1209,45 +1206,6 @@ public sealed class BaseItemRepository
|
||||
return query.IncludeItemTypes.Length == 0 || query.IncludeItemTypes.Contains(type);
|
||||
}
|
||||
|
||||
private Expression<Func<BaseItemEntity, object>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query)
|
||||
{
|
||||
#pragma warning disable CS8603 // Possible null reference return.
|
||||
return sortBy switch
|
||||
{
|
||||
ItemSortBy.AirTime => e => e.SortName, // TODO
|
||||
ItemSortBy.Runtime => e => e.RunTimeTicks,
|
||||
ItemSortBy.Random => e => EF.Functions.Random(),
|
||||
ItemSortBy.DatePlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.LastPlayedDate,
|
||||
ItemSortBy.PlayCount => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.PlayCount,
|
||||
ItemSortBy.IsFavoriteOrLiked => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.IsFavorite,
|
||||
ItemSortBy.IsFolder => e => e.IsFolder,
|
||||
ItemSortBy.IsPlayed => e => e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
|
||||
ItemSortBy.IsUnplayed => e => !e.UserData!.FirstOrDefault(f => f.UserId == query.User!.Id)!.Played,
|
||||
ItemSortBy.DateLastContentAdded => e => e.DateLastMediaAdded,
|
||||
ItemSortBy.Artist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.AlbumArtist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.Studio => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.OfficialRating => e => e.InheritedParentalRatingValue,
|
||||
// ItemSortBy.SeriesDatePlayed => "(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)",
|
||||
ItemSortBy.SeriesSortName => e => e.SeriesName,
|
||||
// ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
|
||||
ItemSortBy.Album => e => e.Album,
|
||||
ItemSortBy.DateCreated => e => e.DateCreated,
|
||||
ItemSortBy.PremiereDate => e => e.PremiereDate,
|
||||
ItemSortBy.StartDate => e => e.StartDate,
|
||||
ItemSortBy.Name => e => e.Name,
|
||||
ItemSortBy.CommunityRating => e => e.CommunityRating,
|
||||
ItemSortBy.ProductionYear => e => e.ProductionYear,
|
||||
ItemSortBy.CriticRating => e => e.CriticRating,
|
||||
ItemSortBy.VideoBitRate => e => e.TotalBitrate,
|
||||
ItemSortBy.ParentIndexNumber => e => e.ParentIndexNumber,
|
||||
ItemSortBy.IndexNumber => e => e.IndexNumber,
|
||||
_ => e => e.SortName
|
||||
};
|
||||
#pragma warning restore CS8603 // Possible null reference return.
|
||||
|
||||
}
|
||||
|
||||
private bool EnableGroupByPresentationUniqueKey(InternalItemsQuery query)
|
||||
{
|
||||
if (!query.GroupByPresentationUniqueKey)
|
||||
@ -1302,7 +1260,7 @@ public sealed class BaseItemRepository
|
||||
var firstOrdering = orderBy.FirstOrDefault();
|
||||
if (firstOrdering != default)
|
||||
{
|
||||
var expression = MapOrderByField(firstOrdering.OrderBy, filter);
|
||||
var expression = OrderMapper.MapOrderByField(firstOrdering.OrderBy, filter);
|
||||
if (firstOrdering.SortOrder == SortOrder.Ascending)
|
||||
{
|
||||
orderedQuery = query.OrderBy(expression);
|
||||
@ -1327,7 +1285,7 @@ public sealed class BaseItemRepository
|
||||
|
||||
foreach (var item in orderBy.Skip(1))
|
||||
{
|
||||
var expression = MapOrderByField(item.OrderBy, filter);
|
||||
var expression = OrderMapper.MapOrderByField(item.OrderBy, filter);
|
||||
if (item.SortOrder == SortOrder.Ascending)
|
||||
{
|
||||
orderedQuery = orderedQuery!.ThenBy(expression);
|
||||
|
57
Jellyfin.Server.Implementations/Item/OrderMapper.cs
Normal file
57
Jellyfin.Server.Implementations/Item/OrderMapper.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Item;
|
||||
|
||||
/// <summary>
|
||||
/// Static class for methods which maps types of ordering to their respecting ordering functions.
|
||||
/// </summary>
|
||||
public static class OrderMapper
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates Func to be executed later with a given BaseItemEntity input for sorting items on query.
|
||||
/// </summary>
|
||||
/// <param name="sortBy">Item property to sort by.</param>
|
||||
/// <param name="query">Context Query.</param>
|
||||
/// <returns>Func to be executed later for sorting query.</returns>
|
||||
public static Expression<Func<BaseItemEntity, object?>> MapOrderByField(ItemSortBy sortBy, InternalItemsQuery query)
|
||||
{
|
||||
return sortBy switch
|
||||
{
|
||||
ItemSortBy.AirTime => e => e.SortName, // TODO
|
||||
ItemSortBy.Runtime => e => e.RunTimeTicks,
|
||||
ItemSortBy.Random => e => EF.Functions.Random(),
|
||||
ItemSortBy.DatePlayed => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.LastPlayedDate,
|
||||
ItemSortBy.PlayCount => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.PlayCount,
|
||||
ItemSortBy.IsFavoriteOrLiked => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.IsFavorite,
|
||||
ItemSortBy.IsFolder => e => e.IsFolder,
|
||||
ItemSortBy.IsPlayed => e => e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
|
||||
ItemSortBy.IsUnplayed => e => !e.UserData!.FirstOrDefault(f => f.UserId.Equals(query.User!.Id))!.Played,
|
||||
ItemSortBy.DateLastContentAdded => e => e.DateLastMediaAdded,
|
||||
ItemSortBy.Artist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Artist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.AlbumArtist => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.AlbumArtist).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.Studio => e => e.ItemValues!.Where(f => f.ItemValue.Type == ItemValueType.Studios).Select(f => f.ItemValue.CleanValue).FirstOrDefault(),
|
||||
ItemSortBy.OfficialRating => e => e.InheritedParentalRatingValue,
|
||||
// ItemSortBy.SeriesDatePlayed => "(Select MAX(LastPlayedDate) from TypedBaseItems B" + GetJoinUserDataText(query) + " where Played=1 and B.SeriesPresentationUniqueKey=A.PresentationUniqueKey)",
|
||||
ItemSortBy.SeriesSortName => e => e.SeriesName,
|
||||
// ItemSortBy.AiredEpisodeOrder => "AiredEpisodeOrder",
|
||||
ItemSortBy.Album => e => e.Album,
|
||||
ItemSortBy.DateCreated => e => e.DateCreated,
|
||||
ItemSortBy.PremiereDate => e => (e.PremiereDate ?? (e.ProductionYear.HasValue ? DateTime.MinValue.AddYears(e.ProductionYear.Value - 1) : null)),
|
||||
ItemSortBy.StartDate => e => e.StartDate,
|
||||
ItemSortBy.Name => e => e.Name,
|
||||
ItemSortBy.CommunityRating => e => e.CommunityRating,
|
||||
ItemSortBy.ProductionYear => e => e.ProductionYear,
|
||||
ItemSortBy.CriticRating => e => e.CriticRating,
|
||||
ItemSortBy.VideoBitRate => e => e.TotalBitrate,
|
||||
ItemSortBy.ParentIndexNumber => e => e.ParentIndexNumber,
|
||||
ItemSortBy.IndexNumber => e => e.IndexNumber,
|
||||
_ => e => e.SortName
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using Jellyfin.Data.Entities;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Server.Implementations.Item;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Server.Implementations.Tests.Item;
|
||||
|
||||
public class OrderMapperTests
|
||||
{
|
||||
[Fact]
|
||||
public void ShouldReturnMappedOrderForSortingByPremierDate()
|
||||
{
|
||||
var orderFunc = OrderMapper.MapOrderByField(ItemSortBy.PremiereDate, new InternalItemsQuery()).Compile();
|
||||
|
||||
var expectedDate = new DateTime(1, 2, 3);
|
||||
var expectedProductionYearDate = new DateTime(4, 1, 1);
|
||||
|
||||
var entityWithOnlyProductionYear = new BaseItemEntity { Id = Guid.NewGuid(), Type = "Test", ProductionYear = expectedProductionYearDate.Year };
|
||||
var entityWithOnlyPremierDate = new BaseItemEntity { Id = Guid.NewGuid(), Type = "Test", PremiereDate = expectedDate };
|
||||
var entityWithBothPremierDateAndProductionYear = new BaseItemEntity { Id = Guid.NewGuid(), Type = "Test", PremiereDate = expectedDate, ProductionYear = expectedProductionYearDate.Year };
|
||||
var entityWithoutEitherPremierDateOrProductionYear = new BaseItemEntity { Id = Guid.NewGuid(), Type = "Test" };
|
||||
|
||||
var resultWithOnlyProductionYear = orderFunc(entityWithOnlyProductionYear);
|
||||
var resultWithOnlyPremierDate = orderFunc(entityWithOnlyPremierDate);
|
||||
var resultWithBothPremierDateAndProductionYear = orderFunc(entityWithBothPremierDateAndProductionYear);
|
||||
var resultWithoutEitherPremierDateOrProductionYear = orderFunc(entityWithoutEitherPremierDateOrProductionYear);
|
||||
|
||||
Assert.Equal(resultWithOnlyProductionYear, expectedProductionYearDate);
|
||||
Assert.Equal(resultWithOnlyPremierDate, expectedDate);
|
||||
Assert.Equal(resultWithBothPremierDateAndProductionYear, expectedDate);
|
||||
Assert.Null(resultWithoutEitherPremierDateOrProductionYear);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user