< 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: 1010
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;
 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, true);
 442        }
 443
 444        public static QueryResult<BaseItem> SortAndPage(
 445            IEnumerable<BaseItem> items,
 446            int? totalRecordLimit,
 447            InternalItemsQuery query,
 448            ILibraryManager libraryManager,
 449            bool enableSorting)
 450        {
 0451            if (enableSorting)
 452            {
 0453                if (query.OrderBy.Count > 0)
 454                {
 0455                    items = libraryManager.Sort(items, query.User, query.OrderBy);
 456                }
 457            }
 458
 0459            var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
 0460            var totalCount = itemsArray.Length;
 461
 0462            if (query.Limit.HasValue)
 463            {
 0464                itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
 465            }
 0466            else if (query.StartIndex.HasValue)
 467            {
 0468                itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
 469            }
 470
 0471            return new QueryResult<BaseItem>(
 0472                query.StartIndex,
 0473                totalCount,
 0474                itemsArray);
 475        }
 476
 477        public static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, 
 478        {
 10479            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 480            {
 0481                return false;
 482            }
 483
 10484            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 485            {
 0486                return false;
 487            }
 488
 10489            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 490            {
 0491                return false;
 492            }
 493
 10494            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 495            {
 0496                return false;
 497            }
 498
 10499            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 500            {
 0501                return false;
 502            }
 503
 10504            UserItemData userData = null;
 505
 10506            if (query.IsLiked.HasValue)
 507            {
 0508                userData = userDataManager.GetUserData(user, item);
 509
 0510                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 511                {
 0512                    return false;
 513                }
 514            }
 515
 10516            if (query.IsFavoriteOrLiked.HasValue)
 517            {
 0518                userData = userData ?? userDataManager.GetUserData(user, item);
 0519                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 520
 0521                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 522                {
 0523                    return false;
 524                }
 525            }
 526
 10527            if (query.IsFavorite.HasValue)
 528            {
 0529                userData = userData ?? userDataManager.GetUserData(user, item);
 530
 0531                if (userData.IsFavorite != query.IsFavorite.Value)
 532                {
 0533                    return false;
 534                }
 535            }
 536
 10537            if (query.IsResumable.HasValue)
 538            {
 0539                userData = userData ?? userDataManager.GetUserData(user, item);
 0540                var isResumable = userData.PlaybackPositionTicks > 0;
 541
 0542                if (isResumable != query.IsResumable.Value)
 543                {
 0544                    return false;
 545                }
 546            }
 547
 10548            if (query.IsPlayed.HasValue)
 549            {
 0550                if (item.IsPlayed(user) != query.IsPlayed.Value)
 551                {
 0552                    return false;
 553                }
 554            }
 555
 556            // Filter by Video3DFormat
 10557            if (query.Is3D.HasValue)
 558            {
 0559                var val = query.Is3D.Value;
 0560                var video = item as Video;
 561
 0562                if (video is null || val != video.Video3DFormat.HasValue)
 563                {
 0564                    return false;
 565                }
 566            }
 567
 568            /*
 569             * fuck - fix this
 570            if (query.IsHD.HasValue)
 571            {
 572                if (item.IsHD != query.IsHD.Value)
 573                {
 574                    return false;
 575                }
 576            }
 577            */
 578
 10579            if (query.IsLocked.HasValue)
 580            {
 0581                var val = query.IsLocked.Value;
 0582                if (item.IsLocked != val)
 583                {
 0584                    return false;
 585                }
 586            }
 587
 10588            if (query.HasOverview.HasValue)
 589            {
 0590                var filterValue = query.HasOverview.Value;
 591
 0592                var hasValue = !string.IsNullOrEmpty(item.Overview);
 593
 0594                if (hasValue != filterValue)
 595                {
 0596                    return false;
 597                }
 598            }
 599
 10600            if (query.HasImdbId.HasValue)
 601            {
 0602                var filterValue = query.HasImdbId.Value;
 603
 0604                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 605
 0606                if (hasValue != filterValue)
 607                {
 0608                    return false;
 609                }
 610            }
 611
 10612            if (query.HasTmdbId.HasValue)
 613            {
 0614                var filterValue = query.HasTmdbId.Value;
 615
 0616                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 617
 0618                if (hasValue != filterValue)
 619                {
 0620                    return false;
 621                }
 622            }
 623
 10624            if (query.HasTvdbId.HasValue)
 625            {
 0626                var filterValue = query.HasTvdbId.Value;
 627
 0628                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 629
 0630                if (hasValue != filterValue)
 631                {
 0632                    return false;
 633                }
 634            }
 635
 10636            if (query.HasOfficialRating.HasValue)
 637            {
 0638                var filterValue = query.HasOfficialRating.Value;
 639
 0640                var hasValue = !string.IsNullOrEmpty(item.OfficialRating);
 641
 0642                if (hasValue != filterValue)
 643                {
 0644                    return false;
 645                }
 646            }
 647
 10648            if (query.IsPlaceHolder.HasValue)
 649            {
 0650                var filterValue = query.IsPlaceHolder.Value;
 651
 0652                var isPlaceHolder = false;
 653
 0654                if (item is ISupportsPlaceHolders hasPlaceHolder)
 655                {
 0656                    isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
 657                }
 658
 0659                if (isPlaceHolder != filterValue)
 660                {
 0661                    return false;
 662                }
 663            }
 664
 10665            if (query.HasSpecialFeature.HasValue)
 666            {
 0667                var filterValue = query.HasSpecialFeature.Value;
 668
 0669                if (item is IHasSpecialFeatures movie)
 670                {
 0671                    var ok = filterValue
 0672                        ? movie.SpecialFeatureIds.Count > 0
 0673                        : movie.SpecialFeatureIds.Count == 0;
 674
 0675                    if (!ok)
 676                    {
 0677                        return false;
 678                    }
 679                }
 680                else
 681                {
 0682                    return false;
 683                }
 684            }
 685
 10686            if (query.HasSubtitles.HasValue)
 687            {
 0688                var val = query.HasSubtitles.Value;
 689
 0690                var video = item as Video;
 691
 0692                if (video is null || val != video.HasSubtitles)
 693                {
 0694                    return false;
 695                }
 696            }
 697
 10698            if (query.HasParentalRating.HasValue)
 699            {
 0700                var val = query.HasParentalRating.Value;
 701
 0702                var rating = item.CustomRating;
 703
 0704                if (string.IsNullOrEmpty(rating))
 705                {
 0706                    rating = item.OfficialRating;
 707                }
 708
 0709                if (val)
 710                {
 0711                    if (string.IsNullOrEmpty(rating))
 712                    {
 0713                        return false;
 714                    }
 715                }
 716                else
 717                {
 0718                    if (!string.IsNullOrEmpty(rating))
 719                    {
 0720                        return false;
 721                    }
 722                }
 723            }
 724
 10725            if (query.HasTrailer.HasValue)
 726            {
 0727                var val = query.HasTrailer.Value;
 0728                var trailerCount = 0;
 729
 0730                if (item is IHasTrailers hasTrailers)
 731                {
 0732                    trailerCount = hasTrailers.GetTrailerCount();
 733                }
 734
 0735                var ok = val ? trailerCount > 0 : trailerCount == 0;
 736
 0737                if (!ok)
 738                {
 0739                    return false;
 740                }
 741            }
 742
 10743            if (query.HasThemeSong.HasValue)
 744            {
 0745                var filterValue = query.HasThemeSong.Value;
 746
 0747                var themeCount = item.GetThemeSongs(user).Count;
 0748                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 749
 0750                if (!ok)
 751                {
 0752                    return false;
 753                }
 754            }
 755
 10756            if (query.HasThemeVideo.HasValue)
 757            {
 0758                var filterValue = query.HasThemeVideo.Value;
 759
 0760                var themeCount = item.GetThemeVideos(user).Count;
 0761                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 762
 0763                if (!ok)
 764                {
 0765                    return false;
 766                }
 767            }
 768
 769            // Apply genre filter
 10770            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 771            {
 0772                return false;
 773            }
 774
 775            // Filter by VideoType
 10776            if (query.VideoTypes.Length > 0)
 777            {
 0778                var video = item as Video;
 0779                if (video is null || !query.VideoTypes.Contains(video.VideoType))
 780                {
 0781                    return false;
 782                }
 783            }
 784
 10785            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 786            {
 0787                return false;
 788            }
 789
 790            // Apply studio filter
 10791            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 10792            {
 10793                var studioItem = libraryManager.GetItemById(id);
 10794                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 10795            }))
 796            {
 0797                return false;
 798            }
 799
 800            // Apply genre filter
 10801            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 10802            {
 10803                var genreItem = libraryManager.GetItemById(id);
 10804                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 10805            }))
 806            {
 0807                return false;
 808            }
 809
 810            // Apply year filter
 10811            if (query.Years.Length > 0)
 812            {
 0813                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 814                {
 0815                    return false;
 816                }
 817            }
 818
 819            // Apply official rating filter
 10820            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 821            {
 0822                return false;
 823            }
 824
 10825            if (query.ItemIds.Length > 0)
 826            {
 0827                if (!query.ItemIds.Contains(item.Id))
 828                {
 0829                    return false;
 830                }
 831            }
 832
 833            // Apply tag filter
 10834            var tags = query.Tags;
 10835            if (tags.Length > 0)
 836            {
 0837                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 838                {
 0839                    return false;
 840                }
 841            }
 842
 10843            if (query.MinCommunityRating.HasValue)
 844            {
 0845                var val = query.MinCommunityRating.Value;
 846
 0847                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 848                {
 0849                    return false;
 850                }
 851            }
 852
 10853            if (query.MinCriticRating.HasValue)
 854            {
 0855                var val = query.MinCriticRating.Value;
 856
 0857                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 858                {
 0859                    return false;
 860                }
 861            }
 862
 10863            if (query.MinIndexNumber.HasValue)
 864            {
 0865                var val = query.MinIndexNumber.Value;
 866
 0867                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 868                {
 0869                    return false;
 870                }
 871            }
 872
 10873            if (query.MinPremiereDate.HasValue)
 874            {
 0875                var val = query.MinPremiereDate.Value;
 876
 0877                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 878                {
 0879                    return false;
 880                }
 881            }
 882
 10883            if (query.MaxPremiereDate.HasValue)
 884            {
 0885                var val = query.MaxPremiereDate.Value;
 886
 0887                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 888                {
 0889                    return false;
 890                }
 891            }
 892
 10893            if (query.ParentIndexNumber.HasValue)
 894            {
 0895                var filterValue = query.ParentIndexNumber.Value;
 896
 0897                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 898                {
 0899                    return false;
 900                }
 901            }
 902
 10903            if (query.SeriesStatuses.Length > 0)
 904            {
 0905                var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.S
 0906                if (!ok)
 907                {
 0908                    return false;
 909                }
 910            }
 911
 10912            if (query.AiredDuringSeason.HasValue)
 913            {
 0914                var episode = item as Episode;
 915
 0916                if (episode is null)
 917                {
 0918                    return false;
 919                }
 920
 0921                if (!Series.FilterEpisodesBySeason(new[] { episode }, query.AiredDuringSeason.Value, true).Any())
 922                {
 0923                    return false;
 924                }
 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,System.Boolean)
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)