mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-18 05:30:34 +01:00
Always apply recursive when filters are requested
This commit is contained in:
@@ -321,24 +321,21 @@ public class ItemsController : BaseJellyfinApiController
|
||||
recursive = true;
|
||||
includeItemTypes = [BaseItemKind.Playlist];
|
||||
}
|
||||
else if (folder is ICollectionFolder)
|
||||
else if (folder is ICollectionFolder && includeItemTypes.Length == 0)
|
||||
{
|
||||
if (includeItemTypes.Length == 0)
|
||||
includeItemTypes = collectionType switch
|
||||
{
|
||||
includeItemTypes = collectionType switch
|
||||
{
|
||||
CollectionType.boxsets => [BaseItemKind.BoxSet],
|
||||
null => [BaseItemKind.Movie, BaseItemKind.Series],
|
||||
_ => []
|
||||
};
|
||||
}
|
||||
CollectionType.boxsets => [BaseItemKind.BoxSet],
|
||||
null => [BaseItemKind.Movie, BaseItemKind.Series],
|
||||
_ => []
|
||||
};
|
||||
}
|
||||
|
||||
// When the client doesn't specify recursive/includeItemTypes, force the query
|
||||
// through the database path where all filters (IsHD, genres, etc.) are applied.
|
||||
if (includeItemTypes.Length > 0)
|
||||
{
|
||||
recursive ??= true;
|
||||
}
|
||||
// includeItemTypes on a library lists its contents recursively rather than just its
|
||||
// immediate children, so default to a recursive query when the client didn't choose.
|
||||
if (folder is ICollectionFolder && includeItemTypes.Length > 0)
|
||||
{
|
||||
recursive ??= true;
|
||||
}
|
||||
|
||||
if (item is not UserRootFolder
|
||||
@@ -351,246 +348,248 @@ public class ItemsController : BaseJellyfinApiController
|
||||
return Unauthorized($"{user.Username} is not permitted to access Library {item.Name}.");
|
||||
}
|
||||
|
||||
if ((recursive.HasValue && recursive.Value) || ids.Length != 0 || item is not UserRootFolder)
|
||||
// Build the query up front so the dispatch below can decide the path from it.
|
||||
// Use search providers when searchTerm is provided. Providers return only IDs and scores;
|
||||
// items are loaded server-side via folder.GetItems below, which applies user-access filtering.
|
||||
Dictionary<Guid, float>? searchResultScores = null;
|
||||
Guid[] itemIds = ids;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
// Use search providers when searchTerm is provided. Providers return only IDs and scores;
|
||||
// items are loaded server-side via folder.GetItems below, which applies user-access filtering.
|
||||
Dictionary<Guid, float>? searchResultScores = null;
|
||||
Guid[] itemIds = ids;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(searchTerm))
|
||||
var searchProviderQuery = new SearchProviderQuery
|
||||
{
|
||||
var searchProviderQuery = new SearchProviderQuery
|
||||
{
|
||||
SearchTerm = searchTerm,
|
||||
UserId = userId,
|
||||
IncludeItemTypes = includeItemTypes,
|
||||
ExcludeItemTypes = excludeItemTypes,
|
||||
MediaTypes = mediaTypes,
|
||||
Limit = limit.HasValue ? limit.Value * 3 : null,
|
||||
ParentId = parentId
|
||||
};
|
||||
|
||||
var searchResults = await _searchManager.GetSearchResultsAsync(searchProviderQuery, HttpContext.RequestAborted).ConfigureAwait(false);
|
||||
if (searchResults.Count > 0)
|
||||
{
|
||||
searchResultScores = searchResults.ToDictionary(r => r.ItemId, r => r.Score);
|
||||
itemIds = ids.Length > 0
|
||||
? ids.Concat(searchResultScores.Keys).Distinct().ToArray()
|
||||
: searchResultScores.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IsPlayed = isPlayed,
|
||||
MediaTypes = mediaTypes,
|
||||
SearchTerm = searchTerm,
|
||||
UserId = userId,
|
||||
IncludeItemTypes = includeItemTypes,
|
||||
ExcludeItemTypes = excludeItemTypes,
|
||||
Recursive = recursive ?? false,
|
||||
OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
|
||||
IsFavorite = isFavorite,
|
||||
Limit = searchResultScores is null ? limit : null,
|
||||
StartIndex = searchResultScores is null ? startIndex : null,
|
||||
IsMissing = isMissing,
|
||||
IsUnaired = isUnaired,
|
||||
CollapseBoxSetItems = collapseBoxSetItems,
|
||||
NameLessThan = nameLessThan,
|
||||
NameStartsWith = nameStartsWith,
|
||||
NameStartsWithOrGreater = nameStartsWithOrGreater,
|
||||
HasImdbId = hasImdbId,
|
||||
IsPlaceHolder = isPlaceHolder,
|
||||
IsLocked = isLocked,
|
||||
MinWidth = minWidth,
|
||||
MinHeight = minHeight,
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight,
|
||||
Is3D = is3D,
|
||||
HasTvdbId = hasTvdbId,
|
||||
HasTmdbId = hasTmdbId,
|
||||
IsMovie = isMovie,
|
||||
IsSeries = isSeries,
|
||||
IsNews = isNews,
|
||||
IsKids = isKids,
|
||||
IsSports = isSports,
|
||||
HasOverview = hasOverview,
|
||||
HasOfficialRating = hasOfficialRating,
|
||||
HasParentalRating = hasParentalRating,
|
||||
HasSpecialFeature = hasSpecialFeature,
|
||||
HasSubtitles = hasSubtitles,
|
||||
HasThemeSong = hasThemeSong,
|
||||
HasThemeVideo = hasThemeVideo,
|
||||
HasTrailer = hasTrailer,
|
||||
IsHD = isHd,
|
||||
Is4K = is4K,
|
||||
Tags = tags,
|
||||
OfficialRatings = officialRatings,
|
||||
Genres = genres,
|
||||
ArtistIds = artistIds,
|
||||
AlbumArtistIds = albumArtistIds,
|
||||
ContributingArtistIds = contributingArtistIds,
|
||||
GenreIds = genreIds,
|
||||
StudioIds = studioIds,
|
||||
Person = person,
|
||||
PersonIds = personIds,
|
||||
PersonTypes = personTypes,
|
||||
Years = years,
|
||||
ImageTypes = imageTypes,
|
||||
VideoTypes = videoTypes,
|
||||
AdjacentTo = adjacentTo,
|
||||
ItemIds = itemIds,
|
||||
MinCommunityRating = minCommunityRating,
|
||||
MinCriticRating = minCriticRating,
|
||||
ParentId = parentId ?? Guid.Empty,
|
||||
IndexNumber = indexNumber,
|
||||
ParentIndexNumber = parentIndexNumber,
|
||||
EnableTotalRecordCount = enableTotalRecordCount,
|
||||
ExcludeItemIds = excludeItemIds,
|
||||
DtoOptions = dtoOptions,
|
||||
SearchTerm = searchResultScores is null ? searchTerm : null,
|
||||
MinDateLastSaved = minDateLastSaved?.ToUniversalTime(),
|
||||
MinDateLastSavedForUser = minDateLastSavedForUser?.ToUniversalTime(),
|
||||
MinPremiereDate = minPremiereDate?.ToUniversalTime(),
|
||||
MaxPremiereDate = maxPremiereDate?.ToUniversalTime(),
|
||||
AudioLanguages = audioLanguages,
|
||||
SubtitleLanguages = subtitleLanguages,
|
||||
LinkedChildAncestorIds = linkedChildAncestorIds,
|
||||
MediaTypes = mediaTypes,
|
||||
Limit = limit.HasValue ? limit.Value * 3 : null,
|
||||
ParentId = parentId
|
||||
};
|
||||
|
||||
if (ids.Length != 0 || !string.IsNullOrWhiteSpace(searchTerm))
|
||||
var searchResults = await _searchManager.GetSearchResultsAsync(searchProviderQuery, HttpContext.RequestAborted).ConfigureAwait(false);
|
||||
if (searchResults.Count > 0)
|
||||
{
|
||||
query.CollapseBoxSetItems = false;
|
||||
searchResultScores = searchResults.ToDictionary(r => r.ItemId, r => r.Score);
|
||||
itemIds = ids.Length > 0
|
||||
? ids.Concat(searchResultScores.Keys).Distinct().ToArray()
|
||||
: searchResultScores.Keys.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (query.SubtitleLanguages.Count > 0 && query.HasSubtitles.HasValue)
|
||||
var query = new InternalItemsQuery(user)
|
||||
{
|
||||
IsPlayed = isPlayed,
|
||||
MediaTypes = mediaTypes,
|
||||
IncludeItemTypes = includeItemTypes,
|
||||
ExcludeItemTypes = excludeItemTypes,
|
||||
Recursive = recursive ?? false,
|
||||
OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder),
|
||||
IsFavorite = isFavorite,
|
||||
Limit = searchResultScores is null ? limit : null,
|
||||
StartIndex = searchResultScores is null ? startIndex : null,
|
||||
IsMissing = isMissing,
|
||||
IsUnaired = isUnaired,
|
||||
CollapseBoxSetItems = collapseBoxSetItems,
|
||||
NameLessThan = nameLessThan,
|
||||
NameStartsWith = nameStartsWith,
|
||||
NameStartsWithOrGreater = nameStartsWithOrGreater,
|
||||
HasImdbId = hasImdbId,
|
||||
IsPlaceHolder = isPlaceHolder,
|
||||
IsLocked = isLocked,
|
||||
MinWidth = minWidth,
|
||||
MinHeight = minHeight,
|
||||
MaxWidth = maxWidth,
|
||||
MaxHeight = maxHeight,
|
||||
Is3D = is3D,
|
||||
HasTvdbId = hasTvdbId,
|
||||
HasTmdbId = hasTmdbId,
|
||||
IsMovie = isMovie,
|
||||
IsSeries = isSeries,
|
||||
IsNews = isNews,
|
||||
IsKids = isKids,
|
||||
IsSports = isSports,
|
||||
HasOverview = hasOverview,
|
||||
HasOfficialRating = hasOfficialRating,
|
||||
HasParentalRating = hasParentalRating,
|
||||
HasSpecialFeature = hasSpecialFeature,
|
||||
HasSubtitles = hasSubtitles,
|
||||
HasThemeSong = hasThemeSong,
|
||||
HasThemeVideo = hasThemeVideo,
|
||||
HasTrailer = hasTrailer,
|
||||
IsHD = isHd,
|
||||
Is4K = is4K,
|
||||
Tags = tags,
|
||||
OfficialRatings = officialRatings,
|
||||
Genres = genres,
|
||||
ArtistIds = artistIds,
|
||||
AlbumArtistIds = albumArtistIds,
|
||||
ContributingArtistIds = contributingArtistIds,
|
||||
GenreIds = genreIds,
|
||||
StudioIds = studioIds,
|
||||
Person = person,
|
||||
PersonIds = personIds,
|
||||
PersonTypes = personTypes,
|
||||
Years = years,
|
||||
ImageTypes = imageTypes,
|
||||
VideoTypes = videoTypes,
|
||||
AdjacentTo = adjacentTo,
|
||||
ItemIds = itemIds,
|
||||
MinCommunityRating = minCommunityRating,
|
||||
MinCriticRating = minCriticRating,
|
||||
ParentId = parentId ?? Guid.Empty,
|
||||
IndexNumber = indexNumber,
|
||||
ParentIndexNumber = parentIndexNumber,
|
||||
EnableTotalRecordCount = enableTotalRecordCount,
|
||||
ExcludeItemIds = excludeItemIds,
|
||||
DtoOptions = dtoOptions,
|
||||
SearchTerm = searchResultScores is null ? searchTerm : null,
|
||||
MinDateLastSaved = minDateLastSaved?.ToUniversalTime(),
|
||||
MinDateLastSavedForUser = minDateLastSavedForUser?.ToUniversalTime(),
|
||||
MinPremiereDate = minPremiereDate?.ToUniversalTime(),
|
||||
MaxPremiereDate = maxPremiereDate?.ToUniversalTime(),
|
||||
AudioLanguages = audioLanguages,
|
||||
SubtitleLanguages = subtitleLanguages,
|
||||
LinkedChildAncestorIds = linkedChildAncestorIds,
|
||||
};
|
||||
|
||||
if (ids.Length != 0 || !string.IsNullOrWhiteSpace(searchTerm))
|
||||
{
|
||||
query.CollapseBoxSetItems = false;
|
||||
}
|
||||
|
||||
if (query.SubtitleLanguages.Count > 0 && query.HasSubtitles.HasValue)
|
||||
{
|
||||
if (query.HasSubtitles.Value)
|
||||
{
|
||||
if (query.HasSubtitles.Value)
|
||||
// if we check for specific subtitles we don't need a separate check for subtitle existence
|
||||
query.HasSubtitles = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we search for items without subtitles, we don't need to check for subtitles of a specific language
|
||||
query.SubtitleLanguages = [];
|
||||
}
|
||||
}
|
||||
|
||||
// for filter values that rely on media streams, we need to include alternative and linked versions
|
||||
if (query.HasSubtitles.HasValue
|
||||
|| query.SubtitleLanguages.Count > 0
|
||||
|| query.AudioLanguages.Count > 0
|
||||
|| query.Is3D.HasValue
|
||||
|| query.IsHD.HasValue
|
||||
|| query.Is4K.HasValue
|
||||
|| query.VideoTypes.Length > 0
|
||||
)
|
||||
{
|
||||
query.IncludeOwnedItems = true;
|
||||
}
|
||||
|
||||
query.ApplyFilters(filters);
|
||||
|
||||
// Filter by Series Status
|
||||
if (seriesStatus.Length != 0)
|
||||
{
|
||||
query.SeriesStatuses = seriesStatus;
|
||||
}
|
||||
|
||||
// Exclude Blocked Unrated Items
|
||||
var blockedUnratedItems = user?.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems);
|
||||
if (blockedUnratedItems is not null)
|
||||
{
|
||||
query.BlockUnratedItems = blockedUnratedItems;
|
||||
}
|
||||
|
||||
// ExcludeLocationTypes
|
||||
if (excludeLocationTypes.Any(t => t == LocationType.Virtual))
|
||||
{
|
||||
query.IsVirtualItem = false;
|
||||
}
|
||||
|
||||
if (locationTypes.Length > 0 && locationTypes.Length < 4)
|
||||
{
|
||||
query.IsVirtualItem = locationTypes.Contains(LocationType.Virtual);
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrWhiteSpace(minOfficialRating))
|
||||
{
|
||||
query.MinParentalRating = _localization.GetRatingScore(minOfficialRating);
|
||||
}
|
||||
|
||||
// Max official rating
|
||||
if (!string.IsNullOrWhiteSpace(maxOfficialRating))
|
||||
{
|
||||
query.MaxParentalRating = _localization.GetRatingScore(maxOfficialRating);
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (artists.Length != 0)
|
||||
{
|
||||
query.ArtistIds = artists.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// if we check for specific subtitles we don't need a separate check for subtitle existence
|
||||
query.HasSubtitles = null;
|
||||
return _libraryManager.GetArtist(i, new DtoOptions(false));
|
||||
}
|
||||
else
|
||||
catch
|
||||
{
|
||||
// if we search for items without subtitles, we don't need to check for subtitles of a specific language
|
||||
query.SubtitleLanguages = [];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}).Where(i => i is not null).Select(i => i!.Id).ToArray();
|
||||
}
|
||||
|
||||
// for filter values that rely on media streams, we need to include alternative and linked versions
|
||||
if (query.HasSubtitles.HasValue
|
||||
|| query.SubtitleLanguages.Count > 0
|
||||
|| query.AudioLanguages.Count > 0
|
||||
|| query.Is3D.HasValue
|
||||
|| query.IsHD.HasValue
|
||||
|| query.Is4K.HasValue
|
||||
|| query.VideoTypes.Length > 0
|
||||
)
|
||||
// ExcludeArtistIds
|
||||
if (excludeArtistIds.Length != 0)
|
||||
{
|
||||
query.ExcludeArtistIds = excludeArtistIds;
|
||||
}
|
||||
|
||||
if (albumIds.Length != 0)
|
||||
{
|
||||
query.AlbumIds = albumIds;
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (albums.Length != 0)
|
||||
{
|
||||
query.AlbumIds = albums.SelectMany(i =>
|
||||
{
|
||||
query.IncludeOwnedItems = true;
|
||||
}
|
||||
return _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = [BaseItemKind.MusicAlbum], Name = i, Limit = 1 });
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
query.ApplyFilters(filters);
|
||||
|
||||
// Filter by Series Status
|
||||
if (seriesStatus.Length != 0)
|
||||
// Studios
|
||||
if (studios.Length != 0)
|
||||
{
|
||||
query.StudioIds = studios.Select(i =>
|
||||
{
|
||||
query.SeriesStatuses = seriesStatus;
|
||||
}
|
||||
|
||||
// Exclude Blocked Unrated Items
|
||||
var blockedUnratedItems = user?.GetPreferenceValues<UnratedItem>(PreferenceKind.BlockUnratedItems);
|
||||
if (blockedUnratedItems is not null)
|
||||
{
|
||||
query.BlockUnratedItems = blockedUnratedItems;
|
||||
}
|
||||
|
||||
// ExcludeLocationTypes
|
||||
if (excludeLocationTypes.Any(t => t == LocationType.Virtual))
|
||||
{
|
||||
query.IsVirtualItem = false;
|
||||
}
|
||||
|
||||
if (locationTypes.Length > 0 && locationTypes.Length < 4)
|
||||
{
|
||||
query.IsVirtualItem = locationTypes.Contains(LocationType.Virtual);
|
||||
}
|
||||
|
||||
// Min official rating
|
||||
if (!string.IsNullOrWhiteSpace(minOfficialRating))
|
||||
{
|
||||
query.MinParentalRating = _localization.GetRatingScore(minOfficialRating);
|
||||
}
|
||||
|
||||
// Max official rating
|
||||
if (!string.IsNullOrWhiteSpace(maxOfficialRating))
|
||||
{
|
||||
query.MaxParentalRating = _localization.GetRatingScore(maxOfficialRating);
|
||||
}
|
||||
|
||||
// Artists
|
||||
if (artists.Length != 0)
|
||||
{
|
||||
query.ArtistIds = artists.Select(i =>
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetArtist(i, new DtoOptions(false));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).Where(i => i is not null).Select(i => i!.Id).ToArray();
|
||||
}
|
||||
|
||||
// ExcludeArtistIds
|
||||
if (excludeArtistIds.Length != 0)
|
||||
{
|
||||
query.ExcludeArtistIds = excludeArtistIds;
|
||||
}
|
||||
|
||||
if (albumIds.Length != 0)
|
||||
{
|
||||
query.AlbumIds = albumIds;
|
||||
}
|
||||
|
||||
// Albums
|
||||
if (albums.Length != 0)
|
||||
{
|
||||
query.AlbumIds = albums.SelectMany(i =>
|
||||
{
|
||||
return _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = [BaseItemKind.MusicAlbum], Name = i, Limit = 1 });
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
// Studios
|
||||
if (studios.Length != 0)
|
||||
{
|
||||
query.StudioIds = studios.Select(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return _libraryManager.GetStudio(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).Where(i => i is not null).Select(i => i!.Id).ToArray();
|
||||
}
|
||||
|
||||
// Apply default sorting if none requested
|
||||
if (query.OrderBy.Count == 0)
|
||||
{
|
||||
// Albums by artist
|
||||
if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.MusicAlbum)
|
||||
{
|
||||
query.OrderBy = [(ItemSortBy.ProductionYear, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Ascending)];
|
||||
return _libraryManager.GetStudio(i);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).Where(i => i is not null).Select(i => i!.Id).ToArray();
|
||||
}
|
||||
|
||||
// Apply default sorting if none requested
|
||||
if (query.OrderBy.Count == 0)
|
||||
{
|
||||
// Albums by artist
|
||||
if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && query.IncludeItemTypes[0] == BaseItemKind.MusicAlbum)
|
||||
{
|
||||
query.OrderBy = [(ItemSortBy.ProductionYear, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Ascending)];
|
||||
}
|
||||
}
|
||||
|
||||
query.Parent = null;
|
||||
query.Parent = null;
|
||||
|
||||
// At the user root an unfiltered, non-recursive request is a plain listing of the user's libraries
|
||||
if ((recursive.HasValue && recursive.Value) || ids.Length != 0 || item is not UserRootFolder || query.HasFilters)
|
||||
{
|
||||
// folder.GetItems applies user-access filtering via the InternalItemsQuery's User.
|
||||
result = folder.GetItems(query);
|
||||
if (searchResultScores is not null && searchResultScores.Count > 0)
|
||||
|
||||
@@ -72,6 +72,102 @@ namespace MediaBrowser.Controller.Entities
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the query carries any criteria that narrows the
|
||||
/// result set, as opposed to user context, pagination, sorting or DTO options.
|
||||
/// </summary>
|
||||
public bool HasFilters =>
|
||||
IncludeItemTypes.Length > 0
|
||||
|| ExcludeItemTypes.Length > 0
|
||||
|| Genres.Count > 0
|
||||
|| GenreIds.Count > 0
|
||||
|| Years.Length > 0
|
||||
|| Tags.Length > 0
|
||||
|| ExcludeTags.Length > 0
|
||||
|| OfficialRatings.Length > 0
|
||||
|| StudioIds.Length > 0
|
||||
|| ArtistIds.Length > 0
|
||||
|| AlbumArtistIds.Length > 0
|
||||
|| ContributingArtistIds.Length > 0
|
||||
|| ExcludeArtistIds.Length > 0
|
||||
|| AlbumIds.Length > 0
|
||||
|| PersonIds.Length > 0
|
||||
|| PersonTypes.Length > 0
|
||||
|| MediaTypes.Length > 0
|
||||
|| VideoTypes.Length > 0
|
||||
|| ImageTypes.Length > 0
|
||||
|| SeriesStatuses.Length > 0
|
||||
|| ItemIds.Length > 0
|
||||
|| ExcludeItemIds.Length > 0
|
||||
|| AudioLanguages.Count > 0
|
||||
|| SubtitleLanguages.Count > 0
|
||||
|| LinkedChildAncestorIds.Length > 0
|
||||
|| AncestorIds.Length > 0
|
||||
|| IsFavorite.HasValue
|
||||
|| IsFavoriteOrLiked.HasValue
|
||||
|| IsLiked.HasValue
|
||||
|| IsPlayed.HasValue
|
||||
|| IsResumable.HasValue
|
||||
|| IsFolder.HasValue
|
||||
|| IsMissing.HasValue
|
||||
|| IsUnaired.HasValue
|
||||
|| IsSpecialSeason.HasValue
|
||||
|| Is3D.HasValue
|
||||
|| IsHD.HasValue
|
||||
|| Is4K.HasValue
|
||||
|| IsLocked.HasValue
|
||||
|| IsPlaceHolder.HasValue
|
||||
|| IsMovie.HasValue
|
||||
|| IsSports.HasValue
|
||||
|| IsKids.HasValue
|
||||
|| IsNews.HasValue
|
||||
|| IsSeries.HasValue
|
||||
|| IsAiring.HasValue
|
||||
|| IsVirtualItem.HasValue
|
||||
|| HasImdbId.HasValue
|
||||
|| HasTmdbId.HasValue
|
||||
|| HasTvdbId.HasValue
|
||||
|| HasOverview.HasValue
|
||||
|| HasOfficialRating.HasValue
|
||||
|| HasParentalRating.HasValue
|
||||
|| HasThemeSong.HasValue
|
||||
|| HasThemeVideo.HasValue
|
||||
|| HasSubtitles.HasValue
|
||||
|| HasSpecialFeature.HasValue
|
||||
|| HasTrailer.HasValue
|
||||
|| HasChapterImages.HasValue
|
||||
|| MinCriticRating.HasValue
|
||||
|| MinCommunityRating.HasValue
|
||||
|| MinParentalRating is not null
|
||||
|| MinIndexNumber.HasValue
|
||||
|| MinParentAndIndexNumber.HasValue
|
||||
|| IndexNumber.HasValue
|
||||
|| ParentIndexNumber.HasValue
|
||||
|| AiredDuringSeason.HasValue
|
||||
|| MinWidth.HasValue
|
||||
|| MinHeight.HasValue
|
||||
|| MaxWidth.HasValue
|
||||
|| MaxHeight.HasValue
|
||||
|| MinPremiereDate.HasValue
|
||||
|| MaxPremiereDate.HasValue
|
||||
|| MinStartDate.HasValue
|
||||
|| MaxStartDate.HasValue
|
||||
|| MinEndDate.HasValue
|
||||
|| MaxEndDate.HasValue
|
||||
|| MinDateCreated.HasValue
|
||||
|| MinDateLastSaved.HasValue
|
||||
|| MinDateLastSavedForUser.HasValue
|
||||
|| AdjacentTo.HasValue
|
||||
|| !string.IsNullOrEmpty(NameStartsWith)
|
||||
|| !string.IsNullOrEmpty(NameStartsWithOrGreater)
|
||||
|| !string.IsNullOrEmpty(NameLessThan)
|
||||
|| !string.IsNullOrEmpty(NameContains)
|
||||
|| !string.IsNullOrEmpty(MinSortName)
|
||||
|| !string.IsNullOrEmpty(Name)
|
||||
|| !string.IsNullOrEmpty(Person)
|
||||
|| !string.IsNullOrEmpty(SearchTerm)
|
||||
|| !string.IsNullOrEmpty(Path);
|
||||
|
||||
public bool Recursive { get; set; }
|
||||
|
||||
public int? StartIndex { get; set; }
|
||||
|
||||
@@ -69,8 +69,14 @@ namespace MediaBrowser.Controller.Entities
|
||||
|
||||
protected override QueryResult<BaseItem> GetItemsInternal(InternalItemsQuery query)
|
||||
{
|
||||
if (query.Recursive)
|
||||
// The user root holds no items of its own - a plain listing returns the user's
|
||||
// views. But a request carrying any filter is a search across the libraries, so
|
||||
// resolve it through the recursive query path even when Recursive wasn't set;
|
||||
// otherwise the filters would be silently dropped. Recursive is set so the
|
||||
// downstream query (ancestor/top-parent scoping) treats it as a recursive search.
|
||||
if (query.Recursive || query.HasFilters)
|
||||
{
|
||||
query.Recursive = true;
|
||||
return QueryRecursive(query);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user