/// <summary>
        /// Returns all files in the given directory.
        /// </summary>
        /// <remarks>
        /// This method simply returns the files files of the given <paramref name="directoryAccessor"/>, filtered
        /// if <paramref name="showSystemResources"/> is set to <c>true</c>.
        /// </remarks>
        /// <param name="directoryAccessor">Directory resource accessor to get all files 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 accessors for all files or <c>null</c>,
        /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/>.</returns>
        public static ICollection <IFileSystemResourceAccessor> GetFiles(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources, bool showChainedDirectories = true)
        {
            IResourceMountingService    resourceMountingService = ServiceRegistration.Get <IResourceMountingService>();
            IFileSystemResourceAccessor chainedResourceAccesor; // Needed in multiple source locations, that's why we declare it here
            ICollection <IFileSystemResourceAccessor> result = new List <IFileSystemResourceAccessor>();

            foreach (IFileSystemResourceAccessor fileAccessor in directoryAccessor.GetFiles())
            {
                if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath))
                {
                    fileAccessor.Dispose();
                    continue;
                }
                // We try to chain up chained resource providers
                if (!showChainedDirectories && TryUnfold(fileAccessor, out chainedResourceAccesor))
                {
                    if (chainedResourceAccesor.IsFile)
                    {
                        result.Add(chainedResourceAccesor);
                    }
                    else
                    {
                        chainedResourceAccesor.Dispose();
                    }
                    fileAccessor.Dispose();
                }
                else
                {
                    result.Add(fileAccessor);
                }
            }
            return(result);
        }
 /// <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;
 }
Beispiel #3
0
        /// <summary>
        /// Returns all files in the given directory.
        /// </summary>
        /// <remarks>
        /// This method simply returns the files files of the given <paramref name="directoryAccessor"/>, filtered
        /// if <paramref name="showSystemResources"/> is set to <c>true</c>.
        /// </remarks>
        /// <param name="directoryAccessor">Directory resource accessor to get all files 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 accessors for all files or <c>null</c>,
        /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/>.</returns>
        public static ICollection <IFileSystemResourceAccessor> GetFiles(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources)
        {
            IResourceMountingService resourceMountingService = ServiceRegistration.Get <IResourceMountingService>();
            ICollection <IFileSystemResourceAccessor> result = new List <IFileSystemResourceAccessor>();

            foreach (IFileSystemResourceAccessor fileAccessor in directoryAccessor.GetFiles())
            {
                if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath))
                {
                    fileAccessor.Dispose();
                    continue;
                }
                result.Add(fileAccessor);
            }
            return(result);
        }
Beispiel #4
0
        private List <ResourcePath> GetPotentialFanArtFiles(IFileSystemResourceAccessor directoryAccessor)
        {
            var result = new List <ResourcePath>();

            if (directoryAccessor.IsFile)
            {
                return(result);
            }
            foreach (var file in directoryAccessor.GetFiles())
            {
                using (file)
                {
                    var path = file.CanonicalLocalResourcePath;
                    if (IMG_EXTENSIONS.Contains(ResourcePathHelper.GetExtension(path.ToString())))
                    {
                        result.Add(path);
                    }
                }
            }
            return(result);
        }
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            try
            {
                VideoResult result = null;
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (fsra != null && fsra.IsDirectory && fsra.ResourceExists("VIDEO_TS"))
                {
                    IFileSystemResourceAccessor fsraVideoTs = fsra.GetResource("VIDEO_TS");
                    if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO"))
                    {
                        // Video DVD
                        using (MediaInfoWrapper videoTsInfo = ReadMediaInfo(fsraVideoTs.GetResource("VIDEO_TS.IFO")))
                        {
                            if (!videoTsInfo.IsValid || videoTsInfo.GetVideoCount() == 0)
                            {
                                return(false); // Invalid video_ts.ifo file
                            }
                            result = VideoResult.CreateDVDInfo(fsra.ResourceName, videoTsInfo);
                        }
                        // Iterate over all video files; MediaInfo finds different audio/video metadata for each .ifo file
                        ICollection <IFileSystemResourceAccessor> files = fsraVideoTs.GetFiles();
                        if (files != null)
                        {
                            foreach (IFileSystemResourceAccessor file in files)
                            {
                                string lowerPath = (file.ResourcePathName ?? string.Empty).ToLowerInvariant();
                                if (!lowerPath.EndsWith(".ifo") || lowerPath.EndsWith("video_ts.ifo"))
                                {
                                    continue;
                                }
                                using (MediaInfoWrapper mediaInfo = ReadMediaInfo(file))
                                {
                                    // Before we start evaluating the file, check if it is a video at all
                                    if (mediaInfo.IsValid && mediaInfo.GetVideoCount() == 0)
                                    {
                                        continue;
                                    }
                                    result.AddMediaInfo(mediaInfo);
                                }
                            }
                        }
                    }
                }
                else if (mediaItemAccessor.IsFile)
                {
                    string filePath = mediaItemAccessor.ResourcePathName;
                    if (!HasVideoExtension(filePath))
                    {
                        return(false);
                    }
                    using (MediaInfoWrapper fileInfo = ReadMediaInfo(mediaItemAccessor))
                    {
                        // Before we start evaluating the file, check if it is a video at all
                        if (!fileInfo.IsValid || (fileInfo.GetVideoCount() == 0 && !IsWorkaroundRequired(filePath)))
                        {
                            return(false);
                        }

                        string mediaTitle = DosPathHelper.GetFileNameWithoutExtension(mediaItemAccessor.ResourceName);
                        result = VideoResult.CreateFileInfo(mediaTitle, fileInfo);
                    }
                    using (Stream stream = mediaItemAccessor.OpenRead())
                        result.MimeType = MimeTypeDetector.GetMimeType(stream);
                }
                if (result != null)
                {
                    result.UpdateMetadata(extractedAspectData);

                    ILocalFsResourceAccessor disposeLfsra = null;
                    try
                    {
                        ILocalFsResourceAccessor lfsra = mediaItemAccessor as ILocalFsResourceAccessor;
                        if (lfsra == null && !forceQuickMode)
                        { // In case forceQuickMode, we only want local browsing
                            IResourceAccessor ra = mediaItemAccessor.Clone();
                            try
                            {
                                lfsra        = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra);
                                disposeLfsra = lfsra; // Remember to dispose the extra resource accessor instance
                            }
                            catch (Exception)
                            {
                                ra.Dispose();
                            }
                        }
                        if (lfsra != null)
                        {
                            string localFsPath = lfsra.LocalFileSystemPath;
                            ExtractMatroskaTags(localFsPath, extractedAspectData, forceQuickMode);
                            ExtractThumbnailData(localFsPath, extractedAspectData, forceQuickMode);
                        }
                    }
                    finally
                    {
                        if (disposeLfsra != null)
                        {
                            disposeLfsra.Dispose();
                        }
                    }
                    return(true);
                }
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This lets the caller know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
 /// <summary>
 /// Returns all files in the given directory.
 /// </summary>
 /// <remarks>
 /// This method simply returns the files files of the given <paramref name="directoryAccessor"/>, filtered
 /// if <paramref name="showSystemResources"/> is set to <c>true</c>.
 /// </remarks>
 /// <param name="directoryAccessor">Directory resource accessor to get all files 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 accessors for all files or <c>null</c>,
 /// if the given <paramref name="directoryAccessor"/> is not a <see cref="IFileSystemResourceAccessor"/>.</returns>
 public static ICollection<IFileSystemResourceAccessor> GetFiles(IFileSystemResourceAccessor directoryAccessor, bool showSystemResources)
 {
   IResourceMountingService resourceMountingService = ServiceRegistration.Get<IResourceMountingService>();
   ICollection<IFileSystemResourceAccessor> result = new List<IFileSystemResourceAccessor>();
   foreach (IFileSystemResourceAccessor fileAccessor in directoryAccessor.GetFiles())
   {
     if (!showSystemResources && resourceMountingService.IsVirtualResource(fileAccessor.CanonicalLocalResourcePath))
     {
       fileAccessor.Dispose();
       continue;
     }
     result.Add(fileAccessor);
   }
   return result;
 }
        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 a list of ResourcePaths to all potential FanArt files in a given directory
 /// </summary>
 /// <param name="directoryAccessor">ResourceAccessor pointing to the directory where FanArt files should be searched</param>
 /// <returns>List of ResourcePaths to potential FanArt files</returns>
 private List<ResourcePath> GetPotentialFanArtFiles(IFileSystemResourceAccessor directoryAccessor)
 {
   var result = new List<ResourcePath>();
   if(directoryAccessor.IsFile)
     return result;
   foreach (var file in directoryAccessor.GetFiles())
     using (file)
     {
       var path = file.CanonicalLocalResourcePath;
       if(EXTENSIONS.Contains(ResourcePathHelper.GetExtension(path.ToString())))
         result.Add(path);
     }
   return result;
 }
Beispiel #9
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);
        }
Beispiel #10
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            try
            {
                VideoResult result = null;
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (fsra == null)
                {
                    return(false);
                }
                if (!fsra.IsFile && fsra.ResourceExists("VIDEO_TS"))
                {
                    IFileSystemResourceAccessor fsraVideoTs = fsra.GetResource("VIDEO_TS");
                    if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO"))
                    {
                        // Video DVD
                        using (MediaInfoWrapper videoTsInfo = ReadMediaInfo(fsraVideoTs.GetResource("VIDEO_TS.IFO")))
                        {
                            if (!videoTsInfo.IsValid || videoTsInfo.GetVideoCount() == 0)
                            {
                                return(false); // Invalid video_ts.ifo file
                            }
                            result = VideoResult.CreateDVDInfo(fsra.ResourceName, videoTsInfo);
                        }
                        // Iterate over all video files; MediaInfo finds different audio/video metadata for each .ifo file
                        ICollection <IFileSystemResourceAccessor> files = fsraVideoTs.GetFiles();
                        if (files != null)
                        {
                            foreach (IFileSystemResourceAccessor file in files)
                            {
                                string lowerPath = (file.ResourcePathName ?? string.Empty).ToLowerInvariant();
                                if (!lowerPath.EndsWith(".ifo") || lowerPath.EndsWith("video_ts.ifo"))
                                {
                                    continue;
                                }
                                using (MediaInfoWrapper mediaInfo = ReadMediaInfo(file))
                                {
                                    // Before we start evaluating the file, check if it is a video at all
                                    if (mediaInfo.IsValid && mediaInfo.GetVideoCount() == 0)
                                    {
                                        continue;
                                    }
                                    result.AddMediaInfo(mediaInfo);
                                }
                            }
                        }
                    }
                }
                else if (fsra.IsFile)
                {
                    string filePath = fsra.ResourcePathName;
                    if (!HasVideoExtension(filePath))
                    {
                        return(false);
                    }
                    using (MediaInfoWrapper fileInfo = ReadMediaInfo(fsra))
                    {
                        // Before we start evaluating the file, check if it is a video at all
                        if (!fileInfo.IsValid || (fileInfo.GetVideoCount() == 0 && !IsWorkaroundRequired(filePath)))
                        {
                            return(false);
                        }

                        string mediaTitle = DosPathHelper.GetFileNameWithoutExtension(fsra.ResourceName);
                        result = VideoResult.CreateFileInfo(mediaTitle, fileInfo);
                    }
                    using (Stream stream = fsra.OpenRead())
                        result.MimeType = MimeTypeDetector.GetMimeType(stream, DEFAULT_MIMETYPE);
                }
                if (result != null)
                {
                    result.UpdateMetadata(extractedAspectData);

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                    {
                        ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor;
                        if (lfsra != null)
                        {
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, lfsra.Size);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, lfsra.LastChanged);
                            ExtractMatroskaTags(lfsra, extractedAspectData, forceQuickMode);
                            ExtractMp4Tags(lfsra, extractedAspectData, forceQuickMode);
                            ExtractThumbnailData(lfsra, extractedAspectData, forceQuickMode);
                        }
                        return(true);
                    }
                }
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This lets the caller know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("VideoMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
        /// <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);
        }
Beispiel #12
0
        /// <summary>
        /// Tries to read a valid IMDB id from additional .nfo or .txt files.
        /// </summary>
        /// <param name="fsra">FileSystemResourceAccessor</param>
        /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param>
        /// <returns>true if matched</returns>
        public static bool TryMatchImdbId(IFileSystemResourceAccessor fsra, out string imdbId)
        {
            imdbId = null;
            if (fsra == null)
            {
                return(false);
            }

            // First try to find a nfo file that has the same name as our main movie.
            if (fsra.IsFile)
            {
                foreach (string extension in NFO_EXTENSIONS)
                {
                    string metaFilePath = ResourcePathHelper.ChangeExtension(fsra.CanonicalLocalResourcePath.ToString(), extension);
                    if (TryRead(metaFilePath, out imdbId))
                    {
                        return(true);
                    }
                }
            }

            // Prepare a list of paths to check: for chained resource path we will also check relative parent paths (like for DVD-ISO files)
            List <string> pathsToCheck = new List <string> {
                fsra.CanonicalLocalResourcePath.ToString()
            };

            if (fsra.CanonicalLocalResourcePath.PathSegments.Count > 1)
            {
                string canocialPath = fsra.CanonicalLocalResourcePath.ToString();
                pathsToCheck.Add(canocialPath.Substring(0, canocialPath.LastIndexOf('>')));
            }

            // Then test for special named files, like "movie.nfo"
            foreach (string path in pathsToCheck)
            {
                foreach (string fileName in NFO_FILENAMES)
                {
                    string metaFilePath = ResourcePathHelper.GetDirectoryName(path);
                    metaFilePath = ResourcePathHelper.Combine(metaFilePath, fileName);
                    if (TryRead(metaFilePath, out imdbId))
                    {
                        return(true);
                    }
                }
            }

            // Now check siblings of movie for any IMDB id containing filename.
            IFileSystemResourceAccessor directoryFsra = null;

            if (fsra.IsDirectory)
            {
                directoryFsra = fsra.Clone() as IFileSystemResourceAccessor;
            }
            if (fsra.IsFile)
            {
                directoryFsra = GetContainingDirectory(fsra);
            }

            if (directoryFsra == null)
            {
                return(false);
            }

            using (directoryFsra)
                foreach (IFileSystemResourceAccessor file in directoryFsra.GetFiles())
                {
                    using (file)
                        if (ImdbIdMatcher.TryMatchImdbId(file.ResourceName, out imdbId))
                        {
                            return(true);
                        }
                }

            return(false);
        }
        public async Task <MetadataContainer> ParseMediaItemAsync(MediaItem media, int?editionId = null, bool cache = true)
        {
            try
            {
                if (media.IsStub)
                {
                    return(null);
                }

                string            category = null;
                MetadataContainer info     = null;

                //Check for live items
                if (media.Aspects.ContainsKey(AudioAspect.ASPECT_ID))
                {
                    category = AUDIO_CATEGORY;
                    if (media.IsLiveRadioItem() && media is LiveTvMediaItem ltmi)
                    {
                        info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false);

                        if (info != null)
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Live = true;
                            info.Metadata[Editions.DEFAULT_EDITION].Size = 0;
                        }
                        return(info);
                    }
                }
                else if (media.Aspects.ContainsKey(VideoAspect.ASPECT_ID))
                {
                    category = VIDEO_CATEGORY;
                    if (media.IsLiveTvItem() && media is LiveTvMediaItem ltmi)
                    {
                        info = await ParseSlimTvItemAsync(ltmi).ConfigureAwait(false);

                        if (info != null)
                        {
                            info.Metadata[Editions.DEFAULT_EDITION].Live = true;
                            info.Metadata[Editions.DEFAULT_EDITION].Size = 0;
                        }
                        return(info);
                    }
                }
                else if (media.Aspects.ContainsKey(ImageAspect.ASPECT_ID))
                {
                    category = IMAGE_CATEGORY;
                }

                info = await LoadAnalysisAsync(media, category, media.MediaItemId);

                if (info != null)
                {
                    return(info);
                }

                IList <MultipleMediaItemAspect> providerAspects;
                if (!MediaItemAspect.TryGetAspects(media.Aspects, ProviderResourceAspect.Metadata, out providerAspects))
                {
                    return(null);
                }

                IDictionary <int, ResourceLocator> resources = null;
                if (media.HasEditions)
                {
                    IEnumerable <int> praIdxs = null;
                    if (editionId.HasValue)
                    {
                        praIdxs = media.Editions.First(e => e.Key == editionId.Value).Value.PrimaryResourceIndexes;
                    }
                    else
                    {
                        praIdxs = media.Editions.SelectMany(e => e.Value.PrimaryResourceIndexes).Distinct();
                    }

                    resources = providerAspects.Where(pra => praIdxs.Contains(pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX))).
                                ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH))));
                }
                else
                {
                    resources = providerAspects.Where(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY).
                                ToDictionary(pra => pra.GetAttributeValue <int>(ProviderResourceAspect.ATTR_RESOURCE_INDEX), pra => new ResourceLocator(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_SYSTEM_ID), ResourcePath.Deserialize(pra.GetAttributeValue <string>(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH))));
                }

                //Process media resources
                Dictionary <int, Dictionary <int, IResourceAccessor> > editions = new Dictionary <int, Dictionary <int, IResourceAccessor> >();
                foreach (var res in resources)
                {
                    int edition = Editions.DEFAULT_EDITION;
                    if (media.HasEditions)
                    {
                        edition = media.Editions.FirstOrDefault(e => e.Value.PrimaryResourceIndexes.Contains(res.Key)).Value.SetNo;
                    }

                    if (!editions.ContainsKey(edition))
                    {
                        editions.Add(edition, new Dictionary <int, IResourceAccessor>());
                    }
                    IResourceAccessor mia = res.Value.CreateAccessor();

                    if (mia is IFileSystemResourceAccessor fileRes && !fileRes.IsFile)
                    {
                        if (fileRes.ResourceExists("VIDEO_TS"))
                        {
                            using (IFileSystemResourceAccessor fsraVideoTs = fileRes.GetResource("VIDEO_TS"))
                            {
                                if (fsraVideoTs != null && fsraVideoTs.ResourceExists("VIDEO_TS.IFO"))
                                {
                                    //Find all titles and add each of them
                                    var titles = GetDvdTitleFiles(fsraVideoTs);
                                    foreach (var title in titles)
                                    {
                                        int fileNo = 0;
                                        foreach (var file in title.Value)
                                        {
                                            fileNo++;
                                            int titleKey = MetadataContainer.GetDvdResource(res.Key, title.Key, fileNo);
                                            editions[edition].Add(titleKey, file);
                                        }
                                    }
                                }
                            }
                        }
                        else if (fileRes.ResourceExists("BDMV"))
                        {
                            using (IFileSystemResourceAccessor fsraBDMV = fileRes.GetResource("BDMV"))
                            {
                                if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv") && fsraBDMV.ResourceExists("STREAM"))
                                {
                                    using (IFileSystemResourceAccessor fsraStream = fsraBDMV.GetResource("STREAM"))
                                    {
                                        var orderedFileList = fsraStream.GetFiles().Where(f => f.ResourceName.EndsWith(".m2ts", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(f => f.Size);
                                        //Use the largest file which is probably the main stream
                                        var mainStream = orderedFileList.First();
                                        editions[edition].Add(res.Key, mainStream);
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        editions[edition].Add(res.Key, mia);
                    }
                    mia.Dispose();
                }