< Summary - Jellyfin

Information
Class: MediaBrowser.Controller.Entities.AggregateFolder
Assembly: MediaBrowser.Controller
File(s): /srv/git/jellyfin/MediaBrowser.Controller/Entities/AggregateFolder.cs
Line coverage
83%
Covered lines: 49
Uncovered lines: 10
Coverable lines: 59
Total lines: 204
Line coverage: 83%
Branch coverage
66%
Covered branches: 16
Total branches: 24
Branch coverage: 66.6%
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%
get_VirtualChildren()100%11100%
get_IsPhysicalRoot()100%210%
get_SupportsPlayedStatus()100%210%
get_PhysicalLocations()100%11100%
CanDelete()100%210%
GetFileSystemChildren(...)100%11100%
LoadChildren()100%44100%
ClearCache()100%11100%
RequiresRefresh()83.33%66100%
BeforeMetadataRefresh(...)50%22100%
CreateResolveArgs(...)100%66100%
GetNonCachedChildren(...)100%11100%
AddVirtualChild(...)100%11100%
FindVirtualChild(...)0%4260%

File(s)

/srv/git/jellyfin/MediaBrowser.Controller/Entities/AggregateFolder.cs

#LineLine coverage
 1#nullable disable
 2
 3#pragma warning disable CA1819, CS1591
 4
 5using System;
 6using System.Collections.Concurrent;
 7using System.Collections.Generic;
 8using System.Linq;
 9using System.Text.Json.Serialization;
 10using System.Threading;
 11using System.Threading.Tasks;
 12using Jellyfin.Extensions;
 13using MediaBrowser.Controller.IO;
 14using MediaBrowser.Controller.Library;
 15using MediaBrowser.Controller.Providers;
 16using MediaBrowser.Model.IO;
 17
 18namespace MediaBrowser.Controller.Entities
 19{
 20    /// <summary>
 21    /// Specialized folder that can have items added to it's children by external entities.
 22    /// Used for our RootFolder so plugins can add items.
 23    /// </summary>
 24    public class AggregateFolder : Folder
 25    {
 4526        private readonly object _childIdsLock = new object();
 27
 28        /// <summary>
 29        /// The _virtual children.
 30        /// </summary>
 4531        private readonly ConcurrentBag<BaseItem> _virtualChildren = new ConcurrentBag<BaseItem>();
 32        private bool _requiresRefresh;
 33        private Guid[] _childrenIds = null;
 34
 4535        public AggregateFolder()
 36        {
 4537            PhysicalLocationsList = Array.Empty<string>();
 4538        }
 39
 40        /// <summary>
 41        /// Gets the virtual children.
 42        /// </summary>
 43        /// <value>The virtual children.</value>
 3344        public ConcurrentBag<BaseItem> VirtualChildren => _virtualChildren;
 45
 46        [JsonIgnore]
 047        public override bool IsPhysicalRoot => true;
 48
 49        [JsonIgnore]
 050        public override bool SupportsPlayedStatus => false;
 51
 52        [JsonIgnore]
 6353        public override string[] PhysicalLocations => PhysicalLocationsList;
 54
 55        public string[] PhysicalLocationsList { get; set; }
 56
 57        public override bool CanDelete()
 58        {
 059            return false;
 60        }
 61
 62        protected override FileSystemMetadata[] GetFileSystemChildren(IDirectoryService directoryService)
 63        {
 4064            return CreateResolveArgs(directoryService, true).FileSystemChildren;
 65        }
 66
 67        protected override List<BaseItem> LoadChildren()
 68        {
 11269            lock (_childIdsLock)
 70            {
 11271                if (_childrenIds is null || _childrenIds.Length == 0)
 72                {
 8473                    var list = base.LoadChildren();
 8474                    _childrenIds = list.Select(i => i.Id).ToArray();
 8475                    return list;
 76                }
 77
 2878                return _childrenIds.Select(LibraryManager.GetItemById).Where(i => i is not null).ToList();
 79            }
 11280        }
 81
 82        private void ClearCache()
 83        {
 16184            lock (_childIdsLock)
 85            {
 16186                _childrenIds = null;
 16187            }
 16188        }
 89
 90        public override bool RequiresRefresh()
 91        {
 2192            var changed = base.RequiresRefresh() || _requiresRefresh;
 93
 2194            if (!changed)
 95            {
 2096                var locations = PhysicalLocations;
 97
 2098                var newLocations = CreateResolveArgs(new DirectoryService(FileSystem), false).PhysicalLocations;
 99
 20100                if (!locations.SequenceEqual(newLocations))
 101                {
 17102                    changed = true;
 103                }
 104            }
 105
 21106            return changed;
 107        }
 108
 109        public override bool BeforeMetadataRefresh(bool replaceAllMetadata)
 110        {
 21111            ClearCache();
 112
 21113            var changed = base.BeforeMetadataRefresh(replaceAllMetadata) || _requiresRefresh;
 21114            _requiresRefresh = false;
 21115            return changed;
 116        }
 117
 118        private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations)
 119        {
 60120            ClearCache();
 121
 60122            var path = ContainingFolderPath;
 123
 60124            var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths, LibraryManager)
 60125            {
 60126                FileInfo = FileSystem.GetDirectoryInfo(path)
 60127            };
 128
 129            // Gather child folder and files
 60130            if (args.IsDirectory)
 131            {
 132                // When resolving the root, we need it's grandchildren (children of user views)
 60133                var flattenFolderDepth = 2;
 134
 60135                var files = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, CollectionFol
 136
 137                // Need to remove subpaths that may have been resolved from shortcuts
 138                // Example: if \\server\movies exists, then strip out \\server\movies\action
 60139                files = LibraryManager.NormalizeRootPathList(files).ToArray();
 140
 60141                args.FileSystemChildren = files;
 142            }
 143
 60144            _requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations);
 60145            if (setPhysicalLocations)
 146            {
 40147                PhysicalLocationsList = args.PhysicalLocations;
 148            }
 149
 60150            return args;
 151        }
 152
 153        protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService)
 154        {
 40155            return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren);
 156        }
 157
 158        protected override async Task ValidateChildrenInternal(IProgress<double> progress, bool recursive, bool refreshC
 159        {
 160            ClearCache();
 161
 162            await base.ValidateChildrenInternal(progress, recursive, refreshChildMetadata, allowRemoveRoot, refreshOptio
 163                .ConfigureAwait(false);
 164
 165            ClearCache();
 166        }
 167
 168        /// <summary>
 169        /// Adds the virtual child.
 170        /// </summary>
 171        /// <param name="child">The child.</param>
 172        /// <exception cref="ArgumentNullException">Throws if child is null.</exception>
 173        public void AddVirtualChild(BaseItem child)
 174        {
 22175            ArgumentNullException.ThrowIfNull(child);
 176
 22177            _virtualChildren.Add(child);
 22178        }
 179
 180        /// <summary>
 181        /// Finds the virtual child.
 182        /// </summary>
 183        /// <param name="id">The id.</param>
 184        /// <returns>BaseItem.</returns>
 185        /// <exception cref="ArgumentNullException">The id is empty.</exception>
 186        public BaseItem FindVirtualChild(Guid id)
 187        {
 0188            if (id.IsEmpty())
 189            {
 0190                throw new ArgumentNullException(nameof(id));
 191            }
 192
 0193            foreach (var child in _virtualChildren)
 194            {
 0195                if (child.Id.Equals(id))
 196                {
 0197                    return child;
 198                }
 199            }
 200
 0201            return null;
 0202        }
 203    }
 204}