mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-10-26 16:45:09 +00:00
Merge pull request #17898 from Shadowghost/filters2
Populate missing tags array in Filters2
This commit is contained in:
6 files changed
+120
No files matched your search
@@ -4127,6 +4127,18 @@ namespace Emby.Server.Implementations.Library
|
||||
return _itemRepository.GetQueryFiltersLegacy(query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> GetTagNames(InternalItemsQuery query)
|
||||
{
|
||||
if (query.User is not null)
|
||||
{
|
||||
AddUserToQuery(query, query.User);
|
||||
}
|
||||
|
||||
SetTopParentOrAncestorIds(query);
|
||||
return _itemRepository.GetTagNames(query);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType)
|
||||
{
|
||||
|
||||
@@ -178,16 +178,35 @@ public class FilterController : BaseJellyfinApiController
|
||||
IsSeries = isSeries
|
||||
};
|
||||
|
||||
var tagQuery = new InternalItemsQuery(user)
|
||||
{
|
||||
IncludeItemTypes = includeItemTypes,
|
||||
DtoOptions = new DtoOptions
|
||||
{
|
||||
Fields = Array.Empty<ItemFields>(),
|
||||
EnableImages = false,
|
||||
EnableUserData = false
|
||||
},
|
||||
IsAiring = isAiring,
|
||||
IsMovie = isMovie,
|
||||
IsSports = isSports,
|
||||
IsKids = isKids,
|
||||
IsNews = isNews,
|
||||
IsSeries = isSeries
|
||||
};
|
||||
|
||||
if ((recursive ?? true) || parentItem is UserView || parentItem is ICollectionFolder)
|
||||
{
|
||||
var ancestorIds = parentItem is null ? Array.Empty<Guid>() : new[] { parentItem.Id };
|
||||
genreQuery.AncestorIds = ancestorIds;
|
||||
streamLanguageQuery.AncestorIds = ancestorIds;
|
||||
tagQuery.AncestorIds = ancestorIds;
|
||||
}
|
||||
else
|
||||
{
|
||||
genreQuery.Parent = parentItem;
|
||||
streamLanguageQuery.Parent = parentItem;
|
||||
tagQuery.Parent = parentItem;
|
||||
}
|
||||
|
||||
if ((includeItemTypes.Contains(BaseItemKind.Series) || includeItemTypes.Contains(BaseItemKind.Season))
|
||||
@@ -218,6 +237,8 @@ public class FilterController : BaseJellyfinApiController
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
filters.Tags = _libraryManager.GetTagNames(tagQuery);
|
||||
|
||||
if (includeItemTypes.Contains(BaseItemKind.Movie)
|
||||
|| includeItemTypes.Contains(BaseItemKind.Series)
|
||||
|| includeItemTypes.Contains(BaseItemKind.Season)
|
||||
|
||||
@@ -117,6 +117,35 @@ public sealed partial class BaseItemRepository
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IReadOnlyList<string> GetTagNames(InternalItemsQuery filter)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(filter);
|
||||
PrepareFilterQuery(filter);
|
||||
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
var baseQuery = PrepareItemQuery(context, filter);
|
||||
baseQuery = TranslateQuery(baseQuery, context, filter);
|
||||
|
||||
var matchingItemIds = baseQuery.Select(e => e.Id);
|
||||
|
||||
// Project the join before grouping. Grouping over the ItemValue navigation instead makes EF
|
||||
// re-resolve the aggregate as a correlated subquery per group, which is orders of magnitude slower.
|
||||
return context.ItemValuesMap
|
||||
.AsNoTracking()
|
||||
.Join(
|
||||
context.ItemValues,
|
||||
ivm => ivm.ItemValueId,
|
||||
iv => iv.ItemValueId,
|
||||
(ivm, iv) => new { ivm.ItemId, iv.Type, iv.CleanValue, iv.Value })
|
||||
.Where(iv => iv.Type == ItemValueType.Tags)
|
||||
.Where(iv => matchingItemIds.Contains(iv.ItemId))
|
||||
.GroupBy(iv => iv.CleanValue)
|
||||
.Select(g => g.Min(iv => iv.Value)!)
|
||||
.OrderBy(t => t)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private string[] GetItemValueNames(IReadOnlyList<ItemValueType> itemValueTypes, IReadOnlyList<string> withItemTypes, IReadOnlyList<string> excludeItemTypes)
|
||||
{
|
||||
using var context = _dbProvider.CreateDbContext();
|
||||
|
||||
@@ -832,6 +832,13 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <returns>Aggregated filter values.</returns>
|
||||
QueryFiltersLegacy GetQueryFiltersLegacy(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all distinct tags of the matching items.
|
||||
/// </summary>
|
||||
/// <param name="query">The query filter.</param>
|
||||
/// <returns>List of tags.</returns>
|
||||
IReadOnlyList<string> GetTagNames(InternalItemsQuery query);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all language codes of the provided stream type.
|
||||
/// </summary>
|
||||
|
||||
@@ -128,6 +128,13 @@ public interface IItemRepository
|
||||
/// <returns>List of language codes.</returns>
|
||||
public IReadOnlyList<string> GetMediaStreamLanguages(InternalItemsQuery filter, MediaStreamType mediaStreamType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all distinct tags of the matching base items.
|
||||
/// </summary>
|
||||
/// <param name="filter">The query filter.</param>
|
||||
/// <returns>The list of tags.</returns>
|
||||
IReadOnlyList<string> GetTagNames(InternalItemsQuery filter);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all artist names.
|
||||
/// </summary>
|
||||
|
||||
@@ -103,6 +103,50 @@ public sealed class BaseItemRepositoryItemValueTests : SqliteDbTestFixture
|
||||
Assert.Equal(["Genre Leak"], result.Genres);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTagNames_GroupsAndFiltersItemValues()
|
||||
{
|
||||
var movie = CreateMovieEntity(Guid.NewGuid(), "Movie");
|
||||
var otherMovie = CreateMovieEntity(Guid.NewGuid(), "Other Movie");
|
||||
var audio = new BaseItemEntity
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Type = _audioTypeName,
|
||||
Name = "Excluded Audio",
|
||||
MediaType = "Audio",
|
||||
IsMovie = false,
|
||||
IsFolder = false,
|
||||
IsVirtualItem = false
|
||||
};
|
||||
var tag = CreateItemValue(ItemValueType.Tags, "Alpha", "alpha");
|
||||
var duplicateTag = CreateItemValue(ItemValueType.Tags, "alpha", "alpha");
|
||||
var otherTag = CreateItemValue(ItemValueType.Tags, "Beta", "beta");
|
||||
var inheritedTag = CreateItemValue(ItemValueType.InheritedTags, "Inherited", "inherited");
|
||||
var genre = CreateItemValue(ItemValueType.Genre, "Genre Leak", "genre leak");
|
||||
var excludedTag = CreateItemValue(ItemValueType.Tags, "Excluded Tag", "excluded tag");
|
||||
|
||||
using (var context = CreateDbContext())
|
||||
{
|
||||
context.BaseItems.AddRange(movie, otherMovie, audio);
|
||||
context.ItemValues.AddRange(tag, duplicateTag, otherTag, inheritedTag, genre, excludedTag);
|
||||
context.ItemValuesMap.AddRange(
|
||||
CreateMap(movie, tag),
|
||||
CreateMap(movie, duplicateTag),
|
||||
CreateMap(otherMovie, otherTag),
|
||||
CreateMap(movie, inheritedTag),
|
||||
CreateMap(movie, genre),
|
||||
CreateMap(audio, excludedTag));
|
||||
context.SaveChanges();
|
||||
}
|
||||
|
||||
var result = _repository.GetTagNames(new InternalItemsQuery(new Database.Implementations.Entities.User("test", "auth", "reset"))
|
||||
{
|
||||
IncludeItemTypes = [BaseItemKind.Movie]
|
||||
});
|
||||
|
||||
Assert.Equal(["Alpha", "Beta"], result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetGenreNames_GroupsAndFiltersMappedItemValues()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user