/// <summary> /// Checks if a potential series folder has season folders /// </summary> /// <param name="seriesFolder">Potential series folder accessor</param> /// <param name="knownSeasonNo">Number of a known season if available</param> /// <returns>True if folder has season folders</returns> public static bool IsSeriesFolder(IFileSystemResourceAccessor seriesFolder, int?knownSeasonNo = null) { if (seriesFolder == null) { return(false); } int maxInvalidFolders = 3; var seasonFolders = seriesFolder.GetChildDirectories(); var seasonNos = seasonFolders.Select(GetSeasonFromFolder).ToList(); var invalidSeasonCount = seasonNos.Count(s => s < 0); var validSeasonCount = seasonNos.Count(s => s >= 0); if (invalidSeasonCount <= maxInvalidFolders && validSeasonCount > 0) { return(true); } if (invalidSeasonCount > maxInvalidFolders) { return(false); } if (validSeasonCount > 0 && knownSeasonNo >= 0 && !seasonNos.Contains(knownSeasonNo.Value)) { return(false); } return(true); }
/// <summary> /// Returns all child directories of the given directory. /// </summary> /// <remarks> /// This will return all native child directories of the given directory together with all virtual child /// directories. The native child directories are taken directly from the given <paramref name="directoryAccessor"/>, /// the virtual child directories are obtained by taking the root directories of each chained resource provider applied /// to the child files of the given directory. /// If, for example, the given <paramref name="directoryAccessor"/> contains a child directory "A" and a child /// archive file "B" which can work as input for an installed archive provider, providing the root directory "C" /// of that archive, this method will return the resource accessors for directories "A" and "C". /// </remarks> /// <param name="directoryAccessor">Directory resource accessor to get all child directories for.</param> /// <param name="showSystemResources">If set to <c>true</c>, system resources like the virtual drives and directories of the /// <see cref="IResourceMountingService"/> will also be returned, else removed from the result value.</param> /// <returns>Collection of directory accessors for all native and virtual child directories or <c>null</c>, /// if the given <paramref name="directoryAccessor"/> does not point to a directory and /// if there is no chained resource provider to unfold the given file.</returns> public static ICollection<IFileSystemResourceAccessor> GetChildDirectories(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get<IResourceMountingService>(); IFileSystemResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here // If directoryAccessor points to a directory, we return all actual subdirectories and the virtual subdirectories // we can create by using all available ChainedResourceProviders on all contained files. if (!directoryAccessor.IsFile) { ICollection<IFileSystemResourceAccessor> childDirectories = directoryAccessor.GetChildDirectories(); ICollection<IFileSystemResourceAccessor> result = new List<IFileSystemResourceAccessor>(); if (childDirectories != null) // Directories are maybe filtered and then just added foreach (IFileSystemResourceAccessor childDirectoryAccessor in childDirectories) { if (!showSystemResources && resourceMountingService.IsVirtualResource(childDirectoryAccessor.CanonicalLocalResourcePath)) { childDirectoryAccessor.Dispose(); continue; } result.Add(childDirectoryAccessor); } ICollection<IFileSystemResourceAccessor> files = directoryAccessor.GetFiles(); if (files != null) // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) using (fileAccessor) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) continue; if (TryUnfold(fileAccessor, out chainedResourceAccesor)) if (!chainedResourceAccesor.IsFile) result.Add(chainedResourceAccesor); else chainedResourceAccesor.Dispose(); // Simply ignore files because we only want to return directories } return result; } // Try to unfold file resource if (TryUnfold(directoryAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) return new List<IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] {chainedResourceAccesor}); chainedResourceAccesor.Dispose(); return new List<IFileSystemResourceAccessor>(); } return null; }
public override async Task <AsyncResult <ContentDirectoryMessaging.MediaItemChangeType> > ProcessAsync(MediaItem mediaItem) { IContentDirectory cd = ServiceRegistration.Get <IServerConnectionManager>().ContentDirectory; bool removeFromML = IsManagedByMediaLibrary(mediaItem) && cd != null; var falseResult = new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(false, ContentDirectoryMessaging.MediaItemChangeType.None); // Support multi-resource media items and secondary resources IList <MultipleMediaItemAspect> providerAspects; if (!MediaItemAspect.TryGetAspects(mediaItem.Aspects, ProviderResourceAspect.Metadata, out providerAspects)) { return(falseResult); } foreach (MultipleMediaItemAspect providerAspect in providerAspects) { string systemId = (string)providerAspect[ProviderResourceAspect.ATTR_SYSTEM_ID]; string resourceAccessorPath = (string)providerAspect[ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH]; var rl = new ResourceLocator(systemId, ResourcePath.Deserialize(resourceAccessorPath)); using (var ra = rl.CreateAccessor()) { var rad = ra as IResourceDeletor; if (rad == null) { return(falseResult); } // First try to delete the file from storage. if (!rad.Delete()) { return(falseResult); } // If the MediaItem was loaded from ML, remove it there as well. if (removeFromML) { await cd.DeleteMediaItemOrPathAsync(rl.NativeSystemId, rl.NativeResourcePath, true); } } } // Check for special cases here: // 1) Recordings have an additional .xml attached // 2) Deleting files could lead to empty folders that should be also removed foreach (DeleteRule rule in _defaultRules.Where(r => r.IsEnabled)) { if (mediaItem.Aspects.ContainsKey(rule.HasAspectGuid)) { var tsPath = mediaItem.GetResourceLocator().NativeResourcePath.ToString(); foreach (string otherExtension in rule.DeleteOtherExtensions) { string otherFilePath = ProviderPathHelper.ChangeExtension(tsPath, otherExtension); IResourceAccessor ra; if (!ResourcePath.Deserialize(otherFilePath).TryCreateLocalResourceAccessor(out ra)) { continue; } // Delete other file. We do not check here for existance of file, the Delete needs to handle this. using (ra) { var rad = ra as IResourceDeletor; rad?.Delete(); } } if (rule.DeleteEmptyFolders) { var folderPath = ProviderPathHelper.GetDirectoryName(tsPath); IResourceAccessor ra; if (!ResourcePath.Deserialize(folderPath).TryCreateLocalResourceAccessor(out ra)) { continue; } // Delete folder if empty using (ra) { IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor; if (fsra != null) { var isEmpty = fsra.GetFiles().Count == 0 && fsra.GetChildDirectories().Count == 0; if (isEmpty) { var rad = ra as IResourceDeletor; rad?.Delete(); } } } } } } return(new AsyncResult <ContentDirectoryMessaging.MediaItemChangeType>(true, ContentDirectoryMessaging.MediaItemChangeType.Deleted)); }
/// <summary> /// Returns all child directories of the given directory. /// </summary> /// <remarks> /// This will return all native child directories of the given directory together with all virtual child /// directories. The native child directories are taken directly from the given <paramref name="directoryAccessor"/>, /// the virtual child directories are obtained by taking the root directories of each chained resource provider applied /// to the child files of the given directory. /// If, for example, the given <paramref name="directoryAccessor"/> contains a child directory "A" and a child /// archive file "B" which can work as input for an installed archive provider, providing the root directory "C" /// of that archive, this method will return the resource accessors for directories "A" and "C". /// </remarks> /// <param name="directoryAccessor">Directory resource accessor to get all child directories for.</param> /// <param name="showSystemResources">If set to <c>true</c>, system resources like the virtual drives and directories of the /// <see cref="IResourceMountingService"/> will also be returned, else removed from the result value.</param> /// <returns>Collection of directory accessors for all native and virtual child directories or <c>null</c>, /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/> and /// if there is no chained resource provider to unfold the given directory.</returns> public static ICollection <IFileSystemResourceAccessor> GetChildDirectories(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get <IResourceMountingService>(); IFileSystemResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here ICollection <IFileSystemResourceAccessor> childDirectories = directoryAccessor.GetChildDirectories(); ICollection <IFileSystemResourceAccessor> result = new List <IFileSystemResourceAccessor>(); if (childDirectories != null) { // Directories are maybe filtered and then just added foreach (IFileSystemResourceAccessor childDirectoryAccessor in childDirectories) { if (!showSystemResources && resourceMountingService.IsVirtualResource(childDirectoryAccessor.CanonicalLocalResourcePath)) { childDirectoryAccessor.Dispose(); continue; } result.Add(childDirectoryAccessor); } } ICollection <IFileSystemResourceAccessor> files = directoryAccessor.GetFiles(); if (files != null) { // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) { using (fileAccessor) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) { continue; } if (TryUnfold(fileAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) { result.Add(chainedResourceAccesor); } else { chainedResourceAccesor.Dispose(); } } // Simply ignore files because we only want to return directories } } } if (result.Count > 0) { return(result); } // Try to unfold simple resource if (TryUnfold(directoryAccessor, out chainedResourceAccesor)) { if (!chainedResourceAccesor.IsFile) { return(new List <IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] { chainedResourceAccesor })); } chainedResourceAccesor.Dispose(); } return(null); }
/// <summary> /// Returns all child directories of the given directory. /// </summary> /// <remarks> /// This will return all native child directories of the given directory together with all virtual child /// directories. The native child directories are taken directly from the given <paramref name="directoryAccessor"/>, /// the virtual child directories are obtained by taking the root directories of each chained resource provider applied /// to the child files of the given directory. /// If, for example, the given <paramref name="directoryAccessor"/> contains a child directory "A" and a child /// archive file "B" which can work as input for an installed archive provider, providing the root directory "C" /// of that archive, this method will return the resource accessors for directories "A" and "C". /// </remarks> /// <param name="directoryAccessor">Directory resource accessor to get all child directories for.</param> /// <param name="showSystemResources">If set to <c>true</c>, system resources like the virtual drives and directories of the /// <see cref="IResourceMountingService"/> will also be returned, else removed from the result value.</param> /// <returns>Collection of directory accessors for all native and virtual child directories or <c>null</c>, /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/> and /// if there is no chained resource provider to unfold the given directory.</returns> public static ICollection <IFileSystemResourceAccessor> GetChildDirectories(IResourceAccessor directoryAccessor, bool showSystemResources) { IResourceMountingService resourceMountingService = ServiceRegistration.Get <IResourceMountingService>(); IResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here if (directoryAccessor is IFileSystemResourceAccessor) { IFileSystemResourceAccessor dirFsra = (IFileSystemResourceAccessor)directoryAccessor; ICollection <IFileSystemResourceAccessor> childDirectories = dirFsra.GetChildDirectories(); ICollection <IFileSystemResourceAccessor> result = new List <IFileSystemResourceAccessor>(); if (childDirectories != null) { // Directories are maybe filtered and then just added foreach (IFileSystemResourceAccessor childDirectoryAccessor in childDirectories) { if (!showSystemResources && resourceMountingService.IsVirtualResource(childDirectoryAccessor.CanonicalLocalResourcePath)) { childDirectoryAccessor.Dispose(); continue; } result.Add(childDirectoryAccessor); } } ICollection <IFileSystemResourceAccessor> files = dirFsra.GetFiles(); if (files != null) { // For files, we try to chain up chained resource providers foreach (IFileSystemResourceAccessor fileAccessor in files) { if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath)) { fileAccessor.Dispose(); continue; } if (TryUnfold(fileAccessor, out chainedResourceAccesor)) { IFileSystemResourceAccessor chainedFsra = chainedResourceAccesor as IFileSystemResourceAccessor; if (chainedFsra != null) { result.Add(chainedFsra); } else { chainedResourceAccesor.Dispose(); } } else { fileAccessor.Dispose(); } } } return(result); } // Try to unfold simple resource IResourceAccessor dra = directoryAccessor.Clone(); try { if (TryUnfold(dra, out chainedResourceAccesor)) { IFileSystemResourceAccessor chainedFsra = chainedResourceAccesor as IFileSystemResourceAccessor; if (chainedFsra != null) { return(new List <IFileSystemResourceAccessor>(new IFileSystemResourceAccessor[] { chainedFsra })); } chainedResourceAccesor.Dispose(); } else { dra.Dispose(); } } catch { dra.Dispose(); throw; } return(null); }