< 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: 54
Uncovered lines: 390
Coverable lines: 444
Total lines: 1010
Line coverage: 12.1%
Branch coverage
29%
Covered branches: 85
Total branches: 284
Branch coverage: 29.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

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 Episode = MediaBrowser.Controller.Entities.TV.Episode;
 20using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
 21using Series = MediaBrowser.Controller.Entities.TV.Series;
 22
 23namespace MediaBrowser.Controller.Entities
 24{
 25    public class UserViewBuilder
 26    {
 27        private readonly IUserViewManager _userViewManager;
 28        private readonly ILibraryManager _libraryManager;
 29        private readonly ILogger<BaseItem> _logger;
 30        private readonly IUserDataManager _userDataManager;
 31        private readonly ITVSeriesManager _tvSeriesManager;
 32
 33        public UserViewBuilder(
 34            IUserViewManager userViewManager,
 35            ILibraryManager libraryManager,
 36            ILogger<BaseItem> logger,
 37            IUserDataManager userDataManager,
 38            ITVSeriesManager tvSeriesManager)
 39        {
 040            _userViewManager = userViewManager;
 041            _libraryManager = libraryManager;
 042            _logger = logger;
 043            _userDataManager = userDataManager;
 044            _tvSeriesManager = tvSeriesManager;
 045        }
 46
 47        public QueryResult<BaseItem> GetUserItems(Folder queryParent, Folder displayParent, CollectionType? viewType, In
 48        {
 049            var user = query.User;
 50
 51            // if (query.IncludeItemTypes is not null &&
 52            //    query.IncludeItemTypes.Length == 1 &&
 53            //    string.Equals(query.IncludeItemTypes[0], "Playlist", StringComparison.OrdinalIgnoreCase))
 54            // {
 55            //    if (!string.Equals(viewType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
 56            //    {
 57            //        return await FindPlaylists(queryParent, user, query).ConfigureAwait(false);
 58            //    }
 59            // }
 60
 61            switch (viewType)
 62            {
 63                case CollectionType.folders:
 064                    return GetResult(_libraryManager.GetUserRootFolder().GetChildren(user, true), query);
 65
 66                case CollectionType.tvshows:
 067                    return GetTvView(queryParent, user, query);
 68
 69                case CollectionType.movies:
 070                    return GetMovieFolders(queryParent, user, query);
 71
 72                case CollectionType.tvshowseries:
 073                    return GetTvSeries(queryParent, user, query);
 74
 75                case CollectionType.tvgenres:
 076                    return GetTvGenres(queryParent, user, query);
 77
 78                case CollectionType.tvgenre:
 079                    return GetTvGenreItems(queryParent, displayParent, user, query);
 80
 81                case CollectionType.tvresume:
 082                    return GetTvResume(queryParent, user, query);
 83
 84                case CollectionType.tvnextup:
 085                    return GetTvNextUp(queryParent, query);
 86
 87                case CollectionType.tvlatest:
 088                    return GetTvLatest(queryParent, user, query);
 89
 90                case CollectionType.moviefavorites:
 091                    return GetFavoriteMovies(queryParent, user, query);
 92
 93                case CollectionType.movielatest:
 094                    return GetMovieLatest(queryParent, user, query);
 95
 96                case CollectionType.moviegenres:
 097                    return GetMovieGenres(queryParent, user, query);
 98
 99                case CollectionType.moviegenre:
 0100                    return GetMovieGenreItems(queryParent, displayParent, user, query);
 101
 102                case CollectionType.movieresume:
 0103                    return GetMovieResume(queryParent, user, query);
 104
 105                case CollectionType.moviemovies:
 0106                    return GetMovieMovies(queryParent, user, query);
 107
 108                case CollectionType.moviecollection:
 0109                    return GetMovieCollections(user, query);
 110
 111                case CollectionType.tvfavoriteepisodes:
 0112                    return GetFavoriteEpisodes(queryParent, user, query);
 113
 114                case CollectionType.tvfavoriteseries:
 0115                    return GetFavoriteSeries(queryParent, user, query);
 116
 117                default:
 118                    {
 0119                        if (queryParent is UserView)
 120                        {
 0121                            return GetResult(GetMediaFolders(user).OfType<Folder>().SelectMany(i => i.GetChildren(user, 
 122                        }
 123
 0124                        return queryParent.GetItems(query);
 125                    }
 126            }
 127        }
 128
 129        private int GetSpecialItemsLimit()
 130        {
 0131            return 50;
 132        }
 133
 134        private QueryResult<BaseItem> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
 135        {
 0136            if (query.Recursive)
 137            {
 0138                query.Recursive = true;
 0139                query.SetUser(user);
 140
 0141                if (query.IncludeItemTypes.Length == 0)
 142                {
 0143                    query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 144                }
 145
 0146                return parent.QueryRecursive(query);
 147            }
 148
 0149            var list = new List<BaseItem>
 0150            {
 0151                GetUserView(CollectionType.movieresume, "HeaderContinueWatching", "0", parent),
 0152                GetUserView(CollectionType.movielatest, "Latest", "1", parent),
 0153                GetUserView(CollectionType.moviemovies, "Movies", "2", parent),
 0154                GetUserView(CollectionType.moviecollection, "Collections", "3", parent),
 0155                GetUserView(CollectionType.moviefavorites, "Favorites", "4", parent),
 0156                GetUserView(CollectionType.moviegenres, "Genres", "5", parent)
 0157            };
 158
 0159            return GetResult(list, query);
 160        }
 161
 162        private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
 163        {
 0164            query.Recursive = true;
 0165            query.Parent = parent;
 0166            query.SetUser(user);
 0167            query.IsFavorite = true;
 0168            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 169
 0170            return _libraryManager.GetItemsResult(query);
 171        }
 172
 173        private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query)
 174        {
 0175            query.Recursive = true;
 0176            query.Parent = parent;
 0177            query.SetUser(user);
 0178            query.IsFavorite = true;
 0179            query.IncludeItemTypes = new[] { BaseItemKind.Series };
 180
 0181            return _libraryManager.GetItemsResult(query);
 182        }
 183
 184        private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query)
 185        {
 0186            query.Recursive = true;
 0187            query.Parent = parent;
 0188            query.SetUser(user);
 0189            query.IsFavorite = true;
 0190            query.IncludeItemTypes = new[] { BaseItemKind.Episode };
 191
 0192            return _libraryManager.GetItemsResult(query);
 193        }
 194
 195        private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
 196        {
 0197            query.Recursive = true;
 0198            query.Parent = parent;
 0199            query.SetUser(user);
 200
 0201            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 202
 0203            return _libraryManager.GetItemsResult(query);
 204        }
 205
 206        private QueryResult<BaseItem> GetMovieCollections(User user, InternalItemsQuery query)
 207        {
 0208            query.Parent = null;
 0209            query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
 0210            query.SetUser(user);
 0211            query.Recursive = true;
 212
 0213            return _libraryManager.GetItemsResult(query);
 214        }
 215
 216        private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
 217        {
 0218            query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desc
 0219            query.Recursive = true;
 0220            query.Parent = parent;
 0221            query.SetUser(user);
 0222            query.Limit = GetSpecialItemsLimit();
 0223            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 224
 0225            return ConvertToResult(_libraryManager.GetItemList(query));
 226        }
 227
 228        private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
 229        {
 0230            query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desce
 0231            query.IsResumable = true;
 0232            query.Recursive = true;
 0233            query.Parent = parent;
 0234            query.SetUser(user);
 0235            query.Limit = GetSpecialItemsLimit();
 0236            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 237
 0238            return ConvertToResult(_libraryManager.GetItemList(query));
 239        }
 240
 241        private QueryResult<BaseItem> ConvertToResult(IReadOnlyList<BaseItem> items)
 242        {
 0243            return new QueryResult<BaseItem>(items);
 244        }
 245
 246        private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
 247        {
 0248            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0249            {
 0250                IncludeItemTypes = new[] { BaseItemKind.Movie },
 0251                Recursive = true,
 0252                EnableTotalRecordCount = false
 0253            }).Items
 0254                .SelectMany(i => i.Genres)
 0255                .DistinctNames()
 0256                .Select(i =>
 0257                {
 0258                    try
 0259                    {
 0260                        return _libraryManager.GetGenre(i);
 0261                    }
 0262                    catch (Exception ex)
 0263                    {
 0264                        _logger.LogError(ex, "Error getting genre");
 0265                        return null;
 0266                    }
 0267                })
 0268                .Where(i => i is not null)
 0269                .Select(i => GetUserViewWithName(CollectionType.moviegenre, i.SortName, parent));
 270
 0271            return GetResult(genres, query);
 272        }
 273
 274        private QueryResult<BaseItem> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalIt
 275        {
 0276            query.Recursive = true;
 0277            query.Parent = queryParent;
 0278            query.GenreIds = new[] { displayParent.Id };
 0279            query.SetUser(user);
 280
 0281            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 282
 0283            return _libraryManager.GetItemsResult(query);
 284        }
 285
 286        private QueryResult<BaseItem> GetTvView(Folder parent, User user, InternalItemsQuery query)
 287        {
 0288            if (query.Recursive)
 289            {
 0290                query.Recursive = true;
 0291                query.SetUser(user);
 292
 0293                if (query.IncludeItemTypes.Length == 0)
 294                {
 0295                    query.IncludeItemTypes = new[]
 0296                    {
 0297                        BaseItemKind.Series,
 0298                        BaseItemKind.Season,
 0299                        BaseItemKind.Episode
 0300                    };
 301                }
 302
 0303                return parent.QueryRecursive(query);
 304            }
 305
 0306            var list = new List<BaseItem>
 0307            {
 0308                GetUserView(CollectionType.tvresume, "HeaderContinueWatching", "0", parent),
 0309                GetUserView(CollectionType.tvnextup, "HeaderNextUp", "1", parent),
 0310                GetUserView(CollectionType.tvlatest, "Latest", "2", parent),
 0311                GetUserView(CollectionType.tvshowseries, "Shows", "3", parent),
 0312                GetUserView(CollectionType.tvfavoriteseries, "HeaderFavoriteShows", "4", parent),
 0313                GetUserView(CollectionType.tvfavoriteepisodes, "HeaderFavoriteEpisodes", "5", parent),
 0314                GetUserView(CollectionType.tvgenres, "Genres", "6", parent)
 0315            };
 316
 0317            return GetResult(list, query);
 318        }
 319
 320        private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
 321        {
 0322            query.OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desc
 0323            query.Recursive = true;
 0324            query.Parent = parent;
 0325            query.SetUser(user);
 0326            query.Limit = GetSpecialItemsLimit();
 0327            query.IncludeItemTypes = new[] { BaseItemKind.Episode };
 0328            query.IsVirtualItem = false;
 329
 0330            return ConvertToResult(_libraryManager.GetItemList(query));
 331        }
 332
 333        private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query)
 334        {
 0335            var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.tvshows });
 336
 0337            var result = _tvSeriesManager.GetNextUp(
 0338                new NextUpQuery
 0339                {
 0340                    Limit = query.Limit,
 0341                    StartIndex = query.StartIndex,
 0342                    User = query.User
 0343                },
 0344                parentFolders,
 0345                query.DtoOptions);
 346
 0347            return result;
 348        }
 349
 350        private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
 351        {
 0352            query.OrderBy = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desce
 0353            query.IsResumable = true;
 0354            query.Recursive = true;
 0355            query.Parent = parent;
 0356            query.SetUser(user);
 0357            query.Limit = GetSpecialItemsLimit();
 0358            query.IncludeItemTypes = new[] { BaseItemKind.Episode };
 359
 0360            return ConvertToResult(_libraryManager.GetItemList(query));
 361        }
 362
 363        private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query)
 364        {
 0365            query.Recursive = true;
 0366            query.Parent = parent;
 0367            query.SetUser(user);
 368
 0369            query.IncludeItemTypes = new[] { BaseItemKind.Series };
 370
 0371            return _libraryManager.GetItemsResult(query);
 372        }
 373
 374        private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, InternalItemsQuery query)
 375        {
 0376            var genres = parent.QueryRecursive(new InternalItemsQuery(user)
 0377            {
 0378                IncludeItemTypes = new[] { BaseItemKind.Series },
 0379                Recursive = true,
 0380                EnableTotalRecordCount = false
 0381            }).Items
 0382                .SelectMany(i => i.Genres)
 0383                .DistinctNames()
 0384                .Select(i =>
 0385                {
 0386                    try
 0387                    {
 0388                        return _libraryManager.GetGenre(i);
 0389                    }
 0390                    catch (Exception ex)
 0391                    {
 0392                        _logger.LogError(ex, "Error getting genre");
 0393                        return null;
 0394                    }
 0395                })
 0396                .Where(i => i is not null)
 0397                .Select(i => GetUserViewWithName(CollectionType.tvgenre, i.SortName, parent));
 398
 0399            return GetResult(genres, query);
 400        }
 401
 402        private QueryResult<BaseItem> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItems
 403        {
 0404            query.Recursive = true;
 0405            query.Parent = queryParent;
 0406            query.GenreIds = new[] { displayParent.Id };
 0407            query.SetUser(user);
 408
 0409            query.IncludeItemTypes = new[] { BaseItemKind.Series };
 410
 0411            return _libraryManager.GetItemsResult(query);
 412        }
 413
 414        private QueryResult<BaseItem> GetResult<T>(
 415            IEnumerable<T> items,
 416            InternalItemsQuery query)
 417            where T : BaseItem
 418        {
 0419            items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
 420
 0421            return PostFilterAndSort(items, null, query, _libraryManager);
 422        }
 423
 424        public static bool FilterItem(BaseItem item, InternalItemsQuery query)
 425        {
 10426            return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager);
 427        }
 428
 429        public static QueryResult<BaseItem> PostFilterAndSort(
 430            IEnumerable<BaseItem> items,
 431            int? totalRecordLimit,
 432            InternalItemsQuery query,
 433            ILibraryManager libraryManager)
 434        {
 435            // This must be the last filter
 0436            if (!query.AdjacentTo.IsNullOrEmpty())
 437            {
 0438                items = FilterForAdjacency(items.ToList(), query.AdjacentTo.Value);
 439            }
 440
 0441            return SortAndPage(items, totalRecordLimit, query, libraryManager);
 442        }
 443
 444        public static QueryResult<BaseItem> SortAndPage(
 445            IEnumerable<BaseItem> items,
 446            int? totalRecordLimit,
 447            InternalItemsQuery query,
 448            ILibraryManager libraryManager)
 449        {
 0450            if (query.OrderBy.Count > 0)
 451            {
 0452                items = libraryManager.Sort(items, query.User, query.OrderBy);
 453            }
 454
 0455            var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
 0456            var totalCount = itemsArray.Length;
 457
 0458            if (query.Limit.HasValue)
 459            {
 0460                itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
 461            }
 0462            else if (query.StartIndex.HasValue)
 463            {
 0464                itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
 465            }
 466
 0467            return new QueryResult<BaseItem>(
 0468                query.StartIndex,
 0469                totalCount,
 0470                itemsArray);
 471        }
 472
 473        public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, 
 474        {
 10475            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 476            {
 0477                return false;
 478            }
 479
 10480            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 481            {
 0482                return false;
 483            }
 484
 10485            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 486            {
 0487                return false;
 488            }
 489
 10490            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 491            {
 0492                return false;
 493            }
 494
 10495            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 496            {
 0497                return false;
 498            }
 499
 10500            UserItemData userData = null;
 501
 10502            if (query.IsLiked.HasValue)
 503            {
 0504                userData = userDataManager.GetUserData(user, item);
 0505                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 506                {
 0507                    return false;
 508                }
 509            }
 510
 10511            if (query.IsFavoriteOrLiked.HasValue)
 512            {
 0513                userData ??= userDataManager.GetUserData(user, item);
 0514                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 515
 0516                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 517                {
 0518                    return false;
 519                }
 520            }
 521
 10522            if (query.IsFavorite.HasValue)
 523            {
 0524                userData ??= userDataManager.GetUserData(user, item);
 0525                if (userData.IsFavorite != query.IsFavorite.Value)
 526                {
 0527                    return false;
 528                }
 529            }
 530
 10531            if (query.IsResumable.HasValue)
 532            {
 0533                userData ??= userDataManager.GetUserData(user, item);
 0534                var isResumable = userData.PlaybackPositionTicks > 0;
 535
 0536                if (isResumable != query.IsResumable.Value)
 537                {
 0538                    return false;
 539                }
 540            }
 541
 10542            if (query.IsPlayed.HasValue)
 543            {
 0544                userData ??= userDataManager.GetUserData(user, item);
 0545                if (item.IsPlayed(user, userData) != query.IsPlayed.Value)
 546                {
 0547                    return false;
 548                }
 549            }
 550
 551            // Filter by Video3DFormat
 10552            if (query.Is3D.HasValue)
 553            {
 0554                var val = query.Is3D.Value;
 0555                var video = item as Video;
 556
 0557                if (video is null || val != video.Video3DFormat.HasValue)
 558                {
 0559                    return false;
 560                }
 561            }
 562
 563            /*
 564             * fuck - fix this
 565            if (query.IsHD.HasValue)
 566            {
 567                if (item.IsHD != query.IsHD.Value)
 568                {
 569                    return false;
 570                }
 571            }
 572            */
 573
 10574            if (query.IsLocked.HasValue)
 575            {
 0576                var val = query.IsLocked.Value;
 0577                if (item.IsLocked != val)
 578                {
 0579                    return false;
 580                }
 581            }
 582
 10583            if (query.HasOverview.HasValue)
 584            {
 0585                var filterValue = query.HasOverview.Value;
 586
 0587                var hasValue = !string.IsNullOrEmpty(item.Overview);
 588
 0589                if (hasValue != filterValue)
 590                {
 0591                    return false;
 592                }
 593            }
 594
 10595            if (query.HasImdbId.HasValue)
 596            {
 0597                var filterValue = query.HasImdbId.Value;
 598
 0599                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 600
 0601                if (hasValue != filterValue)
 602                {
 0603                    return false;
 604                }
 605            }
 606
 10607            if (query.HasTmdbId.HasValue)
 608            {
 0609                var filterValue = query.HasTmdbId.Value;
 610
 0611                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 612
 0613                if (hasValue != filterValue)
 614                {
 0615                    return false;
 616                }
 617            }
 618
 10619            if (query.HasTvdbId.HasValue)
 620            {
 0621                var filterValue = query.HasTvdbId.Value;
 622
 0623                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 624
 0625                if (hasValue != filterValue)
 626                {
 0627                    return false;
 628                }
 629            }
 630
 10631            if (query.HasOfficialRating.HasValue)
 632            {
 0633                var filterValue = query.HasOfficialRating.Value;
 634
 0635                var hasValue = !string.IsNullOrEmpty(item.OfficialRating);
 636
 0637                if (hasValue != filterValue)
 638                {
 0639                    return false;
 640                }
 641            }
 642
 10643            if (query.IsPlaceHolder.HasValue)
 644            {
 0645                var filterValue = query.IsPlaceHolder.Value;
 646
 0647                var isPlaceHolder = false;
 648
 0649                if (item is ISupportsPlaceHolders hasPlaceHolder)
 650                {
 0651                    isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
 652                }
 653
 0654                if (isPlaceHolder != filterValue)
 655                {
 0656                    return false;
 657                }
 658            }
 659
 10660            if (query.HasSpecialFeature.HasValue)
 661            {
 0662                var filterValue = query.HasSpecialFeature.Value;
 663
 0664                if (item is IHasSpecialFeatures movie)
 665                {
 0666                    var ok = filterValue
 0667                        ? movie.SpecialFeatureIds.Count > 0
 0668                        : movie.SpecialFeatureIds.Count == 0;
 669
 0670                    if (!ok)
 671                    {
 0672                        return false;
 673                    }
 674                }
 675                else
 676                {
 0677                    return false;
 678                }
 679            }
 680
 10681            if (query.HasSubtitles.HasValue)
 682            {
 0683                var val = query.HasSubtitles.Value;
 684
 0685                var video = item as Video;
 686
 0687                if (video is null || val != video.HasSubtitles)
 688                {
 0689                    return false;
 690                }
 691            }
 692
 10693            if (query.HasParentalRating.HasValue)
 694            {
 0695                var val = query.HasParentalRating.Value;
 696
 0697                var rating = item.CustomRating;
 698
 0699                if (string.IsNullOrEmpty(rating))
 700                {
 0701                    rating = item.OfficialRating;
 702                }
 703
 0704                if (val)
 705                {
 0706                    if (string.IsNullOrEmpty(rating))
 707                    {
 0708                        return false;
 709                    }
 710                }
 711                else
 712                {
 0713                    if (!string.IsNullOrEmpty(rating))
 714                    {
 0715                        return false;
 716                    }
 717                }
 718            }
 719
 10720            if (query.HasTrailer.HasValue)
 721            {
 0722                var val = query.HasTrailer.Value;
 0723                var trailerCount = 0;
 724
 0725                if (item is IHasTrailers hasTrailers)
 726                {
 0727                    trailerCount = hasTrailers.GetTrailerCount();
 728                }
 729
 0730                var ok = val ? trailerCount > 0 : trailerCount == 0;
 731
 0732                if (!ok)
 733                {
 0734                    return false;
 735                }
 736            }
 737
 10738            if (query.HasThemeSong.HasValue)
 739            {
 0740                var filterValue = query.HasThemeSong.Value;
 741
 0742                var themeCount = item.GetThemeSongs(user).Count;
 0743                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 744
 0745                if (!ok)
 746                {
 0747                    return false;
 748                }
 749            }
 750
 10751            if (query.HasThemeVideo.HasValue)
 752            {
 0753                var filterValue = query.HasThemeVideo.Value;
 754
 0755                var themeCount = item.GetThemeVideos(user).Count;
 0756                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 757
 0758                if (!ok)
 759                {
 0760                    return false;
 761                }
 762            }
 763
 764            // Apply genre filter
 10765            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 766            {
 0767                return false;
 768            }
 769
 770            // Filter by VideoType
 10771            if (query.VideoTypes.Length > 0)
 772            {
 0773                var video = item as Video;
 0774                if (video is null || !query.VideoTypes.Contains(video.VideoType))
 775                {
 0776                    return false;
 777                }
 778            }
 779
 10780            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 781            {
 0782                return false;
 783            }
 784
 785            // Apply studio filter
 10786            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 10787            {
 10788                var studioItem = libraryManager.GetItemById(id);
 10789                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 10790            }))
 791            {
 0792                return false;
 793            }
 794
 795            // Apply genre filter
 10796            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 10797            {
 10798                var genreItem = libraryManager.GetItemById(id);
 10799                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 10800            }))
 801            {
 0802                return false;
 803            }
 804
 805            // Apply year filter
 10806            if (query.Years.Length > 0)
 807            {
 0808                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 809                {
 0810                    return false;
 811                }
 812            }
 813
 814            // Apply official rating filter
 10815            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 816            {
 0817                return false;
 818            }
 819
 10820            if (query.ItemIds.Length > 0)
 821            {
 0822                if (!query.ItemIds.Contains(item.Id))
 823                {
 0824                    return false;
 825                }
 826            }
 827
 828            // Apply tag filter
 10829            var tags = query.Tags;
 10830            if (tags.Length > 0)
 831            {
 0832                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 833                {
 0834                    return false;
 835                }
 836            }
 837
 10838            if (query.MinCommunityRating.HasValue)
 839            {
 0840                var val = query.MinCommunityRating.Value;
 841
 0842                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 843                {
 0844                    return false;
 845                }
 846            }
 847
 10848            if (query.MinCriticRating.HasValue)
 849            {
 0850                var val = query.MinCriticRating.Value;
 851
 0852                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 853                {
 0854                    return false;
 855                }
 856            }
 857
 10858            if (query.MinIndexNumber.HasValue)
 859            {
 0860                var val = query.MinIndexNumber.Value;
 861
 0862                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 863                {
 0864                    return false;
 865                }
 866            }
 867
 10868            if (query.MinPremiereDate.HasValue)
 869            {
 0870                var val = query.MinPremiereDate.Value;
 871
 0872                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 873                {
 0874                    return false;
 875                }
 876            }
 877
 10878            if (query.MaxPremiereDate.HasValue)
 879            {
 0880                var val = query.MaxPremiereDate.Value;
 881
 0882                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 883                {
 0884                    return false;
 885                }
 886            }
 887
 10888            if (query.ParentIndexNumber.HasValue)
 889            {
 0890                var filterValue = query.ParentIndexNumber.Value;
 891
 0892                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 893                {
 0894                    return false;
 895                }
 896            }
 897
 10898            if (query.SeriesStatuses.Length > 0)
 899            {
 0900                var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.S
 0901                if (!ok)
 902                {
 0903                    return false;
 904                }
 905            }
 906
 10907            if (query.AiredDuringSeason.HasValue)
 908            {
 0909                var episode = item as Episode;
 910
 0911                if (episode is null)
 912                {
 0913                    return false;
 914                }
 915
 0916                if (!Series.FilterEpisodesBySeason(new[] { episode }, query.AiredDuringSeason.Value, true).Any())
 917                {
 0918                    return false;
 919                }
 920            }
 921
 10922            if (query.ExcludeItemIds.Contains(item.Id))
 923            {
 0924                return false;
 925            }
 926
 10927            return true;
 928        }
 929
 930        private IEnumerable<BaseItem> GetMediaFolders(User user)
 931        {
 0932            if (user is null)
 933            {
 0934                return _libraryManager.RootFolder
 0935                    .Children
 0936                    .OfType<Folder>()
 0937                    .Where(UserView.IsEligibleForGrouping);
 938            }
 939
 0940            return _libraryManager.GetUserRootFolder()
 0941                .GetChildren(user, true)
 0942                .OfType<Folder>()
 0943                .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
 944        }
 945
 946        private BaseItem[] GetMediaFolders(User user, IEnumerable<CollectionType> viewTypes)
 947        {
 0948            if (user is null)
 949            {
 0950                return GetMediaFolders(null)
 0951                    .Where(i =>
 0952                    {
 0953                        var folder = i as ICollectionFolder;
 0954
 0955                        return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0956                    }).ToArray();
 957            }
 958
 0959            return GetMediaFolders(user)
 0960                .Where(i =>
 0961                {
 0962                    var folder = i as ICollectionFolder;
 0963
 0964                    return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0965                }).ToArray();
 966        }
 967
 968        private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable<CollectionType> viewTypes)
 969        {
 0970            if (parent is null || parent is UserView)
 971            {
 0972                return GetMediaFolders(user, viewTypes);
 973            }
 974
 0975            return new BaseItem[] { parent };
 976        }
 977
 978        private UserView GetUserViewWithName(CollectionType? type, string sortName, BaseItem parent)
 979        {
 0980            return _userViewManager.GetUserSubView(parent.Id, type, parent.Id.ToString("N", CultureInfo.InvariantCulture
 981        }
 982
 983        private UserView GetUserView(CollectionType? type, string localizationKey, string sortName, BaseItem parent)
 984        {
 0985            return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
 986        }
 987
 988        public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
 989        {
 0990            var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
 991
 0992            var index = list.IndexOf(adjacentToItem);
 993
 0994            var previousId = Guid.Empty;
 0995            var nextId = Guid.Empty;
 996
 0997            if (index > 0)
 998            {
 0999                previousId = list[index - 1].Id;
 1000            }
 1001
 01002            if (index < list.Count - 1)
 1003            {
 01004                nextId = list[index + 1].Id;
 1005            }
 1006
 01007            return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
 1008        }
 1009    }
 1010}

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)
FilterItem(MediaBrowser.Controller.Entities.BaseItem,MediaBrowser.Controller.Entities.InternalItemsQuery)
PostFilterAndSort(System.Collections.Generic.IEnumerable`1<MediaBrowser.Controller.Entities.BaseItem>,System.Nullable`1<System.Int32>,MediaBrowser.Controller.Entities.InternalItemsQuery,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)