< Summary - Jellyfin

Information
Class: MediaBrowser.Controller.Entities.UserViewBuilder
Assembly: MediaBrowser.Controller
File(s): /srv/git/jellyfin/MediaBrowser.Controller/Entities/UserViewBuilder.cs
Line coverage
12%
Covered lines: 48
Uncovered lines: 352
Coverable lines: 400
Total lines: 897
Line coverage: 12%
Branch coverage
30%
Covered branches: 72
Total branches: 238
Branch coverage: 30.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 1/23/2026 - 12:11:06 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: 897 1/23/2026 - 12:11:06 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: 897

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.tvshows:
 065                    return GetTvView(queryParent, user, query);
 66
 67                case CollectionType.movies:
 068                    return GetMovieFolders(queryParent, user, query);
 69
 70                case CollectionType.tvshowseries:
 071                    return GetTvSeries(queryParent, user, query);
 72
 73                case CollectionType.tvgenres:
 074                    return GetTvGenres(queryParent, user, query);
 75
 76                case CollectionType.tvgenre:
 077                    return GetTvGenreItems(queryParent, displayParent, user, query);
 78
 79                case CollectionType.tvresume:
 080                    return GetTvResume(queryParent, user, query);
 81
 82                case CollectionType.tvnextup:
 083                    return GetTvNextUp(queryParent, query);
 84
 85                case CollectionType.tvlatest:
 086                    return GetTvLatest(queryParent, user, query);
 87
 88                case CollectionType.moviefavorites:
 089                    return GetFavoriteMovies(queryParent, user, query);
 90
 91                case CollectionType.movielatest:
 092                    return GetMovieLatest(queryParent, user, query);
 93
 94                case CollectionType.moviegenres:
 095                    return GetMovieGenres(queryParent, user, query);
 96
 97                case CollectionType.moviegenre:
 098                    return GetMovieGenreItems(queryParent, displayParent, user, query);
 99
 100                case CollectionType.movieresume:
 0101                    return GetMovieResume(queryParent, user, query);
 102
 103                case CollectionType.moviemovies:
 0104                    return GetMovieMovies(queryParent, user, query);
 105
 106                case CollectionType.moviecollection:
 0107                    return GetMovieCollections(user, query);
 108
 109                case CollectionType.tvfavoriteepisodes:
 0110                    return GetFavoriteEpisodes(queryParent, user, query);
 111
 112                case CollectionType.tvfavoriteseries:
 0113                    return GetFavoriteSeries(queryParent, user, query);
 114
 115                default:
 116                    {
 0117                        if (queryParent is UserView)
 118                        {
 0119                            return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, 
 120                        }
 121
 0122                        return queryParent.GetItems(query);
 123                    }
 124            }
 125        }
 126
 127        private int GetSpecialItemsLimit()
 128        {
 0129            return 50;
 130        }
 131
 132        private QueryResult<BaseItem> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
 133        {
 0134            if (query.Recursive)
 135            {
 0136                query.Recursive = true;
 0137                query.SetUser(user);
 138
 0139                if (query.IncludeItemTypes.Length == 0)
 140                {
 0141                    query.IncludeItemTypes = [BaseItemKind.Movie];
 142                }
 143
 0144                return parent.QueryRecursive(query);
 145            }
 146
 0147            var list = new List<BaseItem>
 0148            {
 0149                GetUserView(CollectionType.movieresume, "HeaderContinueWatching", "0", parent),
 0150                GetUserView(CollectionType.movielatest, "Latest", "1", parent),
 0151                GetUserView(CollectionType.moviemovies, "Movies", "2", parent),
 0152                GetUserView(CollectionType.moviecollection, "Collections", "3", parent),
 0153                GetUserView(CollectionType.moviefavorites, "Favorites", "4", parent),
 0154                GetUserView(CollectionType.moviegenres, "Genres", "5", parent)
 0155            };
 156
 0157            return GetResult(list, query);
 158        }
 159
 160        private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
 161        {
 0162            query.Recursive = true;
 0163            query.Parent = parent;
 0164            query.SetUser(user);
 0165            query.IsFavorite = true;
 0166            query.IncludeItemTypes = [BaseItemKind.Movie];
 167
 0168            return _libraryManager.GetItemsResult(query);
 169        }
 170
 171        private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query)
 172        {
 0173            query.Recursive = true;
 0174            query.Parent = parent;
 0175            query.SetUser(user);
 0176            query.IsFavorite = true;
 0177            query.IncludeItemTypes = [BaseItemKind.Series];
 178
 0179            return _libraryManager.GetItemsResult(query);
 180        }
 181
 182        private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query)
 183        {
 0184            query.Recursive = true;
 0185            query.Parent = parent;
 0186            query.SetUser(user);
 0187            query.IsFavorite = true;
 0188            query.IncludeItemTypes = [BaseItemKind.Episode];
 189
 0190            return _libraryManager.GetItemsResult(query);
 191        }
 192
 193        private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
 194        {
 0195            query.Recursive = true;
 0196            query.Parent = parent;
 0197            query.SetUser(user);
 198
 0199            query.IncludeItemTypes = [BaseItemKind.Movie];
 200
 0201            return _libraryManager.GetItemsResult(query);
 202        }
 203
 204        private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
 205        {
 0206            query.Parent = null;
 0207            query.IncludeItemTypes = [BaseItemKind.BoxSet];
 0208            query.SetUser(user);
 0209            query.Recursive = true;
 210
 0211            return _libraryManager.GetItemsResult(query);
 212        }
 213
 214        private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
 215        {
 0216            query.OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)
 0217            query.Recursive = true;
 0218            query.Parent = parent;
 0219            query.SetUser(user);
 0220            query.Limit = GetSpecialItemsLimit();
 0221            query.IncludeItemTypes = [BaseItemKind.Movie];
 222
 0223            return ConvertToResult(_libraryManager.GetItemList(query));
 224        }
 225
 226        private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
 227        {
 0228            query.OrderBy = [(ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)]
 0229            query.IsResumable = true;
 0230            query.Recursive = true;
 0231            query.Parent = parent;
 0232            query.SetUser(user);
 0233            query.Limit = GetSpecialItemsLimit();
 0234            query.IncludeItemTypes = [BaseItemKind.Movie];
 235
 0236            return ConvertToResult(_libraryManager.GetItemList(query));
 237        }
 238
 239        private QueryResult<BaseItem> ConvertToResult(IReadOnlyList<BaseItem> items)
 240        {
 0241            return new QueryResult<BaseItem>(items);
 242        }
 243
 244        private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
 245        {
 0246            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0247            {
 0248                IncludeItemTypes = [BaseItemKind.Movie],
 0249                Recursive = true,
 0250                EnableTotalRecordCount = false
 0251            }).Items
 0252                .SelectMany(i => i.Genres)
 0253                .DistinctNames()
 0254                .Select(i =>
 0255                {
 0256                    try
 0257                    {
 0258                        return _libraryManager.GetGenre(i);
 0259                    }
 0260                    catch (Exception ex)
 0261                    {
 0262                        _logger.LogError(ex, "Error getting genre");
 0263                        return null;
 0264                    }
 0265                })
 0266                .Where(i => i is not null)
 0267                .Select(i => GetUserViewWithName(CollectionType.moviegenre, i.SortName, parent));
 268
 0269            return GetResult(genres, query);
 270        }
 271
 272        private QueryResult<BaseItem> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalIt
 273        {
 0274            query.Recursive = true;
 0275            query.Parent = queryParent;
 0276            query.GenreIds = [displayParent.Id];
 0277            query.SetUser(user);
 278
 0279            query.IncludeItemTypes = [BaseItemKind.Movie];
 280
 0281            return _libraryManager.GetItemsResult(query);
 282        }
 283
 284        private QueryResult<BaseItem> GetTvView(Folder parent, User user, InternalItemsQuery query)
 285        {
 0286            if (query.Recursive)
 287            {
 0288                query.Recursive = true;
 0289                query.SetUser(user);
 290
 0291                if (query.IncludeItemTypes.Length == 0)
 292                {
 0293                    query.IncludeItemTypes =
 0294                    [
 0295                        BaseItemKind.Series,
 0296                        BaseItemKind.Season,
 0297                        BaseItemKind.Episode
 0298                    ];
 299                }
 300
 0301                return parent.QueryRecursive(query);
 302            }
 303
 0304            var list = new List<BaseItem>
 0305            {
 0306                GetUserView(CollectionType.tvresume, "HeaderContinueWatching", "0", parent),
 0307                GetUserView(CollectionType.tvnextup, "HeaderNextUp", "1", parent),
 0308                GetUserView(CollectionType.tvlatest, "Latest", "2", parent),
 0309                GetUserView(CollectionType.tvshowseries, "Shows", "3", parent),
 0310                GetUserView(CollectionType.tvfavoriteseries, "HeaderFavoriteShows", "4", parent),
 0311                GetUserView(CollectionType.tvfavoriteepisodes, "HeaderFavoriteEpisodes", "5", parent),
 0312                GetUserView(CollectionType.tvgenres, "Genres", "6", parent)
 0313            };
 314
 0315            return GetResult(list, query);
 316        }
 317
 318        private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
 319        {
 0320            query.OrderBy = [(ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)
 0321            query.Recursive = true;
 0322            query.Parent = parent;
 0323            query.SetUser(user);
 0324            query.Limit = GetSpecialItemsLimit();
 0325            query.IncludeItemTypes = [BaseItemKind.Episode];
 0326            query.IsVirtualItem = false;
 327
 0328            return ConvertToResult(_libraryManager.GetItemList(query));
 329        }
 330
 331        private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query)
 332        {
 0333            var parentFolders = GetMediaFolders(parent, query.User, [CollectionType.tvshows]);
 334
 0335            var result = _tvSeriesManager.GetNextUp(
 0336                new NextUpQuery
 0337                {
 0338                    Limit = query.Limit,
 0339                    StartIndex = query.StartIndex,
 0340                    User = query.User
 0341                },
 0342                parentFolders,
 0343                query.DtoOptions);
 344
 0345            return result;
 346        }
 347
 348        private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
 349        {
 0350            query.OrderBy = [(ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Descending)]
 0351            query.IsResumable = true;
 0352            query.Recursive = true;
 0353            query.Parent = parent;
 0354            query.SetUser(user);
 0355            query.Limit = GetSpecialItemsLimit();
 0356            query.IncludeItemTypes = [BaseItemKind.Episode];
 357
 0358            return ConvertToResult(_libraryManager.GetItemList(query));
 359        }
 360
 361        private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query)
 362        {
 0363            query.Recursive = true;
 0364            query.Parent = parent;
 0365            query.SetUser(user);
 366
 0367            query.IncludeItemTypes = [BaseItemKind.Series];
 368
 0369            return _libraryManager.GetItemsResult(query);
 370        }
 371
 372        private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, InternalItemsQuery query)
 373        {
 0374            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0375            {
 0376                IncludeItemTypes = [BaseItemKind.Series],
 0377                Recursive = true,
 0378                EnableTotalRecordCount = false
 0379            }).Items
 0380                .SelectMany(i => i.Genres)
 0381                .DistinctNames()
 0382                .Select(i =>
 0383                {
 0384                    try
 0385                    {
 0386                        return _libraryManager.GetGenre(i);
 0387                    }
 0388                    catch (Exception ex)
 0389                    {
 0390                        _logger.LogError(ex, "Error getting genre");
 0391                        return null;
 0392                    }
 0393                })
 0394                .Where(i => i is not null)
 0395                .Select(i => GetUserViewWithName(CollectionType.tvgenre, i.SortName, parent));
 396
 0397            return GetResult(genres, query);
 398        }
 399
 400        private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItems
 401        {
 0402            query.Recursive = true;
 0403            query.Parent = queryParent;
 0404            query.GenreIds = [displayParent.Id];
 0405            query.SetUser(user);
 406
 0407            query.IncludeItemTypes = [BaseItemKind.Series];
 408
 0409            return _libraryManager.GetItemsResult(query);
 410        }
 411
 412        private QueryResult<BaseItem> GetResult<T>(
 413            IEnumerable<T> items,
 414            InternalItemsQuery query)
 415            where T : BaseItem
 416        {
 0417            var filtered = Filter(items, query.User, query, _userDataManager, _libraryManager);
 418
 0419            return SortAndPage(filtered, null, query, _libraryManager);
 420        }
 421
 422        /// <summary>
 423        /// Batch-aware filter that applies per-item checks.
 424        /// </summary>
 425        /// <param name="items">The items to filter.</param>
 426        /// <param name="user">The user for filtering context.</param>
 427        /// <param name="query">The query parameters.</param>
 428        /// <param name="userDataManager">The user data manager.</param>
 429        /// <param name="libraryManager">The library manager.</param>
 430        /// <returns>The filtered items.</returns>
 431        public static IEnumerable<BaseItem> Filter(
 432            IEnumerable<BaseItem> items,
 433            User user,
 434            InternalItemsQuery query,
 435            IUserDataManager userDataManager,
 436            ILibraryManager libraryManager)
 437        {
 10438            var filtered = items.Where(i => Filter(i, user, query, userDataManager, libraryManager));
 439
 10440            if (query.IsPlayed.HasValue && user is not null)
 441            {
 0442                var itemList = filtered.ToList();
 0443                var folderIds = itemList.OfType<Folder>().Select(f => f.Id).ToList();
 444
 0445                if (folderIds.Count > 0)
 446                {
 0447                    var counts = libraryManager.GetPlayedAndTotalCountBatch(folderIds, user);
 0448                    var isPlayedValue = query.IsPlayed.Value;
 449
 0450                    return itemList.Where(i =>
 0451                    {
 0452                        if (i.IsFolder && counts.TryGetValue(i.Id, out var c))
 0453                        {
 0454                            return (c.Total > 0 && c.Played == c.Total) == isPlayedValue;
 0455                        }
 0456
 0457                        return true;
 0458                    });
 459                }
 460
 0461                return itemList;
 462            }
 463
 10464            return filtered;
 465        }
 466
 467        public static QueryResult<BaseItem> SortAndPage(
 468            IEnumerable<BaseItem> items,
 469            int? totalRecordLimit,
 470            InternalItemsQuery query,
 471            ILibraryManager libraryManager)
 472        {
 0473            if (query.OrderBy.Count > 0)
 474            {
 0475                items = libraryManager.Sort(items, query.User, query.OrderBy);
 476            }
 477
 0478            var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
 0479            var totalCount = itemsArray.Length;
 480
 0481            if (query.Limit.HasValue && query.Limit.Value > 0)
 482            {
 0483                itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
 484            }
 0485            else if (query.StartIndex.HasValue)
 486            {
 0487                itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
 488            }
 489
 0490            return new QueryResult<BaseItem>(
 0491                query.StartIndex,
 0492                totalCount,
 0493                itemsArray);
 494        }
 495
 496        private static bool Filter(
 497            BaseItem item,
 498            User user,
 499            InternalItemsQuery query,
 500            IUserDataManager userDataManager,
 501            ILibraryManager libraryManager)
 502        {
 10503            if (!string.IsNullOrEmpty(query.NameStartsWith) && !item.SortName.StartsWith(query.NameStartsWith, StringCom
 504            {
 0505                return false;
 506            }
 507
 508#pragma warning disable CA1309 // Use ordinal string comparison
 10509            if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater) && string.Compare(query.NameStartsWithOrGreater, it
 510            {
 0511                return false;
 512            }
 513
 10514            if (!string.IsNullOrEmpty(query.NameLessThan) && string.Compare(query.NameLessThan, item.SortName, StringCom
 515#pragma warning restore CA1309 // Use ordinal string comparison
 516            {
 0517                return false;
 518            }
 519
 10520            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 521            {
 0522                return false;
 523            }
 524
 10525            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 526            {
 0527                return false;
 528            }
 529
 10530            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 531            {
 0532                return false;
 533            }
 534
 10535            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 536            {
 0537                return false;
 538            }
 539
 10540            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 541            {
 0542                return false;
 543            }
 544
 10545            UserItemData userData = null;
 546
 10547            if (query.IsLiked.HasValue)
 548            {
 0549                userData = userDataManager.GetUserData(user, item);
 0550                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 551                {
 0552                    return false;
 553                }
 554            }
 555
 10556            if (query.IsFavoriteOrLiked.HasValue)
 557            {
 0558                userData ??= userDataManager.GetUserData(user, item);
 0559                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 560
 0561                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 562                {
 0563                    return false;
 564                }
 565            }
 566
 10567            if (query.IsFavorite.HasValue)
 568            {
 0569                userData ??= userDataManager.GetUserData(user, item);
 0570                if (userData.IsFavorite != query.IsFavorite.Value)
 571                {
 0572                    return false;
 573                }
 574            }
 575
 10576            if (query.IsResumable.HasValue)
 577            {
 0578                userData ??= userDataManager.GetUserData(user, item);
 0579                var isResumable = userData.PlaybackPositionTicks > 0;
 580
 0581                if (isResumable != query.IsResumable.Value)
 582                {
 0583                    return false;
 584                }
 585            }
 586
 10587            if (query.IsPlayed.HasValue)
 588            {
 589                // Folder.IsPlayed() hits the DB per-item (N+1 queries).
 590                // Folders are batch-filtered by the collection Filter() overload.
 0591                if (!item.IsFolder)
 592                {
 0593                    userData ??= userDataManager.GetUserData(user, item);
 0594                    if (item.IsPlayed(user, userData) != query.IsPlayed.Value)
 595                    {
 0596                        return false;
 597                    }
 598                }
 599            }
 600
 10601            if (query.IsLocked.HasValue)
 602            {
 0603                var val = query.IsLocked.Value;
 0604                if (item.IsLocked != val)
 605                {
 0606                    return false;
 607                }
 608            }
 609
 10610            if (query.HasOverview.HasValue)
 611            {
 0612                var filterValue = query.HasOverview.Value;
 613
 0614                var hasValue = !string.IsNullOrEmpty(item.Overview);
 615
 0616                if (hasValue != filterValue)
 617                {
 0618                    return false;
 619                }
 620            }
 621
 10622            if (query.HasImdbId.HasValue)
 623            {
 0624                var filterValue = query.HasImdbId.Value;
 625
 0626                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 627
 0628                if (hasValue != filterValue)
 629                {
 0630                    return false;
 631                }
 632            }
 633
 10634            if (query.HasTmdbId.HasValue)
 635            {
 0636                var filterValue = query.HasTmdbId.Value;
 637
 0638                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 639
 0640                if (hasValue != filterValue)
 641                {
 0642                    return false;
 643                }
 644            }
 645
 10646            if (query.HasTvdbId.HasValue)
 647            {
 0648                var filterValue = query.HasTvdbId.Value;
 649
 0650                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 651
 0652                if (hasValue != filterValue)
 653                {
 0654                    return false;
 655                }
 656            }
 657
 10658            if (query.HasParentalRating.HasValue)
 659            {
 0660                var val = query.HasParentalRating.Value;
 661
 0662                var rating = item.CustomRating;
 663
 0664                if (string.IsNullOrEmpty(rating))
 665                {
 0666                    rating = item.OfficialRating;
 667                }
 668
 0669                if (val)
 670                {
 0671                    if (string.IsNullOrEmpty(rating))
 672                    {
 0673                        return false;
 674                    }
 675                }
 676                else
 677                {
 0678                    if (!string.IsNullOrEmpty(rating))
 679                    {
 0680                        return false;
 681                    }
 682                }
 683            }
 684
 685            // Apply genre filter
 10686            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 687            {
 0688                return false;
 689            }
 690
 10691            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 692            {
 0693                return false;
 694            }
 695
 696            // Apply studio filter
 10697            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 10698            {
 10699                var studioItem = libraryManager.GetItemById(id);
 10700                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 10701            }))
 702            {
 0703                return false;
 704            }
 705
 706            // Apply genre filter
 10707            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 10708            {
 10709                var genreItem = libraryManager.GetItemById(id);
 10710                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 10711            }))
 712            {
 0713                return false;
 714            }
 715
 716            // Apply year filter
 10717            if (query.Years.Length > 0)
 718            {
 0719                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 720                {
 0721                    return false;
 722                }
 723            }
 724
 725            // Apply official rating filter
 10726            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 727            {
 0728                return false;
 729            }
 730
 10731            if (query.ItemIds.Length > 0)
 732            {
 0733                if (!query.ItemIds.Contains(item.Id))
 734                {
 0735                    return false;
 736                }
 737            }
 738
 739            // Apply tag filter
 10740            var tags = query.Tags;
 10741            if (tags.Length > 0)
 742            {
 0743                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 744                {
 0745                    return false;
 746                }
 747            }
 748
 10749            if (query.MinCommunityRating.HasValue)
 750            {
 0751                var val = query.MinCommunityRating.Value;
 752
 0753                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 754                {
 0755                    return false;
 756                }
 757            }
 758
 10759            if (query.MinCriticRating.HasValue)
 760            {
 0761                var val = query.MinCriticRating.Value;
 762
 0763                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 764                {
 0765                    return false;
 766                }
 767            }
 768
 10769            if (query.MinIndexNumber.HasValue)
 770            {
 0771                var val = query.MinIndexNumber.Value;
 772
 0773                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 774                {
 0775                    return false;
 776                }
 777            }
 778
 10779            if (query.MinPremiereDate.HasValue)
 780            {
 0781                var val = query.MinPremiereDate.Value;
 782
 0783                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 784                {
 0785                    return false;
 786                }
 787            }
 788
 10789            if (query.MaxPremiereDate.HasValue)
 790            {
 0791                var val = query.MaxPremiereDate.Value;
 792
 0793                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 794                {
 0795                    return false;
 796                }
 797            }
 798
 10799            if (query.ParentIndexNumber.HasValue)
 800            {
 0801                var filterValue = query.ParentIndexNumber.Value;
 802
 0803                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 804                {
 0805                    return false;
 806                }
 807            }
 808
 10809            if (query.ExcludeItemIds.Contains(item.Id))
 810            {
 0811                return false;
 812            }
 813
 10814            return true;
 815        }
 816
 817        private IEnumerable<BaseItem> GetMediaFolders(User user)
 818        {
 0819            if (user is null)
 820            {
 0821                return _libraryManager.RootFolder
 0822                    .Children
 0823                    .OfType<Folder>()
 0824                    .Where(UserView.IsEligibleForGrouping);
 825            }
 826
 0827            return _libraryManager.GetUserRootFolder()
 0828                .GetChildren(user, true)
 0829                .OfType<Folder>()
 0830                .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
 831        }
 832
 833        private BaseItem[] GetMediaFolders(User user, IEnumerable<CollectionType> viewTypes)
 834        {
 0835            if (user is null)
 836            {
 0837                return GetMediaFolders(null)
 0838                    .Where(i =>
 0839                    {
 0840                        var folder = i as ICollectionFolder;
 0841
 0842                        return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0843                    }).ToArray();
 844            }
 845
 0846            return GetMediaFolders(user)
 0847                .Where(i =>
 0848                {
 0849                    var folder = i as ICollectionFolder;
 0850
 0851                    return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0852                }).ToArray();
 853        }
 854
 855        private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable<CollectionType> viewTypes)
 856        {
 0857            if (parent is null || parent is UserView)
 858            {
 0859                return GetMediaFolders(user, viewTypes);
 860            }
 861
 0862            return [parent];
 863        }
 864
 865        private UserView GetUserViewWithName(CollectionType? type, string sortName, BaseItem parent)
 866        {
 0867            return _userViewManager.GetUserSubView(parent.Id, type, parent.Id.ToString("N", CultureInfo.InvariantCulture
 868        }
 869
 870        private UserView GetUserView(CollectionType? type, string localizationKey, string sortName, BaseItem parent)
 871        {
 0872            return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
 873        }
 874
 875        public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
 876        {
 0877            var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
 878
 0879            var index = list.IndexOf(adjacentToItem);
 880
 0881            var previousId = Guid.Empty;
 0882            var nextId = Guid.Empty;
 883
 0884            if (index > 0)
 885            {
 0886                previousId = list[index - 1].Id;
 887            }
 888
 0889            if (index < list.Count - 1)
 890            {
 0891                nextId = list[index + 1].Id;
 892            }
 893
 0894            return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
 895        }
 896    }
 897}

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)
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)