< Summary - Jellyfin

Information
Class: MediaBrowser.Controller.Entities.UserViewBuilder
Assembly: MediaBrowser.Controller
File(s): /srv/git/jellyfin/MediaBrowser.Controller/Entities/UserViewBuilder.cs
Line coverage
11%
Covered lines: 48
Uncovered lines: 358
Coverable lines: 406
Total lines: 911
Line coverage: 11.8%
Branch coverage
30%
Covered branches: 72
Total branches: 240
Branch coverage: 30%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 3/26/2026 - 12:14:14 AM Line coverage: 12.6% (57/450) Branch coverage: 30.5% (91/298) Total lines: 10275/4/2026 - 12:15:16 AM Line coverage: 12% (48/400) Branch coverage: 30.2% (72/238) Total lines: 8976/30/2026 - 12:15:32 AM Line coverage: 11.8% (48/406) Branch coverage: 30% (72/240) Total lines: 911 3/26/2026 - 12:14:14 AM Line coverage: 12.6% (57/450) Branch coverage: 30.5% (91/298) Total lines: 10275/4/2026 - 12:15:16 AM Line coverage: 12% (48/400) Branch coverage: 30.2% (72/238) Total lines: 8976/30/2026 - 12:15:32 AM Line coverage: 11.8% (48/406) Branch coverage: 30% (72/240) Total lines: 911

Coverage delta

Coverage delta 1 -1

Metrics

File(s)

/srv/git/jellyfin/MediaBrowser.Controller/Entities/UserViewBuilder.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Globalization;
 8using System.Linq;
 9using Jellyfin.Data;
 10using Jellyfin.Data.Enums;
 11using Jellyfin.Database.Implementations.Entities;
 12using Jellyfin.Database.Implementations.Enums;
 13using Jellyfin.Extensions;
 14using MediaBrowser.Controller.Library;
 15using MediaBrowser.Controller.TV;
 16using MediaBrowser.Model.Entities;
 17using MediaBrowser.Model.Querying;
 18using Microsoft.Extensions.Logging;
 19using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
 20
 21namespace MediaBrowser.Controller.Entities
 22{
 23    public class UserViewBuilder
 24    {
 25        private readonly IUserViewManager _userViewManager;
 26        private readonly ILibraryManager _libraryManager;
 27        private readonly ILogger<BaseItem> _logger;
 28        private readonly IUserDataManager _userDataManager;
 29        private readonly ITVSeriesManager _tvSeriesManager;
 30
 31        public UserViewBuilder(
 32            IUserViewManager userViewManager,
 33            ILibraryManager libraryManager,
 34            ILogger<BaseItem> logger,
 35            IUserDataManager userDataManager,
 36            ITVSeriesManager tvSeriesManager)
 37        {
 038            _userViewManager = userViewManager;
 039            _libraryManager = libraryManager;
 040            _logger = logger;
 041            _userDataManager = userDataManager;
 042            _tvSeriesManager = tvSeriesManager;
 043        }
 44
 45        public QueryResult<BaseItem> GetUserItems(Folder queryParent, Folder displayParent, CollectionType? viewType, In
 46        {
 047            var user = query.User;
 48
 49            // if (query.IncludeItemTypes is not null &&
 50            //    query.IncludeItemTypes.Length == 1 &&
 51            //    string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
 52            // {
 53            //    if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
 54            //    {
 55            //        return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
 56            //    }
 57            // }
 58
 59            switch (viewType)
 60            {
 61                case CollectionType.folders:
 062                    return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query);
 63
 64                case CollectionType.books:
 065                    return GetBooks(queryParent, user, query);
 66
 67                case CollectionType.tvshows:
 068                    return GetTvView(queryParent, user, query);
 69
 70                case CollectionType.movies:
 071                    return GetMovieFolders(queryParent, user, query);
 72
 73                case CollectionType.tvshowseries:
 074                    return GetTvSeries(queryParent, user, query);
 75
 76                case CollectionType.tvgenres:
 077                    return GetTvGenres(queryParent, user, query);
 78
 79                case CollectionType.tvgenre:
 080                    return GetTvGenreItems(queryParent, displayParent, user, query);
 81
 82                case CollectionType.tvresume:
 083                    return GetTvResume(queryParent, user, query);
 84
 85                case CollectionType.tvnextup:
 086                    return GetTvNextUp(queryParent, query);
 87
 88                case CollectionType.tvlatest:
 089                    return GetTvLatest(queryParent, user, query);
 90
 91                case CollectionType.moviefavorites:
 092                    return GetFavoriteMovies(queryParent, user, query);
 93
 94                case CollectionType.movielatest:
 095                    return GetMovieLatest(queryParent, user, query);
 96
 97                case CollectionType.moviegenres:
 098                    return GetMovieGenres(queryParent, user, query);
 99
 100                case CollectionType.moviegenre:
 0101                    return GetMovieGenreItems(queryParent, displayParent, user, query);
 102
 103                case CollectionType.movieresume:
 0104                    return GetMovieResume(queryParent, user, query);
 105
 106                case CollectionType.moviemovies:
 0107                    return GetMovieMovies(queryParent, user, query);
 108
 109                case CollectionType.moviecollection:
 0110                    return GetMovieCollections(user, query);
 111
 112                case CollectionType.tvfavoriteepisodes:
 0113                    return GetFavoriteEpisodes(queryParent, user, query);
 114
 115                case CollectionType.tvfavoriteseries:
 0116                    return GetFavoriteSeries(queryParent, user, query);
 117
 118                default:
 119                    {
 0120                        if (queryParent is UserView)
 121                        {
 0122                            return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, 
 123                        }
 124
 0125                        return queryParent.GetItems(query);
 126                    }
 127            }
 128        }
 129
 130        private int GetSpecialItemsLimit()
 131        {
 0132            return 50;
 133        }
 134
 135        private QueryResult<BaseItem> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
 136        {
 0137            if (query.Recursive)
 138            {
 0139                query.Recursive = true;
 0140                query.SetUser(user);
 141
 0142                if (query.IncludeItemTypes.Length == 0)
 143                {
 0144                    query.IncludeItemTypes = [BaseItemKind.Movie];
 145                }
 146
 0147                return parent.QueryRecursive(query);
 148            }
 149
 0150            var list = new List<BaseItem>
 0151            {
 0152                GetUserView(CollectionType.movieresume, "HeaderContinueWatching", "0", parent),
 0153                GetUserView(CollectionType.movielatest, "Latest", "1", parent),
 0154                GetUserView(CollectionType.moviemovies, "Movies", "2", parent),
 0155                GetUserView(CollectionType.moviecollection, "Collections", "3", parent),
 0156                GetUserView(CollectionType.moviefavorites, "Favorites", "4", parent),
 0157                GetUserView(CollectionType.moviegenres, "Genres", "5", parent)
 0158            };
 159
 0160            return GetResult(list, query);
 161        }
 162
 163        private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
 164        {
 0165            query.Recursive = true;
 0166            query.Parent = parent;
 0167            query.SetUser(user);
 0168            query.IsFavorite = true;
 0169            query.IncludeItemTypes = [BaseItemKind.Movie];
 170
 0171            return _libraryManager.GetItemsResult(query);
 172        }
 173
 174        private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query)
 175        {
 0176            query.Recursive = true;
 0177            query.Parent = parent;
 0178            query.SetUser(user);
 0179            query.IsFavorite = true;
 0180            query.IncludeItemTypes = [BaseItemKind.Series];
 181
 0182            return _libraryManager.GetItemsResult(query);
 183        }
 184
 185        private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query)
 186        {
 0187            query.Recursive = true;
 0188            query.Parent = parent;
 0189            query.SetUser(user);
 0190            query.IsFavorite = true;
 0191            query.IncludeItemTypes = [BaseItemKind.Episode];
 192
 0193            return _libraryManager.GetItemsResult(query);
 194        }
 195
 196        private QueryResult<BaseItem> GetBooks(Folder parent, User user, InternalItemsQuery query)
 197        {
 0198            query.Recursive = true;
 0199            query.Parent = parent;
 0200            query.SetUser(user);
 201
 0202            query.IncludeItemTypes = new[] { BaseItemKind.Book, BaseItemKind.AudioBook };
 203
 0204            return _libraryManager.GetItemsResult(query);
 205        }
 206
 207        private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
 208        {
 0209            query.Recursive = true;
 0210            query.Parent = parent;
 0211            query.SetUser(user);
 212
 0213            query.IncludeItemTypes = [BaseItemKind.Movie];
 214
 0215            return _libraryManager.GetItemsResult(query);
 216        }
 217
 218        private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
 219        {
 0220            query.Parent = null;
 0221            query.IncludeItemTypes = [BaseItemKind.BoxSet];
 0222            query.SetUser(user);
 0223            query.Recursive = true;
 224
 0225            return _libraryManager.GetItemsResult(query);
 226        }
 227
 228        private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
 229        {
 0230            query.OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)
 0231            query.Recursive = true;
 0232            query.Parent = parent;
 0233            query.SetUser(user);
 0234            query.Limit = GetSpecialItemsLimit();
 0235            query.IncludeItemTypes = [BaseItemKind.Movie];
 236
 0237            return ConvertToResult(_libraryManager.GetItemList(query));
 238        }
 239
 240        private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
 241        {
 0242            query.OrderBy = [(ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)]
 0243            query.IsResumable = true;
 0244            query.Recursive = true;
 0245            query.Parent = parent;
 0246            query.SetUser(user);
 0247            query.Limit = GetSpecialItemsLimit();
 0248            query.IncludeItemTypes = [BaseItemKind.Movie];
 249
 0250            return ConvertToResult(_libraryManager.GetItemList(query));
 251        }
 252
 253        private QueryResult<BaseItem> ConvertToResult(IReadOnlyList<BaseItem> items)
 254        {
 0255            return new QueryResult<BaseItem>(items);
 256        }
 257
 258        private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
 259        {
 0260            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0261            {
 0262                IncludeItemTypes = [BaseItemKind.Movie],
 0263                Recursive = true,
 0264                EnableTotalRecordCount = false
 0265            }).Items
 0266                .SelectMany(i => i.Genres)
 0267                .DistinctNames()
 0268                .Select(i =>
 0269                {
 0270                    try
 0271                    {
 0272                        return _libraryManager.GetGenre(i);
 0273                    }
 0274                    catch (Exception ex)
 0275                    {
 0276                        _logger.LogError(ex, "Error getting genre");
 0277                        return null;
 0278                    }
 0279                })
 0280                .Where(i => i is not null)
 0281                .Select(i => GetUserViewWithName(CollectionType.moviegenre, i.SortName, parent));
 282
 0283            return GetResult(genres, query);
 284        }
 285
 286        private QueryResult<BaseItem> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalIt
 287        {
 0288            query.Recursive = true;
 0289            query.Parent = queryParent;
 0290            query.GenreIds = [displayParent.Id];
 0291            query.SetUser(user);
 292
 0293            query.IncludeItemTypes = [BaseItemKind.Movie];
 294
 0295            return _libraryManager.GetItemsResult(query);
 296        }
 297
 298        private QueryResult<BaseItem> GetTvView(Folder parent, User user, InternalItemsQuery query)
 299        {
 0300            if (query.Recursive)
 301            {
 0302                query.Recursive = true;
 0303                query.SetUser(user);
 304
 0305                if (query.IncludeItemTypes.Length == 0)
 306                {
 0307                    query.IncludeItemTypes =
 0308                    [
 0309                        BaseItemKind.Series,
 0310                        BaseItemKind.Season,
 0311                        BaseItemKind.Episode
 0312                    ];
 313                }
 314
 0315                return parent.QueryRecursive(query);
 316            }
 317
 0318            var list = new List<BaseItem>
 0319            {
 0320                GetUserView(CollectionType.tvresume, "HeaderContinueWatching", "0", parent),
 0321                GetUserView(CollectionType.tvnextup, "HeaderNextUp", "1", parent),
 0322                GetUserView(CollectionType.tvlatest, "Latest", "2", parent),
 0323                GetUserView(CollectionType.tvshowseries, "Shows", "3", parent),
 0324                GetUserView(CollectionType.tvfavoriteseries, "HeaderFavoriteShows", "4", parent),
 0325                GetUserView(CollectionType.tvfavoriteepisodes, "HeaderFavoriteEpisodes", "5", parent),
 0326                GetUserView(CollectionType.tvgenres, "Genres", "6", parent)
 0327            };
 328
 0329            return GetResult(list, query);
 330        }
 331
 332        private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
 333        {
 0334            query.OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)
 0335            query.Recursive = true;
 0336            query.Parent = parent;
 0337            query.SetUser(user);
 0338            query.Limit = GetSpecialItemsLimit();
 0339            query.IncludeItemTypes = [BaseItemKind.Episode];
 0340            query.IsVirtualItem = false;
 341
 0342            return ConvertToResult(_libraryManager.GetItemList(query));
 343        }
 344
 345        private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query)
 346        {
 0347            var parentFolders = GetMediaFolders(parent, query.User, [CollectionType.tvshows]);
 348
 0349            var result = _tvSeriesManager.GetNextUp(
 0350                new NextUpQuery
 0351                {
 0352                    Limit = query.Limit,
 0353                    StartIndex = query.StartIndex,
 0354                    User = query.User
 0355                },
 0356                parentFolders,
 0357                query.DtoOptions);
 358
 0359            return result;
 360        }
 361
 362        private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
 363        {
 0364            query.OrderBy = [(ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)]
 0365            query.IsResumable = true;
 0366            query.Recursive = true;
 0367            query.Parent = parent;
 0368            query.SetUser(user);
 0369            query.Limit = GetSpecialItemsLimit();
 0370            query.IncludeItemTypes = [BaseItemKind.Episode];
 371
 0372            return ConvertToResult(_libraryManager.GetItemList(query));
 373        }
 374
 375        private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query)
 376        {
 0377            query.Recursive = true;
 0378            query.Parent = parent;
 0379            query.SetUser(user);
 380
 0381            query.IncludeItemTypes = [BaseItemKind.Series];
 382
 0383            return _libraryManager.GetItemsResult(query);
 384        }
 385
 386        private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, InternalItemsQuery query)
 387        {
 0388            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0389            {
 0390                IncludeItemTypes = [BaseItemKind.Series],
 0391                Recursive = true,
 0392                EnableTotalRecordCount = false
 0393            }).Items
 0394                .SelectMany(i => i.Genres)
 0395                .DistinctNames()
 0396                .Select(i =>
 0397                {
 0398                    try
 0399                    {
 0400                        return _libraryManager.GetGenre(i);
 0401                    }
 0402                    catch (Exception ex)
 0403                    {
 0404                        _logger.LogError(ex, "Error getting genre");
 0405                        return null;
 0406                    }
 0407                })
 0408                .Where(i => i is not null)
 0409                .Select(i => GetUserViewWithName(CollectionType.tvgenre, i.SortName, parent));
 410
 0411            return GetResult(genres, query);
 412        }
 413
 414        private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItems
 415        {
 0416            query.Recursive = true;
 0417            query.Parent = queryParent;
 0418            query.GenreIds = [displayParent.Id];
 0419            query.SetUser(user);
 420
 0421            query.IncludeItemTypes = [BaseItemKind.Series];
 422
 0423            return _libraryManager.GetItemsResult(query);
 424        }
 425
 426        private QueryResult<BaseItem> GetResult<T>(
 427            IEnumerable<T> items,
 428            InternalItemsQuery query)
 429            where T : BaseItem
 430        {
 0431            var filtered = Filter(items, query.User, query, _userDataManager, _libraryManager);
 432
 0433            return SortAndPage(filtered, null, query, _libraryManager);
 434        }
 435
 436        /// <summary>
 437        /// Batch-aware filter that applies per-item checks.
 438        /// </summary>
 439        /// <param name="items">The items to filter.</param>
 440        /// <param name="user">The user for filtering context.</param>
 441        /// <param name="query">The query parameters.</param>
 442        /// <param name="userDataManager">The user data manager.</param>
 443        /// <param name="libraryManager">The library manager.</param>
 444        /// <returns>The filtered items.</returns>
 445        public static IEnumerable<BaseItem> Filter(
 446            IEnumerable<BaseItem> items,
 447            User user,
 448            InternalItemsQuery query,
 449            IUserDataManager userDataManager,
 450            ILibraryManager libraryManager)
 451        {
 10452            var filtered = items.Where(i => Filter(i, user, query, userDataManager, libraryManager));
 453
 10454            if (query.IsPlayed.HasValue && user is not null)
 455            {
 0456                var itemList = filtered.ToList();
 0457                var folderIds = itemList.OfType<Folder>().Select(f => f.Id).ToList();
 458
 0459                if (folderIds.Count > 0)
 460                {
 0461                    var counts = libraryManager.GetPlayedAndTotalCountBatch(folderIds, user);
 0462                    var isPlayedValue = query.IsPlayed.Value;
 463
 0464                    return itemList.Where(i =>
 0465                    {
 0466                        if (i.IsFolder && counts.TryGetValue(i.Id, out var c))
 0467                        {
 0468                            return (c.Total > 0 && c.Played == c.Total) == isPlayedValue;
 0469                        }
 0470
 0471                        return true;
 0472                    });
 473                }
 474
 0475                return itemList;
 476            }
 477
 10478            return filtered;
 479        }
 480
 481        public static QueryResult<BaseItem> SortAndPage(
 482            IEnumerable<BaseItem> items,
 483            int? totalRecordLimit,
 484            InternalItemsQuery query,
 485            ILibraryManager libraryManager)
 486        {
 0487            if (query.OrderBy.Count > 0)
 488            {
 0489                items = libraryManager.Sort(items, query.User, query.OrderBy);
 490            }
 491
 0492            var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
 0493            var totalCount = itemsArray.Length;
 494
 0495            if (query.Limit.HasValue && query.Limit.Value > 0)
 496            {
 0497                itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
 498            }
 0499            else if (query.StartIndex.HasValue)
 500            {
 0501                itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
 502            }
 503
 0504            return new QueryResult<BaseItem>(
 0505                query.StartIndex,
 0506                totalCount,
 0507                itemsArray);
 508        }
 509
 510        private static bool Filter(
 511            BaseItem item,
 512            User user,
 513            InternalItemsQuery query,
 514            IUserDataManager userDataManager,
 515            ILibraryManager libraryManager)
 516        {
 10517            if (!string.IsNullOrEmpty(query.NameStartsWith) && !item.SortName.StartsWith(query.NameStartsWith, StringCom
 518            {
 0519                return false;
 520            }
 521
 522#pragma warning disable CA1309 // Use ordinal string comparison
 10523            if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater) && string.Compare(query.NameStartsWithOrGreater, it
 524            {
 0525                return false;
 526            }
 527
 10528            if (!string.IsNullOrEmpty(query.NameLessThan) && string.Compare(query.NameLessThan, item.SortName, StringCom
 529#pragma warning restore CA1309 // Use ordinal string comparison
 530            {
 0531                return false;
 532            }
 533
 10534            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 535            {
 0536                return false;
 537            }
 538
 10539            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 540            {
 0541                return false;
 542            }
 543
 10544            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 545            {
 0546                return false;
 547            }
 548
 10549            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 550            {
 0551                return false;
 552            }
 553
 10554            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 555            {
 0556                return false;
 557            }
 558
 10559            UserItemData userData = null;
 560
 10561            if (query.IsLiked.HasValue)
 562            {
 0563                userData = userDataManager.GetUserData(user, item);
 0564                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 565                {
 0566                    return false;
 567                }
 568            }
 569
 10570            if (query.IsFavoriteOrLiked.HasValue)
 571            {
 0572                userData ??= userDataManager.GetUserData(user, item);
 0573                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 574
 0575                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 576                {
 0577                    return false;
 578                }
 579            }
 580
 10581            if (query.IsFavorite.HasValue)
 582            {
 0583                userData ??= userDataManager.GetUserData(user, item);
 0584                if (userData.IsFavorite != query.IsFavorite.Value)
 585                {
 0586                    return false;
 587                }
 588            }
 589
 10590            if (query.IsResumable.HasValue)
 591            {
 0592                userData ??= userDataManager.GetUserData(user, item);
 0593                var isResumable = userData.PlaybackPositionTicks > 0;
 594
 0595                if (isResumable != query.IsResumable.Value)
 596                {
 0597                    return false;
 598                }
 599            }
 600
 10601            if (query.IsPlayed.HasValue)
 602            {
 603                // Folder.IsPlayed() hits the DB per-item (N+1 queries).
 604                // Folders are batch-filtered by the collection Filter() overload.
 0605                if (!item.IsFolder)
 606                {
 0607                    userData ??= userDataManager.GetUserData(user, item);
 0608                    if (item.IsPlayed(user, userData) != query.IsPlayed.Value)
 609                    {
 0610                        return false;
 611                    }
 612                }
 613            }
 614
 10615            if (query.IsLocked.HasValue)
 616            {
 0617                var val = query.IsLocked.Value;
 0618                if (item.IsLocked != val)
 619                {
 0620                    return false;
 621                }
 622            }
 623
 10624            if (query.HasOverview.HasValue)
 625            {
 0626                var filterValue = query.HasOverview.Value;
 627
 0628                var hasValue = !string.IsNullOrEmpty(item.Overview);
 629
 0630                if (hasValue != filterValue)
 631                {
 0632                    return false;
 633                }
 634            }
 635
 10636            if (query.HasImdbId.HasValue)
 637            {
 0638                var filterValue = query.HasImdbId.Value;
 639
 0640                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 641
 0642                if (hasValue != filterValue)
 643                {
 0644                    return false;
 645                }
 646            }
 647
 10648            if (query.HasTmdbId.HasValue)
 649            {
 0650                var filterValue = query.HasTmdbId.Value;
 651
 0652                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 653
 0654                if (hasValue != filterValue)
 655                {
 0656                    return false;
 657                }
 658            }
 659
 10660            if (query.HasTvdbId.HasValue)
 661            {
 0662                var filterValue = query.HasTvdbId.Value;
 663
 0664                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 665
 0666                if (hasValue != filterValue)
 667                {
 0668                    return false;
 669                }
 670            }
 671
 10672            if (query.HasParentalRating.HasValue)
 673            {
 0674                var val = query.HasParentalRating.Value;
 675
 0676                var rating = item.CustomRating;
 677
 0678                if (string.IsNullOrEmpty(rating))
 679                {
 0680                    rating = item.OfficialRating;
 681                }
 682
 0683                if (val)
 684                {
 0685                    if (string.IsNullOrEmpty(rating))
 686                    {
 0687                        return false;
 688                    }
 689                }
 690                else
 691                {
 0692                    if (!string.IsNullOrEmpty(rating))
 693                    {
 0694                        return false;
 695                    }
 696                }
 697            }
 698
 699            // Apply genre filter
 10700            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 701            {
 0702                return false;
 703            }
 704
 10705            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 706            {
 0707                return false;
 708            }
 709
 710            // Apply studio filter
 10711            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 10712            {
 10713                var studioItem = libraryManager.GetItemById(id);
 10714                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 10715            }))
 716            {
 0717                return false;
 718            }
 719
 720            // Apply genre filter
 10721            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 10722            {
 10723                var genreItem = libraryManager.GetItemById(id);
 10724                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 10725            }))
 726            {
 0727                return false;
 728            }
 729
 730            // Apply year filter
 10731            if (query.Years.Length > 0)
 732            {
 0733                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 734                {
 0735                    return false;
 736                }
 737            }
 738
 739            // Apply official rating filter
 10740            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 741            {
 0742                return false;
 743            }
 744
 10745            if (query.ItemIds.Length > 0)
 746            {
 0747                if (!query.ItemIds.Contains(item.Id))
 748                {
 0749                    return false;
 750                }
 751            }
 752
 753            // Apply tag filter
 10754            var tags = query.Tags;
 10755            if (tags.Length > 0)
 756            {
 0757                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 758                {
 0759                    return false;
 760                }
 761            }
 762
 10763            if (query.MinCommunityRating.HasValue)
 764            {
 0765                var val = query.MinCommunityRating.Value;
 766
 0767                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 768                {
 0769                    return false;
 770                }
 771            }
 772
 10773            if (query.MinCriticRating.HasValue)
 774            {
 0775                var val = query.MinCriticRating.Value;
 776
 0777                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 778                {
 0779                    return false;
 780                }
 781            }
 782
 10783            if (query.MinIndexNumber.HasValue)
 784            {
 0785                var val = query.MinIndexNumber.Value;
 786
 0787                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 788                {
 0789                    return false;
 790                }
 791            }
 792
 10793            if (query.MinPremiereDate.HasValue)
 794            {
 0795                var val = query.MinPremiereDate.Value;
 796
 0797                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 798                {
 0799                    return false;
 800                }
 801            }
 802
 10803            if (query.MaxPremiereDate.HasValue)
 804            {
 0805                var val = query.MaxPremiereDate.Value;
 806
 0807                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 808                {
 0809                    return false;
 810                }
 811            }
 812
 10813            if (query.ParentIndexNumber.HasValue)
 814            {
 0815                var filterValue = query.ParentIndexNumber.Value;
 816
 0817                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 818                {
 0819                    return false;
 820                }
 821            }
 822
 10823            if (query.ExcludeItemIds.Contains(item.Id))
 824            {
 0825                return false;
 826            }
 827
 10828            return true;
 829        }
 830
 831        private IEnumerable<BaseItem> GetMediaFolders(User user)
 832        {
 0833            if (user is null)
 834            {
 0835                return _libraryManager.RootFolder
 0836                    .Children
 0837                    .OfType<Folder>()
 0838                    .Where(UserView.IsEligibleForGrouping);
 839            }
 840
 0841            return _libraryManager.GetUserRootFolder()
 0842                .GetChildren(user, true)
 0843                .OfType<Folder>()
 0844                .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
 845        }
 846
 847        private BaseItem[] GetMediaFolders(User user, IEnumerable<CollectionType> viewTypes)
 848        {
 0849            if (user is null)
 850            {
 0851                return GetMediaFolders(null)
 0852                    .Where(i =>
 0853                    {
 0854                        var folder = i as ICollectionFolder;
 0855
 0856                        return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0857                    }).ToArray();
 858            }
 859
 0860            return GetMediaFolders(user)
 0861                .Where(i =>
 0862                {
 0863                    var folder = i as ICollectionFolder;
 0864
 0865                    return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0866                }).ToArray();
 867        }
 868
 869        private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable<CollectionType> viewTypes)
 870        {
 0871            if (parent is null || parent is UserView)
 872            {
 0873                return GetMediaFolders(user, viewTypes);
 874            }
 875
 0876            return [parent];
 877        }
 878
 879        private UserView GetUserViewWithName(CollectionType? type, string sortName, BaseItem parent)
 880        {
 0881            return _userViewManager.GetUserSubView(parent.Id, type, parent.Id.ToString("N", CultureInfo.InvariantCulture
 882        }
 883
 884        private UserView GetUserView(CollectionType? type, string localizationKey, string sortName, BaseItem parent)
 885        {
 0886            return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
 887        }
 888
 889        public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
 890        {
 0891            var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
 892
 0893            var index = list.IndexOf(adjacentToItem);
 894
 0895            var previousId = Guid.Empty;
 0896            var nextId = Guid.Empty;
 897
 0898            if (index > 0)
 899            {
 0900                previousId = list[index - 1].Id;
 901            }
 902
 0903            if (index < list.Count - 1)
 904            {
 0905                nextId = list[index + 1].Id;
 906            }
 907
 0908            return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
 909        }
 910    }
 911}

Methods/Properties

.ctor(MediaBrowser.Controller.Library.IUserViewManager,MediaBrowser.Controller.Library.ILibraryManager,Microsoft.Extensions.Logging.ILogger`1<MediaBrowser.Controller.Entities.BaseItem>,MediaBrowser.Controller.Library.IUserDataManager,MediaBrowser.Controller.TV.ITVSeriesManager)
GetUserItems(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.Folder,System.Nullable`1<Jellyfin.Data.Enums.CollectionType>,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetSpecialItemsLimit()
GetMovieFolders(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteMovies(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteSeries(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteEpisodes(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetBooks(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieMovies(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieCollections(Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieLatest(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieResume(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
ConvertToResult(System.Collections.Generic.IReadOnlyList`1<MediaBrowser.Controller.Entities.BaseItem>)
GetMovieGenres(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieGenreItems(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvView(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvLatest(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvNextUp(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvResume(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvSeries(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvGenres(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvGenreItems(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetResult(System.Collections.Generic.IEnumerable`1<T>,MediaBrowser.Controller.Entities.InternalItemsQuery)
Filter(System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery,MediaBrowser.Controller.Library.IUserDataManager,MediaBrowser.Controller.Library.ILibraryManager)
SortAndPage(System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.Nullable`1<System.Int32>,MediaBrowser.Controller.Entities.InternalItemsQuery,MediaBrowser.Controller.Library.ILibraryManager)
Filter(MediaBrowser.Controller.Entities.BaseItem,Jellyfin.Database.Implementations.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery,MediaBrowser.Controller.Library.IUserDataManager,MediaBrowser.Controller.Library.ILibraryManager)
GetMediaFolders(Jellyfin.Database.Implementations.Entities.User)
GetMediaFolders(Jellyfin.Database.Implementations.Entities.User,System.Collections.Generic.IEnumerable`1<Jellyfin.Data.Enums.CollectionType>)
GetMediaFolders(MediaBrowser.Controller.Entities.Folder,Jellyfin.Database.Implementations.Entities.User,System.Collections.Generic.IEnumerable`1<Jellyfin.Data.Enums.CollectionType>)
GetUserViewWithName(System.Nullable`1<Jellyfin.Data.Enums.CollectionType>,System.String,MediaBrowser.Controller.Entities.BaseItem)
GetUserView(System.Nullable`1<Jellyfin.Data.Enums.CollectionType>,System.String,System.String,MediaBrowser.Controller.Entities.BaseItem)
FilterForAdjacency(System.Collections.Generic.List`1<MediaBrowser.Controller.Entities.BaseItem>,System.Guid)