< Summary - Jellyfin

Information
Class: Emby.Server.Implementations.Library.UserViewManager
Assembly: Emby.Server.Implementations
File(s): /srv/git/jellyfin/Emby.Server.Implementations/Library/UserViewManager.cs
Line coverage
29%
Covered lines: 54
Uncovered lines: 132
Coverable lines: 186
Total lines: 393
Line coverage: 29%
Branch coverage
15%
Covered branches: 15
Total branches: 98
Branch coverage: 15.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
GetUserViews(...)44.11%553473.84%
GetUserSubViewWithName(...)100%210%
GetUserSubView(...)100%210%
GetUserView(...)0%4260%
GetUserView(...)100%210%
GetLatestItems(...)0%156120%
GetItemsForLatestItems(...)0%2162460%

File(s)

/srv/git/jellyfin/Emby.Server.Implementations/Library/UserViewManager.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CS1591
 4
 5using System;
 6using System.Collections.Generic;
 7using System.Linq;
 8using System.Threading;
 9using Jellyfin.Data;
 10using Jellyfin.Data.Enums;
 11using Jellyfin.Database.Implementations.Entities;
 12using Jellyfin.Database.Implementations.Enums;
 13using Jellyfin.Extensions;
 14using MediaBrowser.Controller.Channels;
 15using MediaBrowser.Controller.Configuration;
 16using MediaBrowser.Controller.Dto;
 17using MediaBrowser.Controller.Entities;
 18using MediaBrowser.Controller.Library;
 19using MediaBrowser.Controller.LiveTv;
 20using MediaBrowser.Model.Channels;
 21using MediaBrowser.Model.Globalization;
 22using MediaBrowser.Model.Library;
 23using MediaBrowser.Model.Querying;
 24
 25namespace Emby.Server.Implementations.Library
 26{
 27    public class UserViewManager : IUserViewManager
 28    {
 29        private readonly ILibraryManager _libraryManager;
 30        private readonly ILocalizationManager _localizationManager;
 31
 32        private readonly IChannelManager _channelManager;
 33        private readonly ILiveTvManager _liveTvManager;
 34        private readonly IServerConfigurationManager _config;
 35
 36        public UserViewManager(ILibraryManager libraryManager, ILocalizationManager localizationManager, IChannelManager
 37        {
 2138            _libraryManager = libraryManager;
 2139            _localizationManager = localizationManager;
 2140            _channelManager = channelManager;
 2141            _liveTvManager = liveTvManager;
 2142            _config = config;
 2143        }
 44
 45        public Folder[] GetUserViews(UserViewQuery query)
 46        {
 147            var user = query.User;
 48
 149            var folders = _libraryManager.GetUserRootFolder()
 150                .GetChildren(user, true)
 151                .OfType<Folder>()
 152                .ToList();
 53
 154            var groupedFolders = new List<ICollectionFolder>();
 155            var list = new List<Folder>();
 56
 457            foreach (var folder in folders)
 58            {
 159                var collectionFolder = folder as ICollectionFolder;
 160                var folderViewType = collectionFolder?.CollectionType;
 61
 62                // Playlist library requires special handling because the folder only references user playlists
 163                if (folderViewType == CollectionType.playlists)
 64                {
 165                    var items = folder.GetItemList(new InternalItemsQuery(user)
 166                    {
 167                        ParentId = folder.ParentId
 168                    });
 69
 170                    if (!items.Any(item => item.IsVisible(user)))
 71                    {
 72                        continue;
 73                    }
 74                }
 75
 076                if (UserView.IsUserSpecific(folder))
 77                {
 078                    list.Add(_libraryManager.GetNamedView(user, folder.Name, folder.Id, folderViewType, null));
 079                    continue;
 80                }
 81
 082                if (collectionFolder is not null && UserView.IsEligibleForGrouping(folder) && user.IsFolderGrouped(folde
 83                {
 084                    groupedFolders.Add(collectionFolder);
 085                    continue;
 86                }
 87
 088                if (query.PresetViews.Contains(folderViewType))
 89                {
 090                    list.Add(GetUserView(folder, folderViewType, string.Empty));
 91                }
 92                else
 93                {
 094                    list.Add(folder);
 95                }
 96            }
 97
 698            foreach (var viewType in new[] { CollectionType.movies, CollectionType.tvshows })
 99            {
 2100                var parents = groupedFolders.Where(i => i.CollectionType == viewType || i.CollectionType is null)
 2101                    .ToList();
 102
 2103                if (parents.Count > 0)
 104                {
 0105                    var localizationKey = viewType == CollectionType.tvshows
 0106                        ? "TvShows"
 0107                        : "Movies";
 108
 0109                    list.Add(GetUserView(parents, viewType, localizationKey, string.Empty, user, query.PresetViews));
 110                }
 111            }
 112
 1113            if (_config.Configuration.EnableFolderView)
 114            {
 0115                var name = _localizationManager.GetLocalizedString("Folders");
 0116                list.Add(_libraryManager.GetNamedView(name, CollectionType.folders, string.Empty));
 117            }
 118
 1119            if (query.IncludeExternalContent)
 120            {
 1121                var channelResult = _channelManager.GetChannelsInternalAsync(new ChannelQuery
 1122                {
 1123                    UserId = user.Id
 1124                }).GetAwaiter().GetResult();
 125
 1126                var channels = channelResult.Items;
 127
 1128                list.AddRange(channels);
 129
 1130                if (_liveTvManager.GetEnabledUsers().Select(i => i.Id).Contains(user.Id))
 131                {
 0132                    list.Add(_liveTvManager.GetInternalLiveTvFolder(CancellationToken.None));
 133                }
 134            }
 135
 1136            if (!query.IncludeHidden)
 137            {
 0138                list = list.Where(i => !user.GetPreferenceValues<Guid>(PreferenceKind.MyMediaExcludes).Contains(i.Id)).T
 139            }
 140
 1141            var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
 1142            var orders = user.GetPreferenceValues<Guid>(PreferenceKind.OrderedViews);
 143
 1144            return list
 1145                .OrderBy(i =>
 1146                {
 1147                    var index = Array.IndexOf(orders, i.Id);
 1148                    if (index == -1
 1149                        && i is UserView view
 1150                        && !view.DisplayParentId.IsEmpty())
 1151                    {
 1152                        index = Array.IndexOf(orders, view.DisplayParentId);
 1153                    }
 1154
 1155                    return index == -1 ? int.MaxValue : index;
 1156                })
 1157                .ThenBy(sorted.IndexOf)
 1158                .ThenBy(i => i.SortName)
 1159                .ToArray();
 160        }
 161
 162        public UserView GetUserSubViewWithName(string name, Guid parentId, CollectionType? type, string sortName)
 163        {
 0164            var uniqueId = parentId + "subview" + type;
 165
 0166            return _libraryManager.GetNamedView(name, parentId, type, sortName, uniqueId);
 167        }
 168
 169        public UserView GetUserSubView(Guid parentId, CollectionType? type, string localizationKey, string sortName)
 170        {
 0171            var name = _localizationManager.GetLocalizedString(localizationKey);
 172
 0173            return GetUserSubViewWithName(name, parentId, type, sortName);
 174        }
 175
 176        private Folder GetUserView(
 177            List<ICollectionFolder> parents,
 178            CollectionType? viewType,
 179            string localizationKey,
 180            string sortName,
 181            User user,
 182            CollectionType?[] presetViews)
 183        {
 0184            if (parents.Count == 1 && parents.All(i => i.CollectionType == viewType))
 185            {
 0186                if (!presetViews.Contains(viewType))
 187                {
 0188                    return (Folder)parents[0];
 189                }
 190
 0191                return GetUserView((Folder)parents[0], viewType, string.Empty);
 192            }
 193
 0194            var name = _localizationManager.GetLocalizedString(localizationKey);
 0195            return _libraryManager.GetNamedView(user, name, viewType, sortName);
 196        }
 197
 198        public UserView GetUserView(Folder parent, CollectionType? viewType, string sortName)
 199        {
 0200            return _libraryManager.GetShadowView(parent, viewType, sortName);
 201        }
 202
 203        public List<Tuple<BaseItem, List<BaseItem>>> GetLatestItems(LatestItemsQuery request, DtoOptions options)
 204        {
 0205            var libraryItems = GetItemsForLatestItems(request.User, request, options);
 206
 0207            var list = new List<Tuple<BaseItem, List<BaseItem>>>();
 208
 0209            foreach (var item in libraryItems)
 210            {
 211                // Only grab the index container for media
 0212                var container = item.IsFolder || !request.GroupItems ? null : item.LatestItemsIndexContainer;
 213
 0214                if (container is null)
 215                {
 0216                    list.Add(new Tuple<BaseItem, List<BaseItem>>(null, new List<BaseItem> { item }));
 217                }
 218                else
 219                {
 0220                    var current = list.FirstOrDefault(i => i.Item1 is not null && i.Item1.Id.Equals(container.Id));
 221
 0222                    if (current is not null)
 223                    {
 0224                        current.Item2.Add(item);
 225                    }
 226                    else
 227                    {
 0228                        list.Add(new Tuple<BaseItem, List<BaseItem>>(container, new List<BaseItem> { item }));
 229                    }
 230                }
 231
 0232                if (list.Count >= request.Limit)
 233                {
 0234                    break;
 235                }
 236            }
 237
 0238            return list;
 239        }
 240
 241        private IReadOnlyList<BaseItem> GetItemsForLatestItems(User user, LatestItemsQuery request, DtoOptions options)
 242        {
 0243            var parentId = request.ParentId;
 244
 0245            var includeItemTypes = request.IncludeItemTypes;
 0246            var limit = request.Limit ?? 10;
 247
 0248            var parents = new List<BaseItem>();
 249
 0250            if (!parentId.IsEmpty())
 251            {
 0252                var parentItem = _libraryManager.GetItemById(parentId);
 0253                if (parentItem is Channel)
 254                {
 0255                    return _channelManager.GetLatestChannelItemsInternal(
 0256                        new InternalItemsQuery(user)
 0257                        {
 0258                            ChannelIds = new[] { parentId },
 0259                            IsPlayed = request.IsPlayed,
 0260                            StartIndex = request.StartIndex,
 0261                            Limit = request.Limit,
 0262                            IncludeItemTypes = request.IncludeItemTypes,
 0263                            EnableTotalRecordCount = false
 0264                        },
 0265                        CancellationToken.None).GetAwaiter().GetResult().Items;
 266                }
 267
 0268                if (parentItem is Folder parent)
 269                {
 0270                    parents.Add(parent);
 271                }
 272            }
 273
 0274            var isPlayed = request.IsPlayed;
 275
 0276            if (parents.OfType<ICollectionFolder>().Any(i => i.CollectionType == CollectionType.music))
 277            {
 0278                isPlayed = null;
 279            }
 280
 0281            if (parents.Count == 0)
 282            {
 0283                parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
 0284                    .Where(i => i is Folder)
 0285                    .Where(i => !user.GetPreferenceValues<Guid>(PreferenceKind.LatestItemExcludes)
 0286                        .Contains(i.Id))
 0287                    .ToList();
 288            }
 289
 0290            if (parents.Count == 0)
 291            {
 0292                return Array.Empty<BaseItem>();
 293            }
 294
 0295            if (includeItemTypes.Length == 0)
 296            {
 297                // Handle situations with the grouping setting, e.g. movies showing up in tv, etc.
 298                // Thanks to mixed content libraries included in the UserView
 0299                var hasCollectionType = parents.OfType<UserView>().ToList();
 0300                if (hasCollectionType.Count > 0)
 301                {
 0302                    if (hasCollectionType.All(i => i.CollectionType == CollectionType.movies))
 303                    {
 0304                        includeItemTypes = new[] { BaseItemKind.Movie };
 305                    }
 0306                    else if (hasCollectionType.All(i => i.CollectionType == CollectionType.tvshows))
 307                    {
 0308                        includeItemTypes = new[] { BaseItemKind.Episode };
 309                    }
 310                }
 311            }
 312
 0313            MediaType[] mediaTypes = [];
 314
 0315            if (includeItemTypes.Length == 0)
 316            {
 0317                HashSet<MediaType> tmpMediaTypes = [];
 0318                foreach (var parent in parents.OfType<ICollectionFolder>())
 319                {
 0320                    switch (parent.CollectionType)
 321                    {
 322                        case CollectionType.books:
 0323                            tmpMediaTypes.Add(MediaType.Book);
 0324                            tmpMediaTypes.Add(MediaType.Audio);
 0325                            break;
 326                        case CollectionType.music:
 0327                            tmpMediaTypes.Add(MediaType.Audio);
 0328                            break;
 329                        case CollectionType.photos:
 0330                            tmpMediaTypes.Add(MediaType.Photo);
 0331                            tmpMediaTypes.Add(MediaType.Video);
 0332                            break;
 333                        case CollectionType.homevideos:
 0334                            tmpMediaTypes.Add(MediaType.Photo);
 0335                            tmpMediaTypes.Add(MediaType.Video);
 0336                            break;
 337                        default:
 0338                            tmpMediaTypes.Add(MediaType.Video);
 339                            break;
 340                    }
 341                }
 342
 0343                mediaTypes = tmpMediaTypes.ToArray();
 344            }
 345
 0346            var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Length == 0
 0347                ? new[]
 0348                {
 0349                    BaseItemKind.Person,
 0350                    BaseItemKind.Studio,
 0351                    BaseItemKind.Year,
 0352                    BaseItemKind.MusicGenre,
 0353                    BaseItemKind.Genre
 0354                }
 0355                : Array.Empty<BaseItemKind>();
 356
 0357            var query = new InternalItemsQuery(user)
 0358            {
 0359                IncludeItemTypes = includeItemTypes,
 0360                OrderBy = new[]
 0361                {
 0362                    (ItemSortBy.DateCreated, SortOrder.Descending),
 0363                    (ItemSortBy.SortName, SortOrder.Descending),
 0364                    (ItemSortBy.ProductionYear, SortOrder.Descending)
 0365                },
 0366                IsFolder = includeItemTypes.Length == 0 ? false : null,
 0367                ExcludeItemTypes = excludeItemTypes,
 0368                IsVirtualItem = false,
 0369                Limit = limit * 5,
 0370                IsPlayed = isPlayed,
 0371                DtoOptions = options,
 0372                MediaTypes = mediaTypes
 0373            };
 374
 0375            if (request.GroupItems)
 376            {
 0377                if (parents.OfType<ICollectionFolder>().All(i => i.CollectionType == CollectionType.tvshows))
 378                {
 0379                    query.Limit = limit;
 0380                    return _libraryManager.GetLatestItemList(query, parents, CollectionType.tvshows);
 381                }
 382
 0383                if (parents.OfType<ICollectionFolder>().All(i => i.CollectionType == CollectionType.music))
 384                {
 0385                    query.Limit = limit;
 0386                    return _libraryManager.GetLatestItemList(query, parents, CollectionType.music);
 387                }
 388            }
 389
 0390            return _libraryManager.GetItemList(query, parents);
 391        }
 392    }
 393}