/// <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));
        }
Beispiel #4
0
        /// <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);
        }