< 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: 57
Uncovered lines: 393
Coverable lines: 450
Total lines: 1027
Line coverage: 12.6%
Branch coverage
30%
Covered branches: 91
Total branches: 296
Branch coverage: 30.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);
 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 (!string.IsNullOrEmpty(query.NameStartsWith) && !item.SortName.StartsWith(query.NameStartsWith, StringCom
 476            {
 0477                return false;
 478            }
 479
 480#pragma warning disable CA1309 // Use ordinal string comparison
 10481            if (!string.IsNullOrEmpty(query.NameStartsWithOrGreater) && string.Compare(query.NameStartsWithOrGreater, it
 482            {
 0483                return false;
 484            }
 485
 10486            if (!string.IsNullOrEmpty(query.NameLessThan) && string.Compare(query.NameLessThan, item.SortName, StringCom
 487#pragma warning restore CA1309 // Use ordinal string comparison
 488            {
 0489                return false;
 490            }
 491
 10492            if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType))
 493            {
 0494                return false;
 495            }
 496
 10497            if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetBaseItemKind()))
 498            {
 0499                return false;
 500            }
 501
 10502            if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetBaseItemKind()))
 503            {
 0504                return false;
 505            }
 506
 10507            if (query.IsVirtualItem.HasValue && item.IsVirtualItem != query.IsVirtualItem.Value)
 508            {
 0509                return false;
 510            }
 511
 10512            if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
 513            {
 0514                return false;
 515            }
 516
 10517            UserItemData userData = null;
 518
 10519            if (query.IsLiked.HasValue)
 520            {
 0521                userData = userDataManager.GetUserData(user, item);
 0522                if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
 523                {
 0524                    return false;
 525                }
 526            }
 527
 10528            if (query.IsFavoriteOrLiked.HasValue)
 529            {
 0530                userData ??= userDataManager.GetUserData(user, item);
 0531                var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
 532
 0533                if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
 534                {
 0535                    return false;
 536                }
 537            }
 538
 10539            if (query.IsFavorite.HasValue)
 540            {
 0541                userData ??= userDataManager.GetUserData(user, item);
 0542                if (userData.IsFavorite != query.IsFavorite.Value)
 543                {
 0544                    return false;
 545                }
 546            }
 547
 10548            if (query.IsResumable.HasValue)
 549            {
 0550                userData ??= userDataManager.GetUserData(user, item);
 0551                var isResumable = userData.PlaybackPositionTicks > 0;
 552
 0553                if (isResumable != query.IsResumable.Value)
 554                {
 0555                    return false;
 556                }
 557            }
 558
 10559            if (query.IsPlayed.HasValue)
 560            {
 0561                userData ??= userDataManager.GetUserData(user, item);
 0562                if (item.IsPlayed(user, userData) != query.IsPlayed.Value)
 563                {
 0564                    return false;
 565                }
 566            }
 567
 568            // Filter by Video3DFormat
 10569            if (query.Is3D.HasValue)
 570            {
 0571                var val = query.Is3D.Value;
 0572                var video = item as Video;
 573
 0574                if (video is null || val != video.Video3DFormat.HasValue)
 575                {
 0576                    return false;
 577                }
 578            }
 579
 580            /*
 581             * fuck - fix this
 582            if (query.IsHD.HasValue)
 583            {
 584                if (item.IsHD != query.IsHD.Value)
 585                {
 586                    return false;
 587                }
 588            }
 589            */
 590
 10591            if (query.IsLocked.HasValue)
 592            {
 0593                var val = query.IsLocked.Value;
 0594                if (item.IsLocked != val)
 595                {
 0596                    return false;
 597                }
 598            }
 599
 10600            if (query.HasOverview.HasValue)
 601            {
 0602                var filterValue = query.HasOverview.Value;
 603
 0604                var hasValue = !string.IsNullOrEmpty(item.Overview);
 605
 0606                if (hasValue != filterValue)
 607                {
 0608                    return false;
 609                }
 610            }
 611
 10612            if (query.HasImdbId.HasValue)
 613            {
 0614                var filterValue = query.HasImdbId.Value;
 615
 0616                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Imdb));
 617
 0618                if (hasValue != filterValue)
 619                {
 0620                    return false;
 621                }
 622            }
 623
 10624            if (query.HasTmdbId.HasValue)
 625            {
 0626                var filterValue = query.HasTmdbId.Value;
 627
 0628                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tmdb));
 629
 0630                if (hasValue != filterValue)
 631                {
 0632                    return false;
 633                }
 634            }
 635
 10636            if (query.HasTvdbId.HasValue)
 637            {
 0638                var filterValue = query.HasTvdbId.Value;
 639
 0640                var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProvider.Tvdb));
 641
 0642                if (hasValue != filterValue)
 643                {
 0644                    return false;
 645                }
 646            }
 647
 10648            if (query.HasOfficialRating.HasValue)
 649            {
 0650                var filterValue = query.HasOfficialRating.Value;
 651
 0652                var hasValue = !string.IsNullOrEmpty(item.OfficialRating);
 653
 0654                if (hasValue != filterValue)
 655                {
 0656                    return false;
 657                }
 658            }
 659
 10660            if (query.IsPlaceHolder.HasValue)
 661            {
 0662                var filterValue = query.IsPlaceHolder.Value;
 663
 0664                var isPlaceHolder = false;
 665
 0666                if (item is ISupportsPlaceHolders hasPlaceHolder)
 667                {
 0668                    isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
 669                }
 670
 0671                if (isPlaceHolder != filterValue)
 672                {
 0673                    return false;
 674                }
 675            }
 676
 10677            if (query.HasSpecialFeature.HasValue)
 678            {
 0679                var filterValue = query.HasSpecialFeature.Value;
 680
 0681                if (item is IHasSpecialFeatures movie)
 682                {
 0683                    var ok = filterValue
 0684                        ? movie.SpecialFeatureIds.Count > 0
 0685                        : movie.SpecialFeatureIds.Count == 0;
 686
 0687                    if (!ok)
 688                    {
 0689                        return false;
 690                    }
 691                }
 692                else
 693                {
 0694                    return false;
 695                }
 696            }
 697
 10698            if (query.HasSubtitles.HasValue)
 699            {
 0700                var val = query.HasSubtitles.Value;
 701
 0702                var video = item as Video;
 703
 0704                if (video is null || val != video.HasSubtitles)
 705                {
 0706                    return false;
 707                }
 708            }
 709
 10710            if (query.HasParentalRating.HasValue)
 711            {
 0712                var val = query.HasParentalRating.Value;
 713
 0714                var rating = item.CustomRating;
 715
 0716                if (string.IsNullOrEmpty(rating))
 717                {
 0718                    rating = item.OfficialRating;
 719                }
 720
 0721                if (val)
 722                {
 0723                    if (string.IsNullOrEmpty(rating))
 724                    {
 0725                        return false;
 726                    }
 727                }
 728                else
 729                {
 0730                    if (!string.IsNullOrEmpty(rating))
 731                    {
 0732                        return false;
 733                    }
 734                }
 735            }
 736
 10737            if (query.HasTrailer.HasValue)
 738            {
 0739                var val = query.HasTrailer.Value;
 0740                var trailerCount = 0;
 741
 0742                if (item is IHasTrailers hasTrailers)
 743                {
 0744                    trailerCount = hasTrailers.GetTrailerCount();
 745                }
 746
 0747                var ok = val ? trailerCount > 0 : trailerCount == 0;
 748
 0749                if (!ok)
 750                {
 0751                    return false;
 752                }
 753            }
 754
 10755            if (query.HasThemeSong.HasValue)
 756            {
 0757                var filterValue = query.HasThemeSong.Value;
 758
 0759                var themeCount = item.GetThemeSongs(user).Count;
 0760                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 761
 0762                if (!ok)
 763                {
 0764                    return false;
 765                }
 766            }
 767
 10768            if (query.HasThemeVideo.HasValue)
 769            {
 0770                var filterValue = query.HasThemeVideo.Value;
 771
 0772                var themeCount = item.GetThemeVideos(user).Count;
 0773                var ok = filterValue ? themeCount > 0 : themeCount == 0;
 774
 0775                if (!ok)
 776                {
 0777                    return false;
 778                }
 779            }
 780
 781            // Apply genre filter
 10782            if (query.Genres.Count > 0 && !query.Genres.Any(v => item.Genres.Contains(v, StringComparison.OrdinalIgnoreC
 783            {
 0784                return false;
 785            }
 786
 787            // Filter by VideoType
 10788            if (query.VideoTypes.Length > 0)
 789            {
 0790                var video = item as Video;
 0791                if (video is null || !query.VideoTypes.Contains(video.VideoType))
 792                {
 0793                    return false;
 794                }
 795            }
 796
 10797            if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
 798            {
 0799                return false;
 800            }
 801
 802            // Apply studio filter
 10803            if (query.StudioIds.Length > 0 && !query.StudioIds.Any(id =>
 10804            {
 10805                var studioItem = libraryManager.GetItemById(id);
 10806                return studioItem is not null && item.Studios.Contains(studioItem.Name, StringComparison.OrdinalIgnoreCa
 10807            }))
 808            {
 0809                return false;
 810            }
 811
 812            // Apply genre filter
 10813            if (query.GenreIds.Count > 0 && !query.GenreIds.Any(id =>
 10814            {
 10815                var genreItem = libraryManager.GetItemById(id);
 10816                return genreItem is not null && item.Genres.Contains(genreItem.Name, StringComparison.OrdinalIgnoreCase)
 10817            }))
 818            {
 0819                return false;
 820            }
 821
 822            // Apply year filter
 10823            if (query.Years.Length > 0)
 824            {
 0825                if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
 826                {
 0827                    return false;
 828                }
 829            }
 830
 831            // Apply official rating filter
 10832            if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)
 833            {
 0834                return false;
 835            }
 836
 10837            if (query.ItemIds.Length > 0)
 838            {
 0839                if (!query.ItemIds.Contains(item.Id))
 840                {
 0841                    return false;
 842                }
 843            }
 844
 845            // Apply tag filter
 10846            var tags = query.Tags;
 10847            if (tags.Length > 0)
 848            {
 0849                if (!tags.Any(v => item.Tags.Contains(v, StringComparison.OrdinalIgnoreCase)))
 850                {
 0851                    return false;
 852                }
 853            }
 854
 10855            if (query.MinCommunityRating.HasValue)
 856            {
 0857                var val = query.MinCommunityRating.Value;
 858
 0859                if (!(item.CommunityRating.HasValue && item.CommunityRating >= val))
 860                {
 0861                    return false;
 862                }
 863            }
 864
 10865            if (query.MinCriticRating.HasValue)
 866            {
 0867                var val = query.MinCriticRating.Value;
 868
 0869                if (!(item.CriticRating.HasValue && item.CriticRating >= val))
 870                {
 0871                    return false;
 872                }
 873            }
 874
 10875            if (query.MinIndexNumber.HasValue)
 876            {
 0877                var val = query.MinIndexNumber.Value;
 878
 0879                if (!(item.IndexNumber.HasValue && item.IndexNumber.Value >= val))
 880                {
 0881                    return false;
 882                }
 883            }
 884
 10885            if (query.MinPremiereDate.HasValue)
 886            {
 0887                var val = query.MinPremiereDate.Value;
 888
 0889                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value >= val))
 890                {
 0891                    return false;
 892                }
 893            }
 894
 10895            if (query.MaxPremiereDate.HasValue)
 896            {
 0897                var val = query.MaxPremiereDate.Value;
 898
 0899                if (!(item.PremiereDate.HasValue && item.PremiereDate.Value <= val))
 900                {
 0901                    return false;
 902                }
 903            }
 904
 10905            if (query.ParentIndexNumber.HasValue)
 906            {
 0907                var filterValue = query.ParentIndexNumber.Value;
 908
 0909                if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value != filterValue)
 910                {
 0911                    return false;
 912                }
 913            }
 914
 10915            if (query.SeriesStatuses.Length > 0)
 916            {
 0917                var ok = new[] { item }.OfType<Series>().Any(p => p.Status.HasValue && query.SeriesStatuses.Contains(p.S
 0918                if (!ok)
 919                {
 0920                    return false;
 921                }
 922            }
 923
 10924            if (query.AiredDuringSeason.HasValue)
 925            {
 0926                var episode = item as Episode;
 927
 0928                if (episode is null)
 929                {
 0930                    return false;
 931                }
 932
 0933                if (!Series.FilterEpisodesBySeason(new[] { episode }, query.AiredDuringSeason.Value, true).Any())
 934                {
 0935                    return false;
 936                }
 937            }
 938
 10939            if (query.ExcludeItemIds.Contains(item.Id))
 940            {
 0941                return false;
 942            }
 943
 10944            return true;
 945        }
 946
 947        private IEnumerable<BaseItem> GetMediaFolders(User user)
 948        {
 0949            if (user is null)
 950            {
 0951                return _libraryManager.RootFolder
 0952                    .Children
 0953                    .OfType<Folder>()
 0954                    .Where(UserView.IsEligibleForGrouping);
 955            }
 956
 0957            return _libraryManager.GetUserRootFolder()
 0958                .GetChildren(user, true)
 0959                .OfType<Folder>()
 0960                .Where(i => user.IsFolderGrouped(i.Id) && UserView.IsEligibleForGrouping(i));
 961        }
 962
 963        private BaseItem[] GetMediaFolders(User user, IEnumerable<CollectionType> viewTypes)
 964        {
 0965            if (user is null)
 966            {
 0967                return GetMediaFolders(null)
 0968                    .Where(i =>
 0969                    {
 0970                        var folder = i as ICollectionFolder;
 0971
 0972                        return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0973                    }).ToArray();
 974            }
 975
 0976            return GetMediaFolders(user)
 0977                .Where(i =>
 0978                {
 0979                    var folder = i as ICollectionFolder;
 0980
 0981                    return folder?.CollectionType is not null && viewTypes.Contains(folder.CollectionType.Value);
 0982                }).ToArray();
 983        }
 984
 985        private BaseItem[] GetMediaFolders(Folder parent, User user, IEnumerable<CollectionType> viewTypes)
 986        {
 0987            if (parent is null || parent is UserView)
 988            {
 0989                return GetMediaFolders(user, viewTypes);
 990            }
 991
 0992            return new BaseItem[] { parent };
 993        }
 994
 995        private UserView GetUserViewWithName(CollectionType? type, string sortName, BaseItem parent)
 996        {
 0997            return _userViewManager.GetUserSubView(parent.Id, type, parent.Id.ToString("N", CultureInfo.InvariantCulture
 998        }
 999
 1000        private UserView GetUserView(CollectionType? type, string localizationKey, string sortName, BaseItem parent)
 1001        {
 01002            return _userViewManager.GetUserSubView(parent.Id, type, localizationKey, sortName);
 1003        }
 1004
 1005        public static IEnumerable<BaseItem> FilterForAdjacency(List<BaseItem> list, Guid adjacentTo)
 1006        {
 01007            var adjacentToItem = list.FirstOrDefault(i => i.Id.Equals(adjacentTo));
 1008
 01009            var index = list.IndexOf(adjacentToItem);
 1010
 01011            var previousId = Guid.Empty;
 01012            var nextId = Guid.Empty;
 1013
 01014            if (index > 0)
 1015            {
 01016                previousId = list[index - 1].Id;
 1017            }
 1018
 01019            if (index < list.Count - 1)
 1020            {
 01021                nextId = list[index + 1].Id;
 1022            }
 1023
 01024            return list.Where(i => i.Id.Equals(previousId) || i.Id.Equals(nextId) || i.Id.Equals(adjacentTo));
 1025        }
 1026    }
 1027}

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)