Beispiel #1
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.IsFile)
        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;
    }
Beispiel #2
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            string fileName = mediaItemAccessor.ResourceName;

            if (!HasImageExtension(fileName))
            {
                return(false);
            }

            MediaItemAspect mediaAspect          = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
            MediaItemAspect imageAspect          = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata);
            MediaItemAspect thumbnailSmallAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailSmallAspect.Metadata);
            MediaItemAspect thumbnailLargeAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ThumbnailLargeAspect.Metadata);

            try
            {
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    return(false);
                }
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                // Open a stream for media item to detect mimeType.
                using (Stream mediaStream = fsra.OpenRead())
                {
                    string mimeType = MimeTypeDetector.GetMimeType(mediaStream);
                    if (mimeType != null)
                    {
                        mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, mimeType);
                    }
                }
                // Extract EXIF information from media item.
                using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra))
                {
                    mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName));
                    mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, exif.OriginalDate != DateTime.MinValue ? exif.OriginalDate : fsra.LastChanged);
                    mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(exif.ImageDescription));

                    if (exif.PixXDim.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_WIDTH, (int)exif.PixXDim);
                    }
                    if (exif.PixYDim.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_HEIGHT, (int)exif.PixYDim);
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_MAKE, StringUtils.TrimToNull(exif.EquipMake));
                    imageAspect.SetAttribute(ImageAspect.ATTR_MODEL, StringUtils.TrimToNull(exif.EquipModel));
                    if (exif.ExposureBias.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_BIAS, ((double)exif.ExposureBias).ToString());
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_EXPOSURE_TIME, exif.ExposureTime);
                    imageAspect.SetAttribute(ImageAspect.ATTR_FLASH_MODE, StringUtils.TrimToNull(exif.FlashMode));
                    if (exif.FNumber.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_FNUMBER, string.Format("F {0}", (double)exif.FNumber));
                    }
                    imageAspect.SetAttribute(ImageAspect.ATTR_ISO_SPEED, StringUtils.TrimToNull(exif.ISOSpeed));
                    imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, (Int32)(exif.OrientationType ?? 0));
                    imageAspect.SetAttribute(ImageAspect.ATTR_METERING_MODE, exif.MeteringMode.ToString());

                    if (exif.Latitude.HasValue && exif.Longitude.HasValue)
                    {
                        imageAspect.SetAttribute(ImageAspect.ATTR_LATITUDE, exif.Latitude);
                        imageAspect.SetAttribute(ImageAspect.ATTR_LONGITUDE, exif.Longitude);

                        LocationInfo locationInfo;
                        if (!forceQuickMode && GeoLocationMatcher.Instance.TryLookup(exif.Latitude.Value, exif.Longitude.Value, out locationInfo))
                        {
                            imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City);
                            imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.State);
                            imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.Country);
                        }
                    }

                    using (ILocalFsResourceAccessor lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor((IFileSystemResourceAccessor)fsra.Clone()))
                    {
                        string localFsResourcePath = lfsra.LocalFileSystemPath;
                        if (localFsResourcePath != null)
                        {
                            // In quick mode only allow thumbs taken from cache.
                            bool cachedOnly = forceQuickMode;

                            // Thumbnail extraction
                            IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                            byte[]    thumbData;
                            ImageType imageType;
                            if (generator.GetThumbnail(localFsResourcePath, 96, 96, cachedOnly, out thumbData, out imageType))
                            {
                                thumbnailSmallAspect.SetAttribute(ThumbnailSmallAspect.ATTR_THUMBNAIL, thumbData);
                            }
                            if (generator.GetThumbnail(localFsResourcePath, 256, 256, cachedOnly, out thumbData, out imageType))
                            {
                                thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                            }
                        }
                    }
                }
                return(true);
            }
            catch (Exception e)
            {
                // Only log at the info level here - And simply return false. This makes the importer know that we
                // couldn't perform our task here.
                ServiceRegistration.Get <ILogger>().Info("ImageMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
        /// <summary>
        /// Executes the given <paramref name="importJob"/>.
        /// </summary>
        /// <remarks>
        /// This method automatically terminates if it encounters that this importer worker was suspended or that the
        /// given <paramref name="importJob"/> was cancelled.
        /// </remarks>
        /// <param name="importJob">Import job to be executed. The state variables of this parameter will be updated by
        /// this method.</param>
        protected void Process(ImportJob importJob)
        {
            ImportJobState state = importJob.State;

            if (state == ImportJobState.Finished || state == ImportJobState.Cancelled || state == ImportJobState.Erroneous)
            {
                return;
            }

            // Preparation
            IMediaAccessor       mediaAccessor = ServiceRegistration.Get <IMediaAccessor>();
            IImportResultHandler resultHandler;
            IMediaBrowsing       mediaBrowsing;

            lock (_syncObj)
            {
                resultHandler = _importResultHandler;
                mediaBrowsing = _mediaBrowsingCallback;
            }
            if (mediaBrowsing == null || resultHandler == null)
            {
                // Can be the case if this importer worker was asynchronously suspended
                return;
            }
            try
            {
                try
                {
                    ICollection <IMetadataExtractor> metadataExtractors = new List <IMetadataExtractor>();
                    foreach (Guid metadataExtractorId in importJob.MetadataExtractorIds)
                    {
                        IMetadataExtractor extractor;
                        if (!mediaAccessor.LocalMetadataExtractors.TryGetValue(metadataExtractorId, out extractor))
                        {
                            continue;
                        }
                        metadataExtractors.Add(extractor);
                    }

                    // Prepare import
                    if (state == ImportJobState.Scheduled)
                    {
                        ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Starting import job '{0}'", importJob);
                        ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportStarted, importJob.BasePath);
                        IResourceAccessor ra;
                        if (!importJob.BasePath.TryCreateLocalResourceAccessor(out ra))
                        {
                            throw new ArgumentException(string.Format("Unable to access resource path '{0}'", importJob.BasePath));
                        }
                        using (ra)
                        {
                            IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
                            if (fsra != null)
                            { // Prepare complex import process
                                importJob.PendingResources.Add(new PendingImportResource(Guid.Empty, (IFileSystemResourceAccessor)fsra.Clone()));
                                importJob.State = ImportJobState.Active;
                            }
                            else
                            { // Simple resource import
                                ImportSingleFile(importJob, ra, metadataExtractors, mediaBrowsing, resultHandler, mediaAccessor);
                                lock (importJob.SyncObj)
                                    if (importJob.State == ImportJobState.Active)
                                    {
                                        importJob.State = ImportJobState.Finished;
                                    }
                                return;
                            }
                        }
                    }
                    else
                    {
                        ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Resuming import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);
                    }

                    // Actual import process
                    while (importJob.HasPendingResources)
                    {
                        Thread.Sleep(0);
                        CheckImportStillRunning(importJob.State);
                        PendingImportResource pendingImportResource;
                        lock (importJob.SyncObj)
                            pendingImportResource = importJob.PendingResources.FirstOrDefault();
                        if (pendingImportResource.IsValid)
                        {
                            IFileSystemResourceAccessor fsra = pendingImportResource.ResourceAccessor;
                            int    numPending    = importJob.PendingResources.Count;
                            string moreResources = numPending > 1 ? string.Format(" ({0} more resources pending)", numPending) : string.Empty;
                            ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Importing '{0}'{1}", fsra.ResourcePathName, moreResources);
                            if (fsra.IsFile && fsra.Exists)
                            {
                                ImportResource(importJob, fsra, pendingImportResource.ParentDirectory, metadataExtractors, resultHandler, mediaAccessor);
                            }
                            else if (!fsra.IsFile)
                            {
                                CheckImportStillRunning(importJob.State);
                                Guid?currentDirectoryId = ImportDirectory(importJob, pendingImportResource.ParentDirectory, fsra, metadataExtractors,
                                                                          mediaBrowsing, resultHandler, mediaAccessor);
                                CheckImportStillRunning(importJob.State);
                                if (currentDirectoryId.HasValue && importJob.IncludeSubDirectories)
                                {
                                    // Add subdirectories in front of work queue
                                    lock (importJob.SyncObj)
                                    {
                                        ICollection <IFileSystemResourceAccessor> directories = FileSystemResourceNavigator.GetChildDirectories(fsra, false);
                                        if (directories != null)
                                        {
                                            foreach (IFileSystemResourceAccessor childDirectory in directories)
                                            {
                                                importJob.PendingResources.Insert(0, new PendingImportResource(currentDirectoryId.Value, childDirectory));
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Cannot import resource '{0}': It's neither a file nor a directory", fsra.CanonicalLocalResourcePath.Serialize());
                            }
                        }
                        lock (importJob.SyncObj)
                            importJob.PendingResources.Remove(pendingImportResource);
                        pendingImportResource.Dispose();
                    }
                    lock (importJob.SyncObj)
                        if (importJob.State == ImportJobState.Active)
                        {
                            importJob.State = ImportJobState.Finished;
                        }
                    ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Finished import job '{0}'", importJob);
                    ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
                }
                catch (Exception e)
                {
                    CheckSuspended(e); // Throw ImportAbortException if suspended - will skip warning and tagging job as erroneous
                    ServiceRegistration.Get <ILogger>().Warn("ImporterWorker: Problem processing '{0}'", e, importJob);
                    ImporterWorkerMessaging.SendImportMessage(ImporterWorkerMessaging.MessageType.ImportCompleted, importJob.BasePath);
                    importJob.State = ImportJobState.Erroneous;
                }
            }
            catch (ImportSuspendedException)
            {
                ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Suspending import job '{0}' ({1} items pending - will be continued next time)", importJob, importJob.PendingResources.Count);
            }
            catch (ImportAbortException)
            {
                ServiceRegistration.Get <ILogger>().Info("ImporterWorker: Aborting import job '{0}' ({1} items pending)", importJob, importJob.PendingResources.Count);
            }
        }
        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);

                    ILocalFsResourceAccessor disposeLfsra = null;
                    try
                    {
                        ILocalFsResourceAccessor lfsra = fsra as ILocalFsResourceAccessor;
                        if (lfsra == null && !forceQuickMode)
                        { // In case forceQuickMode, we only want local browsing
                            IFileSystemResourceAccessor localFsra = (IFileSystemResourceAccessor)fsra.Clone();
                            try
                            {
                                lfsra        = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(localFsra);
                                disposeLfsra = lfsra; // Remember to dispose the extra resource accessor instance
                            }
                            catch (Exception)
                            {
                                localFsra.Dispose();
                            }
                        }
                        if (lfsra != null)
                        {
                            string localFsPath = lfsra.LocalFileSystemPath;
                            ExtractMatroskaTags(localFsPath, extractedAspectData, forceQuickMode);
                            ExtractMp4Tags(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);
        }
Beispiel #5
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);
        }