< 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: 53
Uncovered lines: 389
Coverable lines: 442
Total lines: 1008
Line coverage: 11.9%
Branch coverage
29%
Covered branches: 84
Total branches: 282
Branch coverage: 29.7%
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.Entities;
 10using Jellyfin.Data.Enums;
 11using Jellyfin.Extensions;
 12using MediaBrowser.Controller.Library;
 13using MediaBrowser.Controller.TV;
 14using MediaBrowser.Model.Entities;
 15using MediaBrowser.Model.Querying;
 16using Microsoft.Extensions.Logging;
 17using Episode = MediaBrowser.Controller.Entities.TV.Episode;
 18using MetadataProvider = MediaBrowser.Model.Entities.MetadataProvider;
 19using Series = MediaBrowser.Controller.Entities.TV.Series;
 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 = new[] { 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 = new[] { 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 = new[] { 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 = new[] { 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 = new[] { 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 = new[] { 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 = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desc
 0217            query.Recursive = true;
 0218            query.Parent = parent;
 0219            query.SetUser(user);
 0220            query.Limit = GetSpecialItemsLimit();
 0221            query.IncludeItemTypes = new[] { 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 = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desce
 0229            query.IsResumable = true;
 0230            query.Recursive = true;
 0231            query.Parent = parent;
 0232            query.SetUser(user);
 0233            query.Limit = GetSpecialItemsLimit();
 0234            query.IncludeItemTypes = new[] { BaseItemKind.Movie };
 235
 0236            return ConvertToResult(_libraryManager.GetItemList(query));
 237        }
 238
 239        private QueryResult<BaseItem> ConvertToResult(List<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 = new[] { 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 = new[] { displayParent.Id };
 0277            query.SetUser(user);
 278
 0279            query.IncludeItemTypes = new[] { 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 = new[]
 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 = new[] { (ItemSortBy.DateCreated, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desc
 0321            query.Recursive = true;
 0322            query.Parent = parent;
 0323            query.SetUser(user);
 0324            query.Limit = GetSpecialItemsLimit();
 0325            query.IncludeItemTypes = new[] { 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, new[] { 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 = new[] { (ItemSortBy.DatePlayed, SortOrder.Descending), (ItemSortBy.SortName, SortOrder.Desce
 0351            query.IsResumable = true;
 0352            query.Recursive = true;
 0353            query.Parent = parent;
 0354            query.SetUser(user);
 0355            query.Limit = GetSpecialItemsLimit();
 0356            query.IncludeItemTypes = new[] { 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 = new[] { 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 = new[] { 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 = new[] { displayParent.Id };
 0405            query.SetUser(user);
 406
 0407            query.IncludeItemTypes = new[] { 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            items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager));
 418
 0419            return PostFilterAndSort(items, null, query, _libraryManager);
 420        }
 421
 422        public static bool FilterItem(BaseItem item, InternalItemsQuery query)
 423        {
 15424            return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager);
 425        }
 426
 427        public static QueryResult<BaseItem> PostFilterAndSort(
 428            IEnumerable<BaseItem> items,
 429            int? totalRecordLimit,
 430            InternalItemsQuery query,
 431            ILibraryManager libraryManager)
 432        {
 433            // This must be the last filter
 0434            if (!query.AdjacentTo.IsNullOrEmpty())
 435            {
 0436                items = FilterForAdjacency(items.ToList(), query.AdjacentTo.Value);
 437            }
 438
 0439            return SortAndPage(items, totalRecordLimit, query, libraryManager, true);
 440        }
 441
 442        public static QueryResult<BaseItem> SortAndPage(
 443            IEnumerable<BaseItem> items,
 444            int? totalRecordLimit,
 445            InternalItemsQuery query,
 446            ILibraryManager libraryManager,
 447            bool enableSorting)
 448        {
 0449            if (enableSorting)
 450            {
 0451                if (query.OrderBy.Count > 0)
 452                {
 0453                    items = libraryManager.Sort(items, query.User, query.OrderBy);
 454                }
 455            }
 456
 0457            var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
 0458            var totalCount = itemsArray.Length;
 459
 0460            if (query.Limit.HasValue)
 461            {
 0462                itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
 463            }
 0464            else if (query.StartIndex.HasValue)
 465            {
 0466                itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
 467            }
 468
 0469            return new QueryResult<BaseItem>(
 0470                query.StartIndex,
 0471                totalCount,
 0472                itemsArray);
 473        }
 474
 475        public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, 
 476        {
 15477            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 478            {
 0479                return false;
 480            }
 481
 15482            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 483            {
 0484                return false;
 485            }
 486
 15487            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 488            {
 0489                return false;
 490            }
 491
 15492            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 493            {
 0494                return false;
 495            }
 496
 15497            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 498            {
 0499                return false;
 500            }
 501
 15502            UserItemData userData = null;
 503
 15504            if (query.IsLiked.HasValue)
 505            {
 0506                userData = userDataManager.GetUserData(user, item);
 507
 0508                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 509                {
 0510                    return false;
 511                }
 512            }
 513
 15514            if (query.IsFavoriteOrLiked.HasValue)
 515            {
 0516                userData = userData ?? userDataManager.GetUserData(user, item);
 0517                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 518
 0519                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 520                {
 0521                    return false;
 522                }
 523            }
 524
 15525            if (query.IsFavorite.HasValue)
 526            {
 0527                userData = userData ?? userDataManager.GetUserData(user, item);
 528
 0529                if (userData.IsFavorite != query.IsFavorite.Value)
 530                {
 0531                    return false;
 532                }
 533            }
 534
 15535            if (query.IsResumable.HasValue)
 536            {
 0537                userData = userData ?? userDataManager.GetUserData(user, item);
 0538                var isResumable = userData.PlaybackPositionTicks > 0;
 539
 0540                if (isResumable != query.IsResumable.Value)
 541                {
 0542                    return false;
 543                }
 544            }
 545
 15546            if (query.IsPlayed.HasValue)
 547            {
 0548                if (item.IsPlayed(user) != query.IsPlayed.Value)
 549                {
 0550                    return false;
 551                }
 552            }
 553
 554            // Filter by Video3DFormat
 15555            if (query.Is3D.HasValue)
 556            {
 0557                var val = query.Is3D.Value;
 0558                var video = item as Video;
 559
 0560                if (video is null || val != video.Video3DFormat.HasValue)
 561                {
 0562                    return false;
 563                }
 564            }
 565
 566            /*
 567             * fuck - fix this
 568            if (query.IsHD.HasValue)
 569            {
 570                if (item.IsHD != query.IsHD.Value)
 571                {
 572                    return false;
 573                }
 574            }
 575            */
 576
 15577            if (query.IsLocked.HasValue)
 578            {
 0579                var val = query.IsLocked.Value;
 0580                if (item.IsLocked != val)
 581                {
 0582                    return false;
 583                }
 584            }
 585
 15586            if (query.HasOverview.HasValue)
 587            {
 0588                var filterValue = query.HasOverview.Value;
 589
 0590                var hasValue = !string.IsNullOrEmpty(item.Overview);
 591
 0592                if (hasValue != filterValue)
 593                {
 0594                    return false;
 595                }
 596            }
 597
 15598            if (query.HasImdbId.HasValue)
 599            {
 0600                var filterValue = query.HasImdbId.Value;
 601
 0602                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 603
 0604                if (hasValue != filterValue)
 605                {
 0606                    return false;
 607                }
 608            }
 609
 15610            if (query.HasTmdbId.HasValue)
 611            {
 0612                var filterValue = query.HasTmdbId.Value;
 613
 0614                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 615
 0616                if (hasValue != filterValue)
 617                {
 0618                    return false;
 619                }
 620            }
 621
 15622            if (query.HasTvdbId.HasValue)
 623            {
 0624                var filterValue = query.HasTvdbId.Value;
 625
 0626                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 627
 0628                if (hasValue != filterValue)
 629                {
 0630                    return false;
 631                }
 632            }
 633
 15634            if (query.HasOfficialRating.HasValue)
 635            {
 0636                var filterValue = query.HasOfficialRating.Value;
 637
 0638                var hasValue = !string.IsNullOrEmpty(item.OfficialRating);
 639
 0640                if (hasValue != filterValue)
 641                {
 0642                    return false;
 643                }
 644            }
 645
 15646            if (query.IsPlaceHolder.HasValue)
 647            {
 0648                var filterValue = query.IsPlaceHolder.Value;
 649
 0650                var isPlaceHolder = false;
 651
 0652                if (item is ISupportsPlaceHolders hasPlaceHolder)
 653                {
 0654                    isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
 655                }
 656
 0657                if (isPlaceHolder != filterValue)
 658                {
 0659                    return false;
 660                }
 661            }
 662
 15663            if (query.HasSpecialFeature.HasValue)
 664            {
 0665                var filterValue = query.HasSpecialFeature.Value;
 666
 0667                if (item is IHasSpecialFeatures movie)
 668                {
 0669                    var ok = filterValue
 0670                        ? movie.SpecialFeatureIds.Count > 0
 0671                        : movie.SpecialFeatureIds.Count == 0;
 672
 0673                    if (!ok)
 674                    {
 0675                        return false;
 676                    }
 677                }
 678                else
 679                {
 0680                    return false;
 681                }
 682            }
 683
 15684            if (query.HasSubtitles.HasValue)
 685            {
 0686                var val = query.HasSubtitles.Value;
 687
 0688                var video = item as Video;
 689
 0690                if (video is null || val != video.HasSubtitles)
 691                {
 0692                    return false;
 693                }
 694            }
 695
 15696            if (query.HasParentalRating.HasValue)
 697            {
 0698                var val = query.HasParentalRating.Value;
 699
 0700                var rating = item.CustomRating;
 701
 0702                if (string.IsNullOrEmpty(rating))
 703                {
 0704                    rating = item.OfficialRating;
 705                }
 706
 0707                if (val)
 708                {
 0709                    if (string.IsNullOrEmpty(rating))
 710                    {
 0711                        return false;
 712                    }
 713                }
 714                else
 715                {
 0716                    if (!string.IsNullOrEmpty(rating))
 717                    {
 0718                        return false;
 719                    }
 720                }
 721            }
 722
 15723            if (query.HasTrailer.HasValue)
 724            {
 0725                var val = query.HasTrailer.Value;
 0726                var trailerCount = 0;
 727
 0728                if (item is IHasTrailers hasTrailers)
 729                {
 0730                    trailerCount = hasTrailers.GetTrailerCount();
 731                }
 732
 0733                var ok = val ? trailerCount > 0 : trailerCount == 0;
 734
 0735                if (!ok)
 736                {
 0737                    return false;
 738                }
 739            }
 740
 15741            if (query.HasThemeSong.HasValue)
 742            {
 0743                var filterValue = query.HasThemeSong.Value;
 744
 0745                var themeCount = item.GetThemeSongs(user).Count;
 0746                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 747
 0748                if (!ok)
 749                {
 0750                    return false;
 751                }
 752            }
 753
 15754            if (query.HasThemeVideo.HasValue)
 755            {
 0756                var filterValue = query.HasThemeVideo.Value;
 757
 0758                var themeCount = item.GetThemeVideos(user).Count;
 0759                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 760
 0761                if (!ok)
 762                {
 0763                    return false;
 764                }
 765            }
 766
 767            // Apply genre filter
 15768            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 769            {
 0770                return false;
 771            }
 772
 773            // Filter by VideoType
 15774            if (query.VideoTypes.Length > 0)
 775            {
 0776                var video = item as Video;
 0777                if (video is null || !query.VideoTypes.Contains(video.VideoType))
 778                {
 0779                    return false;
 780                }
 781            }
 782
 15783            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 784            {
 0785                return false;
 786            }
 787
 788            // Apply studio filter
 15789            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 15790            {
 15791                var studioItem = libraryManager.GetItemById(id);
 15792                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 15793            }))
 794            {
 0795                return false;
 796            }
 797
 798            // Apply genre filter
 15799            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 15800            {
 15801                var genreItem = libraryManager.GetItemById(id);
 15802                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 15803            }))
 804            {
 0805                return false;
 806            }
 807
 808            // Apply year filter
 15809            if (query.Years.Length > 0)
 810            {
 0811                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 812                {
 0813                    return false;
 814                }
 815            }
 816
 817            // Apply official rating filter
 15818            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 819            {
 0820                return false;
 821            }
 822
 15823            if (query.ItemIds.Length > 0)
 824            {
 0825                if (!query.ItemIds.Contains(item.Id))
 826                {
 0827                    return false;
 828                }
 829            }
 830
 831            // Apply tag filter
 15832            var tags = query.Tags;
 15833            if (tags.Length > 0)
 834            {
 0835                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 836                {
 0837                    return false;
 838                }
 839            }
 840
 15841            if (query.MinCommunityRating.HasValue)
 842            {
 0843                var val = query.MinCommunityRating.Value;
 844
 0845                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 846                {
 0847                    return false;
 848                }
 849            }
 850
 15851            if (query.MinCriticRating.HasValue)
 852            {
 0853                var val = query.MinCriticRating.Value;
 854
 0855                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 856                {
 0857                    return false;
 858                }
 859            }
 860
 15861            if (query.MinIndexNumber.HasValue)
 862            {
 0863                var val = query.MinIndexNumber.Value;
 864
 0865                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 866                {
 0867                    return false;
 868                }
 869            }
 870
 15871            if (query.MinPremiereDate.HasValue)
 872            {
 0873                var val = query.MinPremiereDate.Value;
 874
 0875                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 876                {
 0877                    return false;
 878                }
 879            }
 880
 15881            if (query.MaxPremiereDate.HasValue)
 882            {
 0883                var val = query.MaxPremiereDate.Value;
 884
 0885                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 886                {
 0887                    return false;
 888                }
 889            }
 890
 15891            if (query.ParentIndexNumber.HasValue)
 892            {
 0893                var filterValue = query.ParentIndexNumber.Value;
 894
 0895                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 896                {
 0897                    return false;
 898                }
 899            }
 900
 15901            if (query.SeriesStatuses.Length > 0)
 902            {
 0903                var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.S
 0904                if (!ok)
 905                {
 0906                    return false;
 907                }
 908            }
 909
 15910            if (query.AiredDuringSeason.HasValue)
 911            {
 0912                var episode = item as Episode;
 913
 0914                if (episode is null)
 915                {
 0916                    return false;
 917                }
 918
 0919                if (!Series.FilterEpisodesBySeason(new[] { episode }, query.AiredDuringSeason.Value, true).Any())
 920                {
 0921                    return false;
 922                }
 923            }
 924
 15925            return true;
 926        }
 927
 928        private IEnumerable<BaseItem> GetMediaFolders(User user)
 929        {
 0930            if (user is null)
 931            {
 0932                return _libraryManager.RootFolder
 0933                    .Children
 0934                    .OfType<Folder>()
 0935                    .Where(UserView.IsEligibleForGrouping);
 936            }
 937
 0938            return _libraryManager.GetUserRootFolder()
 0939                .GetChildren(user, true)
 0940                .OfType<Folder>()
 0941                .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
 942        }
 943
 944        private BaseItem[] GetMediaFolders(User user, IEnumerable<CollectionType> viewTypes)
 945        {
 0946            if (user is null)
 947            {
 0948                return GetMediaFolders(null)
 0949                    .Where(i =>
 0950                    {
 0951                        var folder = i as ICollectionFolder;
 0952
 0953                        return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0954                    }).ToArray();
 955            }
 956
 0957            return GetMediaFolders(user)
 0958                .Where(i =>
 0959                {
 0960                    var folder = i as ICollectionFolder;
 0961
 0962                    return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0963                }).ToArray();
 964        }
 965
 966        private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable<CollectionType> viewTypes)
 967        {
 0968            if (parent is null || parent is UserView)
 969            {
 0970                return GetMediaFolders(user, viewTypes);
 971            }
 972
 0973            return new BaseItem[] { parent };
 974        }
 975
 976        private UserView GetUserViewWithName(CollectionType? type, string sortName, BaseItem parent)
 977        {
 0978            return _userViewManager.GetUserSubView(parent.Id, type, parent.Id.ToString("N", CultureInfo.InvariantCulture
 979        }
 980
 981        private UserView GetUserView(CollectionType? type, string localizationKey, string sortName, BaseItem parent)
 982        {
 0983            return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
 984        }
 985
 986        public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
 987        {
 0988            var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
 989
 0990            var index = list.IndexOf(adjacentToItem);
 991
 0992            var previousId = Guid.Empty;
 0993            var nextId = Guid.Empty;
 994
 0995            if (index > 0)
 996            {
 0997                previousId = list[index - 1].Id;
 998            }
 999
 01000            if (index < list.Count - 1)
 1001            {
 01002                nextId = list[index + 1].Id;
 1003            }
 1004
 01005            return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
 1006        }
 1007    }
 1008}

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.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteMovies(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteSeries(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetFavoriteEpisodes(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieMovies(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieCollections(Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieLatest(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieResume(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
ConvertToResult(System.Collections.Generic.List`1<MediaBrowser.Controller.Entities.BaseItem>)
GetMovieGenres(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetMovieGenreItems(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvView(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvLatest(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvNextUp(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvResume(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvSeries(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvGenres(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery)
GetTvGenreItems(MediaBrowser.Controller.Entities.Folder,MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.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,System.Boolean)
Filter(MediaBrowser.Controller.Entities.BaseItem,Jellyfin.Data.Entities.User,MediaBrowser.Controller.Entities.InternalItemsQuery,MediaBrowser.Controller.Library.IUserDataManager,MediaBrowser.Controller.Library.ILibraryManager)
GetMediaFolders(Jellyfin.Data.Entities.User)
GetMediaFolders(Jellyfin.Data.Entities.User,System.Collections.Generic.IEnumerable`1<Jellyfin.Data.Enums.CollectionType>)
GetMediaFolders(MediaBrowser.Controller.Entities.Folder,Jellyfin.Data.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)