using MediaBrowser.Controller.IO; using MediaBrowser.Controller.Library; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using CommonIO; using MediaBrowser.Controller.Providers; namespace MediaBrowser.Controller.Entities { /// /// Specialized folder that can have items added to it's children by external entities. /// Used for our RootFolder so plug-ins can add items. /// public class AggregateFolder : Folder { public AggregateFolder() { PhysicalLocationsList = new List(); } /// /// We don't support manual shortcuts /// protected override bool SupportsShortcutChildren { get { return false; } } public override bool CanDelete() { return false; } /// /// The _virtual children /// private readonly ConcurrentBag _virtualChildren = new ConcurrentBag(); /// /// Gets the virtual children. /// /// The virtual children. public ConcurrentBag VirtualChildren { get { return _virtualChildren; } } [IgnoreDataMember] public override IEnumerable PhysicalLocations { get { return PhysicalLocationsList; } } public List PhysicalLocationsList { get; set; } protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { return CreateResolveArgs(directoryService, true).FileSystemChildren; } private bool _requiresRefresh; public override bool RequiresRefresh() { var changed = base.RequiresRefresh() || _requiresRefresh; if (!changed) { var locations = PhysicalLocations.ToList(); var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList(); if (!locations.SequenceEqual(newLocations)) { changed = true; } } return changed; } public override bool BeforeMetadataRefresh() { var changed = base.BeforeMetadataRefresh() || _requiresRefresh; _requiresRefresh = false; return changed; } private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations) { var path = ContainingFolderPath; var args = new ItemResolveArgs(ConfigurationManager.ApplicationPaths , directoryService) { FileInfo = FileSystem.GetDirectoryInfo(path), Path = path, Parent = Parent }; // Gather child folder and files if (args.IsDirectory) { var isPhysicalRoot = args.IsPhysicalRoot; // When resolving the root, we need it's grandchildren (children of user views) var flattenFolderDepth = isPhysicalRoot ? 2 : 0; var fileSystemDictionary = FileData.GetFilteredFileSystemEntries(directoryService, args.Path, FileSystem, Logger, args, flattenFolderDepth: flattenFolderDepth, resolveShortcuts: isPhysicalRoot || args.IsVf); // Need to remove subpaths that may have been resolved from shortcuts // Example: if \\server\movies exists, then strip out \\server\movies\action if (isPhysicalRoot) { var paths = LibraryManager.NormalizeRootPathList(fileSystemDictionary.Values); fileSystemDictionary = paths.ToDictionary(i => i.FullName); } args.FileSystemDictionary = fileSystemDictionary; } if (setPhysicalLocations) { _requiresRefresh = !args.PhysicalLocations.SequenceEqual(PhysicalLocations); PhysicalLocationsList = args.PhysicalLocations.ToList(); } return args; } /// /// Adds the virtual child. /// /// The child. /// public void AddVirtualChild(BaseItem child) { if (child == null) { throw new ArgumentNullException(); } _virtualChildren.Add(child); } /// /// Get the children of this folder from the actual file system /// /// IEnumerable{BaseItem}. protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) { return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); } /// /// Finds the virtual child. /// /// The id. /// BaseItem. /// id public BaseItem FindVirtualChild(Guid id) { if (id == Guid.Empty) { throw new ArgumentNullException("id"); } return _virtualChildren.FirstOrDefault(i => i.Id == id); } } }