/// <summary>
 /// Creates a new instance of this class which is based on the given <paramref name="baseAccessor"/>.
 /// </summary>
 /// <param name="key">Key which is used for this instance.</param>
 /// <param name="baseAccessor">Resource accessor denoting a filesystem resource.</param>
 public MountingDataProxy(string key, IResourceAccessor baseAccessor)
 {
   _key = key;
   _baseAccessor = baseAccessor;
   if (!MountResource())
     throw new EnvironmentException("Cannot mount resource '{0}' to local file system", baseAccessor);
 }
    public override bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      try
      {
        IResourceAccessor metaFileAccessor;
        if (!CanExtract(mediaItemAccessor, extractedAspectData, out metaFileAccessor)) return false;

        Argus.Recording recording;
        using (metaFileAccessor)
        {
          using (Stream metaStream = ((IFileSystemResourceAccessor)metaFileAccessor).OpenRead())
            recording = (Argus.Recording)GetTagsXmlSerializer().Deserialize(metaStream);
        }

        // Handle series information
        SeriesInfo seriesInfo = GetSeriesFromTags(recording);
        if (seriesInfo.IsCompleteMatch)
        {
          if (!forceQuickMode)
            SeriesTvDbMatcher.Instance.FindAndUpdateSeries(seriesInfo);

          seriesInfo.SetMetadata(extractedAspectData);
        }
        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("ArgusRecordingSeriesMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
      }
      return false;
    }
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
   // TODO: support different ResourceAccessors for either local files (single seat) or network streams (multi seat). Current implementation always uses
   // network streams, even in single seat.
   result = SlimTvResourceAccessor.GetResourceAccessor(path);
   return result != null;
 }
 /// <summary>
 /// Constructs a <see cref="ResourceAccessorTextureImageSource"/> for the given data.
 /// </summary>
 /// <param name="resourceAccessor">The resource accessor to load the texture data from.</param>
 /// <param name="rotation">Desired rotation for the given image.</param>
 public ResourceAccessorTextureImageSource(IResourceAccessor resourceAccessor, RightAngledRotation rotation)
 {
   _key = resourceAccessor.CanonicalLocalResourcePath.Serialize();
   _resourceAccessor = resourceAccessor;
   _stream = _resourceAccessor.OpenRead();
   _rotation = rotation;
 }
Beispiel #5
0
    /// <summary>
    /// Sets the font manager up with the specified <paramref name="resourcesCollection"/>.
    /// This method will load the font defaults (family and size) and the font files from the
    /// resource collection.
    /// </summary>
    public static void Load(IResourceAccessor resourcesCollection)
    {
      Unload();
      string defaultFontFilePath = resourcesCollection.GetResourceFilePath(
          SkinResources.FONTS_DIRECTORY + Path.DirectorySeparatorChar + DEFAULT_FONT_FILE);

      XPathDocument doc = new XPathDocument(defaultFontFilePath);

      XPathNavigator nav = doc.CreateNavigator();
      nav.MoveToChild(XPathNodeType.Element);
      _defaultFontFamily = nav.GetAttribute("FontFamily", string.Empty);
      string defaultFontSize = nav.GetAttribute("FontSize", string.Empty);
      _defaultFontSize = int.Parse(defaultFontSize);

      // Iterate over font family descriptors
      foreach (string descriptorFilePath in resourcesCollection.GetResourceFilePaths(
          "^" + SkinResources.FONTS_DIRECTORY + "\\\\.*\\.desc$").Values)
      {
        doc = new XPathDocument(descriptorFilePath);
        nav = doc.CreateNavigator();
        nav.MoveToChild(XPathNodeType.Element);
        string familyName = nav.GetAttribute("Name", string.Empty);
        if (string.IsNullOrEmpty(familyName))
          throw new ArgumentException("FontManager: Failed to parse family name for font descriptor file '{0}'", descriptorFilePath);
        string ttfFile = nav.GetAttribute("Ttf", string.Empty);
        if (string.IsNullOrEmpty(ttfFile))
          throw new ArgumentException("FontManager: Failed to parse ttf name for font descriptor file '{0}'", descriptorFilePath);

        string fontFilePath = resourcesCollection.GetResourceFilePath(
            SkinResources.FONTS_DIRECTORY + Path.DirectorySeparatorChar + ttfFile);
        FontFamily family = new FontFamily(familyName, fontFilePath);
        _families[familyName] = family;
      }
    }
    public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
    {
      result = null;
      if (!IsResource(path))
        return false;

      result = new RawUrlResourceAccessor(path);
      return true;
    }
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
   if (!IsResource(path))
   {
     result = null;
     return false;
   }
   result = new NetworkNeighborhoodResourceAccessor(this, path);
   return true;
 }
 public void Dispose()
 {
   if (_baseAccessor == null)
     // Already disposed
     return;
   if (!UnmountResource())
     // The ownership was transferred to the resource mounting service, so if unmounting was succesful, we must not dispose our base accessor
     _baseAccessor.Dispose();
   _baseAccessor = null;
 }
Beispiel #9
0
 public static void AddSourceFilterOverride(Action fallbackAction, IResourceAccessor resourceAccessor, IGraphBuilder graphBuilder)
 {
   string sourceFilterName = GetSourceFilterName(resourceAccessor.ResourcePathName);
   if (string.IsNullOrEmpty(sourceFilterName))
   {
     fallbackAction();
   }
   else
   {
     AddStreamSourceFilter(sourceFilterName, resourceAccessor, graphBuilder);
   }
 }
 public ZipResourceProxy(string key, IResourceAccessor zipFileAccessor)
 {
   _key = key;
   _zipFileResourceAccessor = zipFileAccessor;
   _zipFileStream = _zipFileResourceAccessor.OpenRead(); // Not sure if the ZipFile closes the stream appropriately, so we keep a reference to it
   try
   {
     _zipFile = new ZipFile(_zipFileStream);
   }
   catch
   {
     _zipFileStream.Dispose();
     throw;
   }
 }
 public virtual void Dispose()
 {
   foreach (FileHandle handle in _fileHandles)
     handle.Cleanup();
   if (_resourceAccessor != null)
     try
     {
       _resourceAccessor.Dispose();
     }
     catch (Exception e)
     {
       ServiceRegistration.Get<ILogger>().Warn("Dokan virtual filesystem resource: Error disposing resource accessor '{0}'", e, _resourceAccessor);
     }
   _resourceAccessor = null;
 }
    public IsoResourceProxy(string key, IResourceAccessor isoFileResourceAccessor)
    {
      _key = key;
      _isoFileResourceAccessor = isoFileResourceAccessor;

      _underlayingStream = _isoFileResourceAccessor.OpenRead();
      try
      {
        _diskFileSystem = GetFileSystem(_underlayingStream);
      }
      catch
      {
        _underlayingStream.Dispose();
        throw;
      }
    }
 public static bool ConnectFile(string nativeSystemId, ResourcePath nativeResourcePath, out IResourceAccessor result)
 {
   IRemoteResourceInformationService rris = ServiceRegistration.Get<IRemoteResourceInformationService>();
   result = null;
   bool isFileSystemResource;
   bool isFile;
   string resourcePathName;
   string resourceName;
   DateTime lastChanged;
   long size;
   if (!rris.GetResourceInformation(nativeSystemId, nativeResourcePath,
       out isFileSystemResource, out isFile, out resourcePathName, out resourceName, out lastChanged, out size) ||
           !isFile)
     return false;
   result = new RemoteFileResourceAccessor(nativeSystemId, nativeResourcePath, resourcePathName, resourceName, lastChanged, size);
   return true;
 }
    /// <summary>
    /// Creates a new <see cref="LocalFsResourceAccessor"/> instance. The given <paramref name="mediaItemAccessor"/> will be either directly used or
    /// given over to the <see cref="StreamedResourceToLocalFsAccessBridge"/>. The caller must call <see cref="Dispose"/> on the created <see cref="LocalFsResourceAccessorHelper"/>
    /// instance but must not dispose the given <paramref name="mediaItemAccessor"/>.
    /// </summary>
    /// <param name="mediaItemAccessor">IResourceAccessor.</param>
    public LocalFsResourceAccessorHelper(IResourceAccessor mediaItemAccessor)
    {
      _localFsra = mediaItemAccessor as ILocalFsResourceAccessor;
      _disposeLfsra = null;
      if (_localFsra != null)
        return;

      IFileSystemResourceAccessor localFsra = (IFileSystemResourceAccessor) mediaItemAccessor.Clone();
      try
      {
        _localFsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(localFsra);
        _disposeLfsra = _localFsra;
      }
      catch (Exception)
      {
        localFsra.Dispose();
        throw;
      }
    }
 public void Dispose()
 {
   foreach (string tempFilePath in _tempFilePaths.Values)
     try
     {
       File.Delete(tempFilePath);
     }
     catch (Exception e)
     {
       ServiceRegistration.Get<ILogger>().Warn("ZipResourceProxy: Unable to delete temp file '{0}'", e, tempFilePath);
     }
   _tempFilePaths.Clear();
   CloseZipFile();
   if (_zipFileResourceAccessor != null)
   {
     _zipFileResourceAccessor.Dispose();
     _zipFileResourceAccessor= null;
   }
 }
Beispiel #16
0
    public static void AddStreamSourceFilter(string sourceFilterName, IResourceAccessor resourceAccessor, IGraphBuilder graphBuilder)
    {
      IBaseFilter sourceFilter = null;
      try
      {
        if (sourceFilterName == Utils.FilterName)
        {
          var filterPath = FileUtils.BuildAssemblyRelativePath(@"MPUrlSourceSplitter\MPUrlSourceSplitter.ax");
          sourceFilter = FilterLoader.LoadFilterFromDll(filterPath, new Guid(Utils.FilterCLSID));
          if (sourceFilter != null)
          {
            graphBuilder.AddFilter(sourceFilter, Utils.FilterName);
          }
        }
        else
        {
          sourceFilter = FilterGraphTools.AddFilterByName(graphBuilder, FilterCategory.LegacyAmFilterCategory, sourceFilterName);
        }

        if (sourceFilter == null)
          throw new UPnPRendererExceptions(string.Format("Could not create instance of source filter: '{0}'", sourceFilterName));

        string url = resourceAccessor.ResourcePathName;

        var filterStateEx = sourceFilter as OnlineVideos.MPUrlSourceFilter.IFilterStateEx;
        if (filterStateEx != null)
          LoadAndWaitForMPUrlSourceFilter(url, filterStateEx);
        else
        {
          var fileSourceFilter = sourceFilter as IFileSourceFilter;
          if (fileSourceFilter != null)
            Marshal.ThrowExceptionForHR(fileSourceFilter.Load(resourceAccessor.ResourcePathName, null));
          else
            throw new UPnPRendererExceptions(string.Format("'{0}' does not implement IFileSourceFilter", sourceFilterName));
        }

        FilterGraphTools.RenderOutputPins(graphBuilder, sourceFilter);
      }
      finally
      {
        FilterGraphTools.TryRelease(ref sourceFilter);
      }
    }
    /// <summary>
    /// Creates an <see cref="IInputSource"/> object for a given mediaitem.
    /// </summary>
    /// <param name="resourceLocator">Locator instance to the media item to create the input source for.</param>
    /// <param name="mimeType">Mime type of the media item, if present. May be <c>null</c>.</param>
    /// <returns>Input source object for the given <paramref name="resourceLocator"/> or <c>null</c>, if no input source
    /// could be created.</returns>
    public IInputSource CreateInputSource(IResourceLocator resourceLocator, string mimeType)
    {
      if (!CanPlay(resourceLocator, mimeType))
        return null;
      IInputSource result;
      _accessor = resourceLocator.CreateAccessor();

      AudioCDResourceAccessor acdra = _accessor as AudioCDResourceAccessor;
      if (acdra != null)
        result = BassCDTrackInputSource.Create(acdra.Drive, acdra.TrackNo);
      else
      {
        string filePath = _accessor.ResourcePathName;
        // Network streams
        INetworkResourceAccessor netra = _accessor as INetworkResourceAccessor;
        if (netra != null)
        {
          result = BassWebStreamInputSource.Create(netra.URL);
        }
        // CDDA
        else if (URLUtils.IsCDDA(filePath))
        {
          ILocalFsResourceAccessor lfra = _accessor as ILocalFsResourceAccessor;
          if (lfra == null)
            return null;
          using (lfra.EnsureLocalFileSystemAccess())
            result = BassFsCDTrackInputSource.Create(lfra.LocalFileSystemPath);
        }
        else
        {
          // Filesystem resources
          IFileSystemResourceAccessor fsra = _accessor as IFileSystemResourceAccessor;
          if (fsra == null)
            return null;
          if (URLUtils.IsMODFile(filePath))
            result = BassMODFileInputSource.Create(fsra);
          else
            result = BassAudioFileInputSource.Create(fsra);
        }
      }
      Log.Debug("InputSourceFactory: Creating input source for media resource '{0}' of type '{1}'", _accessor, result.GetType());
      return result;
    }
Beispiel #18
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (fsra == null || !mediaItemAccessor.IsFile)
                {
                    return(false);
                }

                string filePath       = mediaItemAccessor.CanonicalLocalResourcePath.ToString();
                string lowerExtension = StringUtils.TrimToEmpty(ProviderPathHelper.GetExtension(filePath)).ToLowerInvariant();
                if (lowerExtension != ".ts")
                {
                    return(false);
                }
                string            metaFilePath = ProviderPathHelper.ChangeExtension(filePath, ".xml");
                IResourceAccessor metaFileAccessor;
                if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out metaFileAccessor))
                {
                    return(false);
                }

                Tags tags;
                using (metaFileAccessor)
                {
                    using (Stream metaStream = metaFileAccessor.OpenRead())
                        tags = (Tags)GetTagsXmlSerializer().Deserialize(metaStream);
                }

                MediaItemAspect mediaAspect     = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
                MediaItemAspect videoAspect     = MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
                MediaItemAspect recordingAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, RecordingAspect.Metadata);

                // Handle series information
                SeriesInfo seriesInfo = GetSeriesFromTags(tags);
                if (seriesInfo.IsCompleteMatch)
                {
                    if (!forceQuickMode)
                    {
                        SeriesTvDbMatcher.Instance.FindAndUpdateSeries(seriesInfo);
                    }

                    seriesInfo.SetMetadata(extractedAspectData);
                }

                string value;
                if (TryGet(tags, TAG_TITLE, out value) && !string.IsNullOrEmpty(value))
                {
                    mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, value);
                }

                if (TryGet(tags, TAG_GENRE, out value))
                {
                    videoAspect.SetCollectionAttribute(VideoAspect.ATTR_GENRES, new List <String> {
                        value
                    });
                }

                if (TryGet(tags, TAG_PLOT, out value))
                {
                    videoAspect.SetAttribute(VideoAspect.ATTR_STORYPLOT, value);
                    Match yearMatch = _yearMatcher.Match(value);
                    int   guessedYear;
                    if (int.TryParse(yearMatch.Value, out guessedYear))
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(guessedYear, 1, 1));
                    }
                }

                if (TryGet(tags, TAG_CHANNEL, out value))
                {
                    recordingAspect.SetAttribute(RecordingAspect.ATTR_CHANNEL, value);
                }

                // Recording date formatted: 2011-11-04 20:55
                DateTime recordingStart;
                DateTime recordingEnd;
                if (TryGet(tags, TAG_STARTTIME, out value) && DateTime.TryParse(value, out recordingStart))
                {
                    recordingAspect.SetAttribute(RecordingAspect.ATTR_STARTTIME, recordingStart);
                }

                if (TryGet(tags, TAG_ENDTIME, out value) && DateTime.TryParse(value, out recordingEnd))
                {
                    recordingAspect.SetAttribute(RecordingAspect.ATTR_ENDTIME, recordingEnd);
                }

                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("Tve3RecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
    public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      try
      {
        if (forceQuickMode)
          return false;

        if (!(mediaItemAccessor is IFileSystemResourceAccessor))
          return false;
        using (IFileSystemResourceAccessor fsra = (IFileSystemResourceAccessor) mediaItemAccessor.Clone())
        using (ILocalFsResourceAccessor lfsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(fsra))
        {
          string localFsPath = lfsra.LocalFileSystemPath;
          return ExtractSeriesData(localFsPath, extractedAspectData);
        }
      }
      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("SeriesMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
      }
      return false;
    }
    public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      try
      {
        if (forceQuickMode)
          return false;

        if (!(mediaItemAccessor is IFileSystemResourceAccessor))
          return false;
        using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
          return ExtractThumbnail(rah.LocalFsResourceAccessor, extractedAspectData);
      }
      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>().Error("VideoThumbnailer: Exception reading resource '{0}' (Text: '{1}')", e, mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
      }
      return false;
    }
 public bool TryExtractStubItems(IResourceAccessor mediaItemAccessor, ICollection <IDictionary <Guid, IList <MediaItemAspect> > > extractedStubAspectData)
 {
     return(false);
 }
Beispiel #22
0
        private async Task <bool> TryExtractStubItemsAsync(IResourceAccessor mediaItemAccessor, ICollection <IDictionary <Guid, IList <MediaItemAspect> > > extractedStubAspectData)
        {
            // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
            // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
            // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
            var miNumber = Interlocked.Increment(ref _lastMediaItemNumber);

            try
            {
                _debugLogger.Info("[#{0}]: Start extracting stubs for resource '{1}'", miNumber, mediaItemAccessor);

                if (!IsStubResource(mediaItemAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; file does not have a supported extension", miNumber);
                    return(false);
                }

                // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
                // Otherwise it is not possible to find a stub-file in the MediaItem's directory.
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract stubs; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
                    return(false);
                }

                var fsra             = mediaItemAccessor as IFileSystemResourceAccessor;
                var seriesStubReader = new StubSeriesReader(_debugLogger, miNumber, true, _settings);
                if (fsra != null && await seriesStubReader.TryReadMetadataAsync(fsra).ConfigureAwait(false))
                {
                    SeriesStub series = seriesStubReader.GetSeriesStubs().FirstOrDefault();
                    if (series != null && series.Episodes != null && series.Episodes.Count > 0)
                    {
                        Dictionary <Guid, IList <MediaItemAspect> > extractedAspectData = new Dictionary <Guid, IList <MediaItemAspect> >();
                        string title = string.Format("{0} S{1:00}{2}", series.Title, series.Season.Value, string.Join("", series.Episodes.Select(e => "E" + e.ToString("00"))));

                        MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_TYPE, ProviderResourceAspect.TYPE_STUB);
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, fsra.CanonicalLocalResourcePath.Serialize());
                        if (IsVhs(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/unknown");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_SD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(4.0 / 3.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 720);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 576);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 2);
                        }
                        else if (IsTv(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/unknown");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 2);
                        }
                        else if (IsDvd(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/mp2t");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_SD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 25F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 720);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 576);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "MPEG-2 Video");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }
                        else if (IsBluray(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/mp4");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 24F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "AVC");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }
                        else if (IsHdDvd(mediaItemAccessor))
                        {
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "video/wvc1");

                            MultipleMediaItemAspect videoStreamAspects = MediaItemAspect.CreateAspect(extractedAspectData, VideoStreamAspect.Metadata);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_STREAM_INDEX, 0);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_TYPE, VideoStreamAspect.TYPE_HD);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_ASPECTRATIO, Convert.ToSingle(16.0 / 9.0));
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_FPS, 24F);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_WIDTH, 1920);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_HEIGHT, 1080);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEOENCODING, "VC1");
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_AUDIOSTREAMCOUNT, 1);
                            videoStreamAspects.SetAttribute(VideoStreamAspect.ATTR_VIDEO_PART, 1);

                            MultipleMediaItemAspect audioAspect = MediaItemAspect.CreateAspect(extractedAspectData, VideoAudioStreamAspect.Metadata);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_RESOURCE_INDEX, 0);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_STREAM_INDEX, 1);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOENCODING, "AC3");
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOCHANNELS, 6);
                            audioAspect.SetAttribute(VideoAudioStreamAspect.ATTR_AUDIOSAMPLERATE, 48000L);
                        }

                        SingleMediaItemAspect videoAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
                        videoAspect.SetAttribute(VideoAspect.ATTR_ISDVD, true);

                        SingleMediaItemAspect movieAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, EpisodeAspect.Metadata);
                        movieAspect.SetCollectionAttribute(EpisodeAspect.ATTR_EPISODE, series.Episodes);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SEASON, series.Season.Value);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_EPISODE_NAME, string.Format("{0} {1}", "Episode", string.Join(", ", series.Episodes)));
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SERIES_NAME, series.Title);
                        movieAspect.SetAttribute(EpisodeAspect.ATTR_SERIES_SEASON, string.Format("{0} S{1:00}", series.Title, series.Season.Value));

                        SingleMediaItemAspect stubAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, StubAspect.Metadata);
                        stubAspect.SetAttribute(StubAspect.ATTR_DISC_NAME, series.DiscName);
                        stubAspect.SetAttribute(StubAspect.ATTR_MESSAGE, series.Message);

                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, series.Title);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, BaseInfo.GetSortTitle(series.Title));
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, false);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISSTUB, true);
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, fsra.LastChanged);

                        extractedStubAspectData.Add(extractedAspectData);
                    }
                }
                else
                {
                    _debugLogger.Warn("[#{0}]: No valid metadata found in movie stub file", miNumber);
                }


                _debugLogger.Info("[#{0}]: Successfully finished extracting stubs", miNumber);
                return(true);
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Warn("StubMovieMetadataExtractor: Exception while extracting stubs for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
                _debugLogger.Error("[#{0}]: Exception while extracting stubs", e, miNumber);
                return(false);
            }
        }
Beispiel #23
0
 public Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
 {
     return(Task.FromResult(false));
 }
Beispiel #24
0
        /// <summary>
        /// Asynchronously tries to extract metadata for the given <param name="mediaItemAccessor"></param>
        /// </summary>
        /// <param name="mediaItemAccessor">Points to the resource for which we try to extract metadata</param>
        /// <param name="extractedAspectData">Dictionary of <see cref="MediaItemAspect"/>s with the extracted metadata</param>
        /// <param name="forceQuickMode">If <c>true</c>, nothing is downloaded from the internet</param>
        /// <returns><c>true</c> if metadata was found and stored into <param name="extractedAspectData"></param>, else <c>false</c></returns>
        private async Task <bool> TryExtractAudioMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
            // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
            // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
            var  miNumber = Interlocked.Increment(ref _lastMediaItemNumber);
            bool isStub   = extractedAspectData.ContainsKey(StubAspect.ASPECT_ID);

            if (!isStub)
            {
                _debugLogger.Info("[#{0}]: Ignoring non-stub track", miNumber);
                return(false);
            }
            try
            {
                _debugLogger.Info("[#{0}]: Start extracting metadata for resource '{1}' (forceQuickMode: {2})", miNumber, mediaItemAccessor, forceQuickMode);

                // We only extract metadata with this MetadataExtractor, if another MetadataExtractor that was applied before
                // has identified this MediaItem as a video and therefore added a VideoAspect.
                if (!extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract metadata; this resource is not audio", miNumber);
                    return(false);
                }

                // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
                // Otherwise it is not possible to find a nfo-file in the MediaItem's directory.
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract metadata; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
                    return(false);
                }

                // First we try to find an IFileSystemResourceAccessor pointing to the album nfo-file.
                IFileSystemResourceAccessor albumNfoFsra;
                if (TryGetAlbumNfoSResourceAccessor(miNumber, mediaItemAccessor as IFileSystemResourceAccessor, out albumNfoFsra))
                {
                    // If we found one, we (asynchronously) extract the metadata into a stub object and, if metadata was found,
                    // we store it into the MediaItemAspects.
                    var albumNfoReader = new NfoAlbumReader(_debugLogger, miNumber, forceQuickMode, isStub, _httpClient, _settings);
                    using (albumNfoFsra)
                    {
                        if (await albumNfoReader.TryReadMetadataAsync(albumNfoFsra).ConfigureAwait(false))
                        {
                            //Check reimport
                            if (extractedAspectData.ContainsKey(ReimportAspect.ASPECT_ID))
                            {
                                AlbumInfo reimport = new AlbumInfo();
                                reimport.FromMetadata(extractedAspectData);
                                if (!VerifyAlbumReimport(albumNfoReader, reimport))
                                {
                                    ServiceRegistration.Get <ILogger>().Info("NfoMovieMetadataExtractor: Nfo album metadata from resource '{0}' ignored because it does not match reimport {1}", mediaItemAccessor, reimport);
                                    return(false);
                                }
                            }

                            Stubs.AlbumStub album = albumNfoReader.GetAlbumStubs().FirstOrDefault();
                            if (album != null)
                            {
                                int trackNo = 0;
                                if (album.Tracks != null && album.Tracks.Count > 0 && MediaItemAspect.TryGetAttribute(extractedAspectData, AudioAspect.ATTR_TRACK, out trackNo))
                                {
                                    var track = album.Tracks.FirstOrDefault(t => t.TrackNumber.HasValue && trackNo == t.TrackNumber.Value);
                                    if (track != null)
                                    {
                                        TrackInfo trackInfo = new TrackInfo();
                                        string    title;
                                        string    sortTitle;

                                        title     = track.Title.Trim();
                                        sortTitle = BaseInfo.GetSortTitle(title);

                                        IEnumerable <string> artists;
                                        if (track.Artists.Count > 0)
                                        {
                                            artists = track.Artists;
                                        }

                                        IList <MultipleMediaItemAspect> providerResourceAspects;
                                        if (MediaItemAspect.TryGetAspects(extractedAspectData, ProviderResourceAspect.Metadata, out providerResourceAspects))
                                        {
                                            MultipleMediaItemAspect providerResourceAspect = providerResourceAspects.First(pa => pa.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_STUB);
                                            string mime = null;
                                            if (track.FileInfo != null && track.FileInfo.Count > 0)
                                            {
                                                mime = MimeTypeDetector.GetMimeTypeFromExtension("file" + track.FileInfo.First().Container);
                                            }
                                            if (mime != null)
                                            {
                                                providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mime);
                                            }
                                        }

                                        trackInfo.TrackName               = title;
                                        trackInfo.TrackNameSort           = sortTitle;
                                        trackInfo.Duration                = track.Duration.HasValue ? Convert.ToInt64(track.Duration.Value.TotalSeconds) : 0;
                                        trackInfo.Album                   = !string.IsNullOrEmpty(album.Title) ? album.Title.Trim() : null;
                                        trackInfo.TrackNum                = track.TrackNumber.HasValue ? track.TrackNumber.Value : 0;
                                        trackInfo.TotalTracks             = album.Tracks.Count;
                                        trackInfo.MusicBrainzId           = track.MusicBrainzId;
                                        trackInfo.IsrcId                  = track.Isrc;
                                        trackInfo.AudioDbId               = track.AudioDbId.HasValue ? track.AudioDbId.Value : 0;
                                        trackInfo.AlbumMusicBrainzId      = album.MusicBrainzAlbumId;
                                        trackInfo.AlbumMusicBrainzGroupId = album.MusicBrainzReleaseGroupId;
                                        trackInfo.ReleaseDate             = album.ReleaseDate;
                                        if (track.FileInfo != null && track.FileInfo.Count > 0 && track.FileInfo.First().AudioStreams != null && track.FileInfo.First().AudioStreams.Count > 0)
                                        {
                                            var audio = track.FileInfo.First().AudioStreams.First();
                                            trackInfo.Encoding = audio.Codec;
                                            trackInfo.BitRate  = audio.Bitrate != null?Convert.ToInt32(audio.Bitrate / 1000) : 0;

                                            trackInfo.Channels = audio.Channels != null ? audio.Channels.Value : 0;
                                        }
                                        trackInfo.Artists = new List <PersonInfo>();
                                        if (track.Artists != null && track.Artists.Count > 0)
                                        {
                                            foreach (string artistName in track.Artists)
                                            {
                                                trackInfo.Artists.Add(new PersonInfo()
                                                {
                                                    Name            = artistName.Trim(),
                                                    Occupation      = PersonAspect.OCCUPATION_ARTIST,
                                                    ParentMediaName = trackInfo.Album,
                                                    MediaName       = trackInfo.TrackName
                                                });
                                            }
                                        }
                                        trackInfo.AlbumArtists = new List <PersonInfo>();
                                        if (album.Artists != null && album.Artists.Count > 0)
                                        {
                                            foreach (string artistName in album.Artists)
                                            {
                                                trackInfo.AlbumArtists.Add(new PersonInfo()
                                                {
                                                    Name            = artistName.Trim(),
                                                    Occupation      = PersonAspect.OCCUPATION_ARTIST,
                                                    ParentMediaName = trackInfo.Album,
                                                    MediaName       = trackInfo.TrackName
                                                });
                                            }
                                        }
                                        if (album.Genres != null && album.Genres.Count > 0)
                                        {
                                            trackInfo.Genres = album.Genres.Where(s => !string.IsNullOrEmpty(s?.Trim())).Select(s => new GenreInfo {
                                                Name = s.Trim()
                                            }).ToList();
                                            IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>();
                                            foreach (var genre in trackInfo.Genres)
                                            {
                                                if (!genre.Id.HasValue && converter.GetGenreId(genre.Name, GenreCategory.Music, null, out int genreId))
                                                {
                                                    genre.Id = genreId;
                                                }
                                            }
                                        }

                                        if (album.Thumb != null && album.Thumb.Length > 0)
                                        {
                                            try
                                            {
                                                using (MemoryStream stream = new MemoryStream(album.Thumb))
                                                {
                                                    trackInfo.Thumbnail  = stream.ToArray();
                                                    trackInfo.HasChanged = true;
                                                }
                                            }
                                            // Decoding of invalid image data can fail, but main MediaItem is correct.
                                            catch { }
                                        }

                                        //Determine compilation
                                        if (trackInfo.AlbumArtists.Count > 0 &&
                                            (trackInfo.AlbumArtists[0].Name.IndexOf("Various", StringComparison.InvariantCultureIgnoreCase) >= 0 ||
                                             trackInfo.AlbumArtists[0].Name.Equals("VA", StringComparison.InvariantCultureIgnoreCase)))
                                        {
                                            trackInfo.Compilation = true;
                                        }
                                        else
                                        {
                                            //Look for itunes compilation folder
                                            var mediaItemPath = mediaItemAccessor.CanonicalLocalResourcePath;
                                            var artistMediaItemDirectoryPath = ResourcePathHelper.Combine(mediaItemPath, "../../");
                                            if (artistMediaItemDirectoryPath.FileName.IndexOf("Compilation", StringComparison.InvariantCultureIgnoreCase) >= 0)
                                            {
                                                trackInfo.Compilation = true;
                                            }
                                        }
                                        trackInfo.SetMetadata(extractedAspectData);
                                    }
                                }
                            }
                        }
                        else
                        {
                            _debugLogger.Warn("[#{0}]: No valid metadata found in album nfo-file", miNumber);
                        }
                    }
                }

                _debugLogger.Info("[#{0}]: Successfully finished extracting metadata", miNumber);
                ServiceRegistration.Get <ILogger>().Debug("NfoAudioMetadataExtractor: Assigned nfo audio metadata for resource '{0}'", mediaItemAccessor);
                return(true);
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Warn("NfoAudioMetadataExtractor: Exception while extracting metadata for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
                _debugLogger.Error("[#{0}]: Exception while extracting metadata", e, miNumber);
                return(false);
            }
        }
Beispiel #25
0
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            if (!mediaItemAccessor.IsFile)
            {
                return(false);
            }
            string fileName = mediaItemAccessor.ResourceName;

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

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

            try
            {
                File tag;
                try
                {
                    ByteVector.UseBrokenLatin1Behavior = true; // Otherwise we have problems retrieving non-latin1 chars
                    tag = File.Create(new ResourceProviderFileAbstraction(mediaItemAccessor));
                }
                catch (CorruptFileException)
                {
                    // 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("AudioMetadataExtractor: Audio file '{0}' seems to be broken", mediaItemAccessor.CanonicalLocalResourcePath);
                    return(false);
                }

                // Some file extensions like .mp4 can contain audio and video. Do not handle files with video content here.
                if (tag.Properties.VideoHeight > 0 && tag.Properties.VideoWidth > 0)
                {
                    return(false);
                }

                fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                string title;
                string artist;
                uint?  trackNo;
                GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                if (!string.IsNullOrEmpty(tag.Tag.Title))
                {
                    title = tag.Tag.Title;
                }
                IEnumerable <string> artists;
                if (tag.Tag.Performers.Length > 0)
                {
                    artists = tag.Tag.Performers;
                    if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                    {
                        artists = PatchID3v23Enumeration(artists);
                    }
                }
                else
                {
                    artists = artist == null ? null : new string[] { artist }
                };
                if (tag.Tag.Track != 0)
                {
                    trackNo = tag.Tag.Track;
                }
                mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title);
                // FIXME Albert: tag.MimeType returns taglib/mp3 for an MP3 file. This is not what we want and collides with the
                // mimetype handling in the BASS player, which expects audio/xxx.
                //mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, tag.MimeType);
                audioAspect.SetCollectionAttribute(AudioAspect.ATTR_ARTISTS, ApplyAdditionalSeparator(artists));
                audioAspect.SetAttribute(AudioAspect.ATTR_ALBUM, StringUtils.TrimToNull(tag.Tag.Album));
                IEnumerable <string> albumArtists = tag.Tag.AlbumArtists;
                if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                {
                    albumArtists = PatchID3v23Enumeration(albumArtists);
                }
                audioAspect.SetCollectionAttribute(AudioAspect.ATTR_ALBUMARTISTS, ApplyAdditionalSeparator(albumArtists));
                audioAspect.SetAttribute(AudioAspect.ATTR_BITRATE, tag.Properties.AudioBitrate);
                mediaAspect.SetAttribute(MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tag.Tag.Comment));
                IEnumerable <string> composers = tag.Tag.Composers;
                if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                {
                    composers = PatchID3v23Enumeration(composers);
                }
                audioAspect.SetCollectionAttribute(AudioAspect.ATTR_COMPOSERS, ApplyAdditionalSeparator(composers));

                audioAspect.SetAttribute(AudioAspect.ATTR_DURATION, tag.Properties.Duration.TotalSeconds);
                if (tag.Tag.Genres.Length > 0)
                {
                    IEnumerable <string> genres = tag.Tag.Genres;
                    if ((tag.TagTypes & TagTypes.Id3v2) != 0)
                    {
                        genres = PatchID3v23Enumeration(genres);
                    }
                    audioAspect.SetCollectionAttribute(AudioAspect.ATTR_GENRES, ApplyAdditionalSeparator(genres));
                }
                if (trackNo.HasValue)
                {
                    audioAspect.SetAttribute(AudioAspect.ATTR_TRACK, (int)trackNo.Value);
                }
                if (tag.Tag.TrackCount != 0)
                {
                    audioAspect.SetAttribute(AudioAspect.ATTR_NUMTRACKS, (int)tag.Tag.TrackCount);
                }
                int year = (int)tag.Tag.Year;
                if (year >= 30 && year <= 99)
                {
                    year += 1900;
                }
                if (year >= 1930 && year <= 2030)
                {
                    mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));
                }


                // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                IPicture[] pics = tag.Tag.Pictures;
                if (pics.Length > 0)
                {
                    thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, pics[0].Data.Data);
                }
                else
                {
                    // In quick mode only allow thumbs taken from cache.
                    bool cachedOnly = forceQuickMode;

                    // Thumbnail extraction
                    fileName = mediaItemAccessor.ResourcePathName;
                    IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                    byte[]    thumbData;
                    ImageType imageType;
                    if (generator.GetThumbnail(fileName, 96, 96, cachedOnly, out thumbData, out imageType))
                    {
                        thumbnailSmallAspect.SetAttribute(ThumbnailSmallAspect.ATTR_THUMBNAIL, thumbData);
                    }
                    if (generator.GetThumbnail(fileName, 256, 256, cachedOnly, out thumbData, out imageType))
                    {
                        thumbnailLargeAspect.SetAttribute(ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                    }
                }
                return(true);
            }
            catch (UnsupportedFormatException)
            {
                ServiceRegistration.Get <ILogger>().Info("AudioMetadataExtractor: Unsupported audio file '{0}'", mediaItemAccessor.CanonicalLocalResourcePath);
                return(false);
            }
            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("AudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
        /// <summary>
        /// Asynchronously creates an <see cref="NfoSeriesEpisodeReader"/> for the given <param name="mediaItemAccessor"></param>
        /// </summary>
        /// <param name="mediaItemAccessor">Points to the resource for which we try to create an NfoSeriesEpisodeReader</param>
        /// <param name="season">Season number of the episode to create an NfoSeriesEpisodeReader for</param>
        /// <param name="episode">Episode number of the episode to create an NfoSeriesEpisodeReader for</param>
        /// <returns>An NfoSeriesEpisodeReader if an nfo file was found, else <c>null</c></returns>
        protected async Task <NfoSeriesEpisodeReader> TryGetNfoSeriesEpisodeReaderAsync(IResourceAccessor mediaItemAccessor, int?season, int?episode, bool includeFanart)
        {
            // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
            // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
            // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
            var miNumber = Interlocked.Increment(ref _lastMediaItemNumber);

            try
            {
                _debugLogger.Info("[#{0}]: Start extracting metadata for resource '{1}'", miNumber, mediaItemAccessor);

                // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
                // Otherwise it is not possible to find a nfo-file in the MediaItem's directory or parent directory.
                if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                {
                    _debugLogger.Info("[#{0}]: Cannot extract metadata; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
                    return(null);
                }

                // Here we try to find an IFileSystemResourceAccessor pointing to the episode nfo-file.
                // If we don't find one, we cannot extract any metadata.
                IFileSystemResourceAccessor episodeNfoFsra;
                NfoSeriesEpisodeReader      episodeNfoReader = null;
                bool episodeDetailsFound = false;
                if (TryGetEpisodeNfoSResourceAccessor(miNumber, mediaItemAccessor as IFileSystemResourceAccessor, out episodeNfoFsra))
                {
                    episodeDetailsFound = true;
                    // Now we (asynchronously) extract the metadata into a stub object.
                    // If no metadata was found, nothing can be stored in the MediaItemAspects.
                    episodeNfoReader = new NfoSeriesEpisodeReader(_debugLogger, miNumber, false, false, _httpClient, _settings, includeFanart);
                    using (episodeNfoFsra)
                    {
                        if (!await episodeNfoReader.TryReadMetadataAsync(episodeNfoFsra).ConfigureAwait(false))
                        {
                            _debugLogger.Warn("[#{0}]: No valid metadata found in episode nfo-file", miNumber);
                            return(null);
                        }
                    }
                }

                // Then we try to find an IFileSystemResourceAccessor pointing to the series nfo-file.
                IFileSystemResourceAccessor seriesNfoFsra;
                if (TryGetSeriesNfoSResourceAccessor(miNumber, mediaItemAccessor as IFileSystemResourceAccessor, out seriesNfoFsra))
                {
                    // If we found one, we (asynchronously) extract the metadata into a stub object and, if metadata was found,
                    // we store it into the episodeNfoReader so that the latter can store metadata from series and episode level into the MediaItemAspects.
                    var seriesNfoReader = new NfoSeriesReader(_debugLogger, miNumber, false, !episodeDetailsFound, false, _httpClient, _settings, includeFanart);
                    using (seriesNfoFsra)
                    {
                        if (await seriesNfoReader.TryReadMetadataAsync(seriesNfoFsra).ConfigureAwait(false))
                        {
                            Stubs.SeriesStub series = seriesNfoReader.GetSeriesStubs().FirstOrDefault();
                            if (series != null)
                            {
                                if (!episodeDetailsFound && series.Episodes != null && season.HasValue && episode.HasValue)
                                {
                                    Stubs.SeriesEpisodeStub episodeStub = series.Episodes.FirstOrDefault(e => e.Season == season && e.Episodes != null && e.Episodes.Contains(episode.Value));
                                    episodeNfoReader = new NfoSeriesEpisodeReader(_debugLogger, miNumber, false, false, _httpClient, _settings, includeFanart);
                                    episodeNfoReader.SetEpisodeStubs(new List <Stubs.SeriesEpisodeStub>(new[] { episodeStub }));
                                }

                                if (episodeNfoReader != null)
                                {
                                    episodeNfoReader.SetSeriesStubs(new List <Stubs.SeriesStub> {
                                        series
                                    });
                                }
                            }
                            else
                            {
                                _debugLogger.Warn("[#{0}]: No valid metadata found in series nfo-file", miNumber);
                            }
                        }
                    }
                }

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

                _debugLogger.Warn("[#{0}]: No valid nfo-file found", miNumber);
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Warn("NfoSeriesMetadataExtractor: Exception while extracting metadata for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
                _debugLogger.Error("[#{0}]: Exception while extracting metadata", e, miNumber);
            }
            return(null);
        }
        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);
                            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>
        /// Sets the data of the new image to be played.
        /// </summary>
        /// <param name="locator">Resource locator of the image item.</param>
        /// <param name="mediaItemTitle">Title of the image item.</param>
        /// <param name="rotation">Rotation of the image.</param>
        /// <param name="flipX">Flipping in horizontal direction.</param>
        /// <param name="flipY">Flipping in vertical direction.</param>
        public void SetMediaItemData(IResourceLocator locator, string mediaItemTitle, RightAngledRotation rotation, bool flipX, bool flipY)
        {
            if (locator == null)
            {
                lock (_syncObj)
                {
                    _currentLocator = null;
                    return;
                }
            }

            using (IResourceAccessor ra = locator.CreateAccessor())
            {
                IFileSystemResourceAccessor fsra = ra as IFileSystemResourceAccessor;
                if (fsra == null)
                {
                    return;
                }
                using (Stream stream = fsra.OpenRead())
                {
                    string key = fsra.CanonicalLocalResourcePath.Serialize();
                    _texture = ContentManager.Instance.GetTexture(stream, key, true);
                    if (_texture == null)
                    {
                        return;
                    }
                    if (!_texture.IsAllocated)
                    {
                        _texture.Allocate();
                    }
                    if (!_texture.IsAllocated)
                    {
                        return;
                    }
                }
            }
            lock (_syncObj)
            {
                ReloadSettings();
                _state = PlayerState.Active;

                _currentLocator = locator;
                _mediaItemTitle = mediaItemTitle;
                _rotation       = rotation;
                _flipX          = flipX;
                _flipY          = flipY;
                SurfaceDescription desc = _texture.Texture.GetLevelDescription(0);
                _textureMaxUV = new SizeF(_texture.Width / (float)desc.Width, _texture.Height / (float)desc.Height);

                // Reset animation
                _animator.Initialize();

                if (_slideShowTimer != null)
                {
                    _slideShowTimer.Change(_slideShowImageDuration, TS_INFINITE);
                }
                else
                {
                    CheckTimer();
                }
                _playbackStartTime = DateTime.Now;
                if (_pauseTime.HasValue)
                {
                    _pauseTime = _playbackStartTime;
                }
            }
        }
        public Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

            if (fsra == null || !fsra.IsFile)
            {
                return(Task.FromResult(false));
            }
            if (extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID))
            {
                return(Task.FromResult(false)); //Ignore video recordings
            }
            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                return(Task.FromResult(false));
            }

            try
            {
                var extension = DosPathHelper.GetExtension(fsra.ResourceName).ToLowerInvariant();
                if (extension != ".ts")
                {
                    return(Task.FromResult(false));
                }

                using (MediaInfoWrapper mediaInfo = ReadMediaInfo(fsra))
                {
                    // Before we start evaluating the file, check if it is not a video file
                    if (mediaInfo.IsValid && (mediaInfo.GetVideoCount() != 0 || mediaInfo.GetAudioCount() == 0))
                    {
                        return(Task.FromResult(false));
                    }

                    string fileName = ProviderPathHelper.GetFileNameWithoutExtension(fsra.Path) ?? string.Empty;
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, fileName);
                    MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "slimtv/radio");

                    var audioBitrate = mediaInfo.GetAudioBitrate(0);
                    if (audioBitrate.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, (int)(audioBitrate.Value / 1000)); // We store kbit/s;
                    }
                    var audioChannels = mediaInfo.GetAudioChannels(0);
                    if (audioChannels.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_CHANNELS, audioChannels.Value);
                    }
                    var audioSampleRate = mediaInfo.GetAudioSampleRate(0);
                    if (audioSampleRate.HasValue)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_SAMPLERATE, audioSampleRate.Value);
                    }

                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_ENCODING, mediaInfo.GetAudioCodec(0));
                    // MediaInfo returns milliseconds, we need seconds
                    long?time = mediaInfo.GetPlaytime(0);
                    if (time.HasValue && time > 1000)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, time.Value / 1000);
                    }
                }
                return(Task.FromResult(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("RadioRecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
                return(Task.FromResult(false));
            }
        }
Beispiel #30
0
        internal static void ParseH264Info(IResourceAccessor res, MetadataContainer info, Dictionary <float, long> h264MaxDpbMbs, int transcoderTimeout)
        {
            if (info.Video[Editions.DEFAULT_EDITION].Codec == VideoCodec.H264)
            {
                if (res is ILocalFsResourceAccessor fileRes && !fileRes.IsFile)
                {
                    return;
                }
                //if (!(res is INetworkResourceAccessor))
                //  return;

                //TODO: Remove this debug code when error found
                string debug        = "";
                string tempFileName = Path.GetTempPath() + Guid.NewGuid() + ".bin";
                try
                {
                    byte[] data = null;
                    //string arguments = string.Format("-i \"{0}\" -frames:v 1 -c:v copy -f h264", info.Metadata.Source);
                    //if (info.Metadata.VideoContainerType != VideoContainer.Mpeg2Ts)
                    //{
                    //  arguments += " -bsf:v h264_mp4toannexb";
                    //}
                    //arguments += string.Format(" -an \"{0}\"", tempFileName);
                    //debug = arguments;

                    //ProcessExecutionResult result;
                    //lock (FFPROBE_THROTTLE_LOCK)
                    //  result = FFMpegBinary.FFMpegExecuteWithResourceAccessAsync((ILocalFsResourceAccessor)info.Metadata.Source, arguments, ProcessPriorityClass.Idle, transcoderTimeout).Result;
                    //debug = result.StandardError;
                    //if (!result.Success || !File.Exists(tempFileName))
                    //{
                    //  ServiceRegistration.Get<ILogger>().Warn("MediaAnalyzer: Failed to extract h264 annex b header information for resource: '{0}'", info.Metadata.Source);
                    //  return;
                    //}
                    //data = File.ReadAllBytes(tempFileName);

                    string arguments = string.Format("-i \"{0}\" -frames:v 1 -c:v copy -f h264", res);
                    if (info.Metadata[Editions.DEFAULT_EDITION].VideoContainerType != VideoContainer.Mpeg2Ts)
                    {
                        arguments += " -bsf:v h264_mp4toannexb";
                    }
                    arguments += " -an -";
                    data       = ProbeResource(res, arguments, transcoderTimeout);
                    if (data == null)
                    {
                        Logger.Error("MediaAnalyzer: Timed out analyzing H264 information for resource '{0}'", res);
                        return;
                    }

                    debug = "Parse binary dump";
                    H264Analyzer avcAnalyzer = new H264Analyzer();
                    if (avcAnalyzer.Parse(data) == true)
                    {
                        switch (avcAnalyzer.HeaderProfile)
                        {
                        case H264Analyzer.H264HeaderProfile.ConstrainedBaseline:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.Baseline;
                            break;

                        case H264Analyzer.H264HeaderProfile.Baseline:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.Baseline;
                            break;

                        case H264Analyzer.H264HeaderProfile.Main:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.Main;
                            break;

                        case H264Analyzer.H264HeaderProfile.Extended:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.Main;
                            break;

                        case H264Analyzer.H264HeaderProfile.High:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.High;
                            break;

                        case H264Analyzer.H264HeaderProfile.High_10:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.High10;
                            break;

                        case H264Analyzer.H264HeaderProfile.High_422:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.High422;
                            break;

                        case H264Analyzer.H264HeaderProfile.High_444:
                            info.Video[Editions.DEFAULT_EDITION].ProfileType = EncodingProfile.High444;
                            break;
                        }
                        info.Video[Editions.DEFAULT_EDITION].HeaderLevel = avcAnalyzer.HeaderLevel;
                        int refFrames = avcAnalyzer.HeaderRefFrames;

                        debug = "File parsed";
                        if (info.Video[Editions.DEFAULT_EDITION].Width > 0 && info.Video[Editions.DEFAULT_EDITION].Height > 0 && refFrames > 0 && refFrames <= 16)
                        {
                            long dpbMbs = Convert.ToInt64(((float)info.Video[Editions.DEFAULT_EDITION].Width * (float)info.Video[Editions.DEFAULT_EDITION].Height * (float)refFrames) / 256F);
                            foreach (KeyValuePair <float, long> levelDbp in h264MaxDpbMbs)
                            {
                                if (levelDbp.Value > dpbMbs)
                                {
                                    info.Video[Editions.DEFAULT_EDITION].RefLevel = levelDbp.Key;
                                    break;
                                }
                            }
                        }
                        if (info.Video[Editions.DEFAULT_EDITION].HeaderLevel == 0 && info.Video[Editions.DEFAULT_EDITION].RefLevel == 0)
                        {
                            Logger.Warn("MediaAnalyzer: Couldn't resolve H264 profile/level/reference frames for resource: '{0}'", res);
                        }
                    }
                    Logger.Debug("MediaAnalyzer: Successfully decoded H264 header: H264 profile {0}, level {1}/level {2}",
                                 info.Video[Editions.DEFAULT_EDITION].ProfileType, info.Video[Editions.DEFAULT_EDITION].HeaderLevel, info.Video[Editions.DEFAULT_EDITION].RefLevel);
                }
                catch (Exception e)
                {
                    if (Logger != null)
                    {
                        Logger.Error("MediaAnalyzer: Failed to analyze H264 information for resource '{0}':\n{1}", res, e.Message);
                        Logger.Error("MediaAnalyzer: Debug info: {0}", debug);
                    }
                }
                try
                {
                    if (File.Exists(tempFileName))
                    {
                        File.Delete(tempFileName);
                    }
                }
                catch { }
            }
        }
 internal IsoResourceProxy CreateIsoResourceProxy(string key, IResourceAccessor isoFileResourceAccessor)
 {
   IsoResourceProxy result = new IsoResourceProxy(key, isoFileResourceAccessor);
   result.Orphaned += OnIsoResourceProxyOrphaned;
   return result;
 }
Beispiel #32
0
        public override bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            // If the base AudioMDE already extracted metadata, don't try here again to avoid conflicts.
            if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID))
            {
                return(false);
            }

            ILocalFsResourceAccessor fsra = mediaItemAccessor as ILocalFsResourceAccessor;

            if (fsra == null)
            {
                return(false);
            }
            if (!fsra.IsFile)
            {
                return(false);
            }
            string fileName = fsra.ResourceName;

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

            try
            {
                TAG_INFO tags;
                using (fsra.EnsureLocalFileSystemAccess())
                    tags = BassTags.BASS_TAG_GetFromFile(fsra.LocalFileSystemPath);
                if (tags == null)
                {
                    return(false);
                }

                fileName = ProviderPathHelper.GetFileNameWithoutExtension(fileName) ?? string.Empty;
                string title;
                string artist;
                uint?  trackNo;
                GuessMetadataFromFileName(fileName, out title, out artist, out trackNo);
                if (!string.IsNullOrWhiteSpace(tags.title))
                {
                    title = tags.title;
                }
                IEnumerable <string> artists;
                if (!string.IsNullOrWhiteSpace(tags.artist))
                {
                    artists = SplitTagEnum(tags.artist);
                    artists = PatchID3v23Enumeration(artists);
                }
                else
                {
                    artists = artist == null ? null : new string[] { artist }
                };
                if (!string.IsNullOrWhiteSpace(tags.track) && tags.track != "0")
                {
                    int iTrackNo;
                    if (int.TryParse(tags.track, out iTrackNo))
                    {
                        trackNo = (uint?)iTrackNo;
                    }
                    else
                    {
                        trackNo = null;
                    }
                }

                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SIZE, fsra.Size);
                // Calling EnsureLocalFileSystemAccess not necessary; only string operation
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_MIME_TYPE, "audio/" + Path.GetExtension(fsra.LocalFileSystemPath).Substring(1));
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ARTISTS, ApplyAdditionalSeparator(artists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_ALBUM, StringUtils.TrimToNull(tags.album));
                IEnumerable <string> albumArtists = SplitTagEnum(tags.albumartist);
                albumArtists = PatchID3v23Enumeration(albumArtists);

                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_ALBUMARTISTS, ApplyAdditionalSeparator(albumArtists));
                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, tags.bitrate);
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tags.comment));
                IEnumerable <string> composers = SplitTagEnum(tags.composer);
                composers = PatchID3v23Enumeration(composers);
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_COMPOSERS, ApplyAdditionalSeparator(composers));

                MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, (long)tags.duration);

                IEnumerable <string> genres = SplitTagEnum(tags.genre);
                genres = PatchID3v23Enumeration(genres);
                MediaItemAspect.SetCollectionAttribute(extractedAspectData, AudioAspect.ATTR_GENRES, ApplyAdditionalSeparator(genres));

                if (trackNo.HasValue)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_TRACK, (int)trackNo.Value);
                }

                int year;
                if (int.TryParse(tags.year, out year))
                {
                    if (year >= 30 && year <= 99)
                    {
                        year += 1900;
                    }
                    if (year >= 1930 && year <= 2030)
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1));
                    }
                }

                // The following code gets cover art images from file (embedded) or from windows explorer cache (supports folder.jpg).
                if (tags.PictureCount > 0)
                {
                    try
                    {
                        using (Image cover = tags.PictureGetImage(0))
                            using (Image resized = ImageUtilities.ResizeImage(cover, MAX_COVER_WIDTH, MAX_COVER_HEIGHT))
                                using (MemoryStream result = new MemoryStream())
                                {
                                    resized.Save(result, ImageFormat.Jpeg);
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, result.ToArray());
                                }
                    }
                    // Decoding of invalid image data can fail, but main MediaItem is correct.
                    catch { }
                }
                else
                {
                    // In quick mode only allow thumbs taken from cache.
                    bool cachedOnly = forceQuickMode;

                    // Thumbnail extraction
                    fileName = mediaItemAccessor.ResourcePathName;
                    IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                    byte[]    thumbData;
                    ImageType imageType;
                    if (generator.GetThumbnail(fileName, cachedOnly, out thumbData, out imageType))
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, 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("BassAudioMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", fsra.CanonicalLocalResourcePath, e.Message);
            }
            return(false);
        }
Beispiel #33
0
 public ResourceProviderFileAbstraction(IResourceAccessor resourceAccessor)
 {
     _resourceAccessor = resourceAccessor;
 }
    /// <summary>
    /// Asynchronously tries to extract metadata for the given <param name="mediaItemAccessor"></param>
    /// </summary>
    /// <param name="mediaItemAccessor">Points to the resource for which we try to extract metadata</param>
    /// <param name="extractedAspectData">Dictionary of <see cref="MediaItemAspect"/>s with the extracted metadata</param>
    /// <param name="forceQuickMode">If <c>true</c>, nothing is downloaded from the internet</param>
    /// <returns><c>true</c> if metadata was found and stored into <param name="extractedAspectData"></param>, else <c>false</c></returns>
    private async Task<bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      // Get a unique number for this call to TryExtractMetadataAsync. We use this to make reading the debug log easier.
      // This MetadataExtractor is called in parallel for multiple MediaItems so that the respective debug log entries
      // for one call are not contained one after another in debug log. We therefore prepend this number before every log entry.
      var miNumber = Interlocked.Increment(ref _lastMediaItemNumber);
      try
      {
        _debugLogger.Info("[#{0}]: Start extracting metadata for resource '{1}' (forceQuickMode: {2})", miNumber, mediaItemAccessor, forceQuickMode);

        // We only extract metadata with this MetadataExtractor, if another MetadataExtractor that was applied before
        // has identified this MediaItem as a video and therefore added a VideoAspect.
        if (!extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID))
        {
          _debugLogger.Info("[#{0}]: Cannot extract metadata; this resource is not a video", miNumber);
          return false;
        }

        // This MetadataExtractor only works for MediaItems accessible by an IFileSystemResourceAccessor.
        // Otherwise it is not possible to find a nfo-file in the MediaItem's directory.
        if (!(mediaItemAccessor is IFileSystemResourceAccessor))
        {
          _debugLogger.Info("[#{0}]: Cannot extract metadata; mediaItemAccessor is not an IFileSystemResourceAccessor", miNumber);
          return false;
        }

        // Here we try to find an IFileSystemResourceAccessor pointing to the nfo-file.
        // If we don't find one, we cannot extract any metadata.
        IFileSystemResourceAccessor nfoFsra;
        if (!TryGetNfoSResourceAccessor(miNumber, mediaItemAccessor as IFileSystemResourceAccessor, out nfoFsra))
          return false;

        // Now we (asynchronously) extract the metadata into a stub object.
        // If no metadata was found, nothing can be stored in the MediaItemAspects.
        var nfoReader = new NfoMovieReader(_debugLogger, miNumber, forceQuickMode, _httpClient, _settings);
        using (nfoFsra)
        {
          if (!await nfoReader.TryReadMetadataAsync(nfoFsra).ConfigureAwait(false))
          {
            _debugLogger.Warn("[#{0}]: No valid metadata found", miNumber);
            return false;
          }
        }

        // Then we store the found metadata in the MediaItemAspects. If we only found metadata that is
        // not (yet) supported by our MediaItemAspects, this MetadataExtractor returns false.
        if (!nfoReader.TryWriteMetadata(extractedAspectData))
        {
          _debugLogger.Warn("[#{0}]: No metadata was written into MediaItemsAspects", miNumber);
          return false;
        }

        _debugLogger.Info("[#{0}]: Successfully finished extracting metadata", miNumber);
        return true;
      }
      catch (Exception e)
      {
        ServiceRegistration.Get<ILogger>().Warn("NfoMovieMetadataExtractor: Exception while extracting metadata for resource '{0}'; enable debug logging for more details.", mediaItemAccessor);
        _debugLogger.Error("[#{0}]: Exception while extracting metadata", e, miNumber);
        return false;
      }
    }
Beispiel #35
0
 public VirtualFile(string name, IResourceAccessor resourceAccessor) :
     base(name, resourceAccessor)
 {
 }
Beispiel #36
0
 protected IResourceAccessor WrapLocalFsResourceAccessor(IResourceAccessor localFsResourceAccessor)
 {
     return(new NetworkNeighborhoodResourceAccessor(_parent, localFsResourceAccessor.Path.Substring(1)));
 }
Beispiel #37
0
 public bool TryExtractStubItems(IResourceAccessor mediaItemAccessor, ICollection <IDictionary <Guid, IList <MediaItemAspect> > > extractedStubAspectData)
 {
     // The following is bad practice as it wastes one ThreadPool thread.
     // ToDo: Once the IMetadataExtractor interface is updated to support async operations, call TryExtractMetadataAsync directly
     return(TryExtractStubItemsAsync(mediaItemAccessor, extractedStubAspectData).Result);
 }
Beispiel #38
0
 public IDictionary<Guid, MediaItemAspect> ExtractMetadata(IResourceAccessor mediaItemAccessor,
     IEnumerable<IMetadataExtractor> metadataExtractors, bool forceQuickMode)
 {
   IDictionary<Guid, MediaItemAspect> result = new Dictionary<Guid, MediaItemAspect>();
   bool success = false;
   // Execute all metadata extractors in order of their priority
   foreach (IMetadataExtractor extractor in metadataExtractors.OrderBy(m => m.Metadata.Priority))
   {
     try
     {
       if (extractor.TryExtractMetadata(mediaItemAccessor, result, forceQuickMode))
         success = true;
     }
     catch (Exception e)
     {
       MetadataExtractorMetadata mem = extractor.Metadata;
       ServiceRegistration.Get<ILogger>().Error("MediaAccessor: Error extracting metadata from metadata extractor '{0}' (Id: '{1}')",
           e, mem.Name, mem.MetadataExtractorId);
       throw;
     }
   }
   return success ? result : null;
 }
    public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      try
      {
        IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
        if (fsra == null || !fsra.IsFile)
          return false;

        string title;
        if (!MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) || string.IsNullOrEmpty(title))
          return false;

        string filePath = mediaItemAccessor.CanonicalLocalResourcePath.ToString();
        string lowerExtension = StringUtils.TrimToEmpty(ProviderPathHelper.GetExtension(filePath)).ToLowerInvariant();
        if (lowerExtension != ".ts")
          return false;
        string metaFilePath = ProviderPathHelper.ChangeExtension(filePath, ".xml");
        IResourceAccessor metaFileAccessor;
        if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out metaFileAccessor))
          return false;

        Tags tags;
        using (metaFileAccessor)
        {
          using (Stream metaStream = ((IFileSystemResourceAccessor) metaFileAccessor).OpenRead())
            tags = (Tags) GetTagsXmlSerializer().Deserialize(metaStream);
        }

        // Handle series information
        SeriesInfo seriesInfo = GetSeriesFromTags(tags);
        if (seriesInfo.IsCompleteMatch)
        {
          if (!forceQuickMode)
            SeriesTvDbMatcher.Instance.FindAndUpdateSeries(seriesInfo);

          seriesInfo.SetMetadata(extractedAspectData);
        }

        string value;
        if (TryGet(tags, TAG_TITLE, out value) && !string.IsNullOrEmpty(value))
          MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, value);

        if (TryGet(tags, TAG_GENRE, out value))
          MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_GENRES, new List<String> { value });

        if (TryGet(tags, TAG_PLOT, out value))
        {
          MediaItemAspect.SetAttribute(extractedAspectData, VideoAspect.ATTR_STORYPLOT, value);
          Match yearMatch = _yearMatcher.Match(value);
          int guessedYear;
          if (int.TryParse(yearMatch.Value, out guessedYear))
            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(guessedYear, 1, 1));
        }

        if (TryGet(tags, TAG_CHANNEL, out value))
          MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_CHANNEL, value);

        // Recording date formatted: 2011-11-04 20:55
        DateTime recordingStart;
        DateTime recordingEnd;
        if (TryGet(tags, TAG_STARTTIME, out value) && DateTime.TryParse(value, out recordingStart))
          MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_STARTTIME, recordingStart);

        if (TryGet(tags, TAG_ENDTIME, out value) && DateTime.TryParse(value, out recordingEnd))
          MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_ENDTIME, recordingEnd);

        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("Tve3RecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
      }
      return false;
    }
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
   char drive;
   byte trackNo;
   if (TryExtract(path, out drive, out trackNo))
   {
     result = new AudioCDResourceAccessor(this, drive, trackNo);
     return true;
   }
   result = null;
   return false;
 }
Beispiel #41
0
        protected static bool IsChainedResourceProvider(IResourceAccessor mediaItemAccessor)
        {
            Guid providerId = mediaItemAccessor.ParentProvider.Metadata.ResourceProviderId;

            return(ServiceRegistration.Get <IMediaAccessor>().LocalChainedResourceProviders.Any(rp => rp.Metadata.ResourceProviderId == providerId));
        }
Beispiel #42
0
        public bool TryChainUp(IResourceAccessor potentialBaseResourceAccessor, string path, out IResourceAccessor resultResourceAccessor)
        {
            resultResourceAccessor = null;
            string resourcePathName = potentialBaseResourceAccessor.ResourcePathName;

            if (string.IsNullOrEmpty(resourcePathName) || !potentialBaseResourceAccessor.IsFile ||
                !".iso".Equals(DosPathHelper.GetExtension(resourcePathName), StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }

            lock (_syncObj)
            {
                string key = potentialBaseResourceAccessor.CanonicalLocalResourcePath.Serialize();
                try
                {
                    IsoResourceProxy proxy;
                    if (!_isoUsages.TryGetValue(key, out proxy))
                    {
                        _isoUsages.Add(key, proxy = CreateIsoResourceProxy(key, potentialBaseResourceAccessor));
                    }
                    resultResourceAccessor = new IsoResourceAccessor(this, proxy, path);
                }
                catch (Exception e)
                {
                    ServiceRegistration.Get <ILogger>().Warn("IsoResourceProvider: Error chaining up to '{0}'", e, potentialBaseResourceAccessor.CanonicalLocalResourcePath);
                    return(false);
                }
                return(true);
            }
        }
 protected VirtualBaseDirectory(string name, IResourceAccessor resourceAccessor) : base(name, resourceAccessor)
 {
 }
        /// <summary>
        /// Extracts relations from all <see cref="IRelationshipRoleExtractor"/>s that support the given aspects.
        /// </summary>
        /// <param name="mediaItemId">The id of the media item.</param>
        /// <param name="aspects">The aspects of the media item.</param>
        /// <returns></returns>
        protected async Task <ICollection <ExtractedRelation> > ExtractRelationshipMetadata(IResourceAccessor mediaItemAccessor,
                                                                                            Guid mediaItemId, IDictionary <Guid, IList <MediaItemAspect> > aspects)
        {
            ICollection <ExtractedRelation> relations = new List <ExtractedRelation>();

            foreach (IList <IRelationshipRoleExtractor> extractorList in GetExtractorsByRoleLinkedRole(aspects).Values)
            {
                await ExtractRelationshipMetadata(extractorList, mediaItemAccessor, mediaItemId, aspects, relations).ConfigureAwait(false);
            }
            return(relations);
        }
 public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
 {
   // The following is bad practice as it wastes one ThreadPool thread.
   // ToDo: Once the IMetadataExtractor interface is updated to support async operations, call TryExtractMetadataAsync directly
   return TryExtractMetadataAsync(mediaItemAccessor, extractedAspectData, forceQuickMode).Result;
 }
        /// <summary>
        /// Extracts relations for the specified <paramref name="roleExtractor"/> and adds them to <paramref name="relations"/> collection.
        /// </summary>
        /// <param name="roleExtractor">The extractor to use to extract relations.</param>
        /// <param name="mediaItemId">The id of the media item.</param>
        /// <param name="aspects">The aspects of the media item.</param>
        /// <param name="relations">Collection of relations to add any extracted relations.</param>
        protected async Task ExtractRelationshipMetadata(IList <IRelationshipRoleExtractor> roleExtractors, IResourceAccessor mediaItemAccessor,
                                                         Guid mediaItemId, IDictionary <Guid, IList <MediaItemAspect> > aspects, ICollection <ExtractedRelation> relations)
        {
            IList <IDictionary <Guid, IList <MediaItemAspect> > > extractedItems = new List <IDictionary <Guid, IList <MediaItemAspect> > >();

            foreach (IRelationshipRoleExtractor roleExtractor in roleExtractors)
            {
                await roleExtractor.TryExtractRelationshipsAsync(mediaItemAccessor, aspects, extractedItems).ConfigureAwait(false);
            }

            foreach (IDictionary <Guid, IList <MediaItemAspect> > extractedItem in extractedItems)
            {
                relations.Add(new ExtractedRelation(roleExtractors[0], extractedItem));
            }

            ServiceRegistration.Get <ILogger>().Debug("Extractor {0} extracted {1} media items from media item {2}", roleExtractors[0].GetType().Name, extractedItems.Count, mediaItemId);
        }
Beispiel #47
0
 public IDictionary<Guid, MediaItemAspect> ExtractMetadata(IResourceAccessor mediaItemAccessor,
     IEnumerable<Guid> metadataExtractorIds, bool forceQuickMode)
 {
   ICollection<IMetadataExtractor> extractors = new List<IMetadataExtractor>();
   foreach (Guid extractorId in metadataExtractorIds)
   {
     IMetadataExtractor extractor;
     if (LocalMetadataExtractors.TryGetValue(extractorId, out extractor))
       extractors.Add(extractor);
   }
   return ExtractMetadata(mediaItemAccessor, extractors, forceQuickMode);
 }
 /// <summary>
 /// Creates _resourceAccessor from the _resourceLocator which can be used by the specific player.
 /// </summary>
 protected virtual void CreateResourceAccessor()
 {
     _resourceAccessor = _resourceLocator.CreateAccessor();
 }
Beispiel #49
0
 public MediaItem CreateLocalMediaItem(IResourceAccessor mediaItemAccessor, IEnumerable<Guid> metadataExtractorIds)
 {
   ISystemResolver systemResolver = ServiceRegistration.Get<ISystemResolver>();
   const bool forceQuickMode = true;
   IDictionary<Guid, MediaItemAspect> aspects = ExtractMetadata(mediaItemAccessor, metadataExtractorIds, forceQuickMode);
   if (aspects == null)
     return null;
   MediaItemAspect providerResourceAspect = MediaItemAspect.GetOrCreateAspect(aspects, ProviderResourceAspect.Metadata);
   providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SYSTEM_ID, systemResolver.LocalSystemId);
   providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH, mediaItemAccessor.CanonicalLocalResourcePath.Serialize());
   return new MediaItem(Guid.Empty, aspects);
 }
Beispiel #50
0
        public virtual Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            try
            {
                IResourceAccessor metaFileAccessor;
                if (!CanExtract(mediaItemAccessor, extractedAspectData, out metaFileAccessor))
                {
                    return(Task.FromResult(false));
                }

                Tags tags;
                using (metaFileAccessor)
                {
                    using (Stream metaStream = ((IFileSystemResourceAccessor)metaFileAccessor).OpenRead())
                        tags = (Tags)GetTagsXmlSerializer().Deserialize(metaStream);
                }

                string value;
                MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, false);
                MediaItemAspect.SetAttribute(extractedAspectData, VideoAspect.ATTR_ISDVD, false);

                if (TryGet(tags, TAG_TITLE, out value) && !string.IsNullOrEmpty(value))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, value);
                    MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, BaseInfo.GetSortTitle(value));
                }

                if (TryGet(tags, TAG_GENRE, out value) && !string.IsNullOrEmpty(value?.Trim()))
                {
                    List <GenreInfo> genreList = new List <GenreInfo>(new GenreInfo[] { new GenreInfo {
                                                                                            Name = value.Trim()
                                                                                        } });
                    IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>();
                    foreach (var genre in genreList)
                    {
                        if (!genre.Id.HasValue && converter.GetGenreId(genre.Name, GenreCategory.Movie, null, out int genreId))
                        {
                            genre.Id = genreId;
                        }
                    }
                    MultipleMediaItemAspect genreAspect = MediaItemAspect.CreateAspect(extractedAspectData, GenreAspect.Metadata);
                    genreAspect.SetAttribute(GenreAspect.ATTR_ID, genreList[0].Id);
                    genreAspect.SetAttribute(GenreAspect.ATTR_GENRE, genreList[0].Name);
                }

                if (TryGet(tags, TAG_PLOT, out value))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, VideoAspect.ATTR_STORYPLOT, value);
                    Match yearMatch = _yearMatcher.Match(value);
                    int   guessedYear;
                    if (int.TryParse(yearMatch.Value, out guessedYear))
                    {
                        MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(guessedYear, 1, 1));
                    }
                }

                if (TryGet(tags, TAG_CHANNEL, out value))
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_CHANNEL, value);
                }

                // Recording date formatted: 2011-11-04 20:55
                DateTime tmpValue;
                DateTime?recordingStart = null;
                DateTime?recordingEnd   = null;
                DateTime?programStart   = null;
                DateTime?programEnd     = null;

                // First try to read program start and end times, they will be preferred.
                if (TryGet(tags, TAG_PROGRAMSTARTTIME, out value) && DateTime.TryParse(value, out tmpValue))
                {
                    programStart = tmpValue;
                }

                if (TryGet(tags, TAG_PROGRAMENDTIME, out value) && DateTime.TryParse(value, out tmpValue))
                {
                    programEnd = tmpValue;
                }

                if (TryGet(tags, TAG_STARTTIME, out value) && DateTime.TryParse(value, out tmpValue))
                {
                    recordingStart = tmpValue;
                }

                if (TryGet(tags, TAG_ENDTIME, out value) && DateTime.TryParse(value, out tmpValue))
                {
                    recordingEnd = tmpValue;
                }

                // Correct start time if recording started before the program (skip pre-recording offset)
                if (programStart.HasValue && recordingStart.HasValue && programStart > recordingStart)
                {
                    recordingStart = programStart;
                }

                // Correct end time if recording ended after the program (skip the post-recording offset)
                if (programEnd.HasValue && recordingEnd.HasValue && programEnd < recordingEnd)
                {
                    recordingEnd = programEnd;
                }

                if (recordingStart.HasValue)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_STARTTIME, recordingStart.Value);
                }
                if (recordingEnd.HasValue)
                {
                    MediaItemAspect.SetAttribute(extractedAspectData, RecordingAspect.ATTR_ENDTIME, recordingEnd.Value);
                }

                return(Task.FromResult(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("Tve3RecordingMetadataExtractor: Exception reading resource '{0}' (Text: '{1}')", mediaItemAccessor.CanonicalLocalResourcePath, e.Message);
            }
            return(Task.FromResult(false));
        }
 public bool IsStubResource(IResourceAccessor mediaItemAccessor)
 {
     return(false);
 }
Beispiel #52
0
        protected static bool CanExtract(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, out IResourceAccessor metaFileAccessor)
        {
            metaFileAccessor = null;
            IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;

            if (fsra == null || !fsra.IsFile)
            {
                return(false);
            }

            string title;

            if (!MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) || string.IsNullOrEmpty(title))
            {
                return(false);
            }

            string filePath       = mediaItemAccessor.CanonicalLocalResourcePath.ToString();
            string lowerExtension = StringUtils.TrimToEmpty(ProviderPathHelper.GetExtension(filePath)).ToLowerInvariant();

            if (lowerExtension != ".ts")
            {
                return(false);
            }
            string metaFilePath = ProviderPathHelper.ChangeExtension(filePath, ".xml");

            if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out metaFileAccessor))
            {
                return(false);
            }
            return(true);
        }
 public bool IsDirectorySingleResource(IResourceAccessor mediaItemAccessor)
 {
     return(false);
 }
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
   result = GetResourceAccessor(path);
   return result != null;
 }
    public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
    {
      try
      {
        if (!(mediaItemAccessor is IFileSystemResourceAccessor))
          return false;

        using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
        {
          ILocalFsResourceAccessor lfsra = rah.LocalFsResourceAccessor;
          if (!lfsra.IsFile && lfsra.ResourceExists("BDMV"))
          {
            IFileSystemResourceAccessor fsraBDMV = lfsra.GetResource("BDMV");
            if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv"))
            {
              // This line is important to keep in, if no VideoAspect is created here, the MediaItems is not detected as Video! 
              MediaItemAspect.GetOrCreateAspect(extractedAspectData, VideoAspect.Metadata);
              MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);

              mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc

              using (lfsra.EnsureLocalFileSystemAccess())
              {
                BDInfoExt bdinfo = new BDInfoExt(lfsra.LocalFileSystemPath);
                string title = bdinfo.GetTitle();
                mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, title ?? mediaItemAccessor.ResourceName);

                // Check for BD disc thumbs
                FileInfo thumbnail = bdinfo.GetBiggestThumb();
                if (thumbnail != null)
                {
                  try
                  {
                    using (FileStream fileStream = new FileStream(thumbnail.FullName, FileMode.Open, FileAccess.Read))
                    using (MemoryStream resized = (MemoryStream)ImageUtilities.ResizeImage(fileStream, ImageFormat.Jpeg, MAX_COVER_WIDTH, MAX_COVER_HEIGHT))
                    {
                      MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, resized.ToArray());
                    }
                  }
                    // Decoding of invalid image data can fail, but main MediaItem is correct.
                  catch
                  {
                  }
                }
              }
              return true;
            }
          }
        }
        return false;
      }
      catch
      {
        // Only log at the info level here - And simply return false. This makes the importer know that we
        // couldn't perform our task here
        if (mediaItemAccessor != null)
          ServiceRegistration.Get<ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName);
        return false;
      }
    }
Beispiel #56
0
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
     result = SlimTvResourceAccessor.GetResourceAccessor(path);
     return(result != null);
 }
 public bool TryCreateResourceAccessor(string path, out IResourceAccessor result)
 {
   string nativeSystemId;
   ResourcePath nativeResourcePath;
   if (!TryExtractSystemAndPath(path, out nativeSystemId, out nativeResourcePath))
     throw new InvalidDataException("Path '{0}' is not a valid path for remote resource provider", path);
   ISystemResolver systemResolver = ServiceRegistration.Get<ISystemResolver>();
   SystemName nativeSystem = systemResolver.GetSystemNameForSystemId(nativeSystemId);
   if (nativeSystem == null)
     throw new IllegalCallException("Cannot create resource accessor for resource location '{0}' at system '{1}': System is not available", nativeResourcePath, nativeSystemId);
   // Try to access resource locally. This might work if we have the correct resource providers installed.
   if (nativeSystem.IsLocalSystem() && nativeResourcePath.IsValidLocalPath && nativeResourcePath.TryCreateLocalResourceAccessor(out result))
     return true;
   IFileSystemResourceAccessor fsra;
   if (RemoteFileSystemResourceAccessor.ConnectFileSystem(nativeSystemId, nativeResourcePath, out fsra))
   {
     result = fsra;
     return true;
   }
   IResourceAccessor ra;
   if (RemoteFileResourceAccessor.ConnectFile(nativeSystemId, nativeResourcePath, out ra))
   {
     result = ra;
     return true;
   }
   result = null;
   return false;
 }
Beispiel #58
0
        public async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool forceQuickMode)
        {
            string fileName = mediaItemAccessor.ResourceName;

            if (!HasImageExtension(fileName))
            {
                return(false);
            }
            if (DosPathHelper.GetFileNameWithoutExtension(fileName).ToLowerInvariant() == "folder")
            {
                return(false); //Ignore folder images
            }
            bool refresh = false;

            if (extractedAspectData.ContainsKey(ImageAspect.ASPECT_ID))
            {
                refresh = true;
            }

            try
            {
                IFileSystemResourceAccessor fsra = mediaItemAccessor as IFileSystemResourceAccessor;
                if (!refresh)
                {
                    MultipleMediaItemAspect providerResourceAspect = MediaItemAspect.CreateAspect(extractedAspectData, ProviderResourceAspect.Metadata);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_RESOURCE_INDEX, 0);
                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_TYPE, ProviderResourceAspect.TYPE_PRIMARY);

                    if (!(mediaItemAccessor is IFileSystemResourceAccessor))
                    {
                        return(false);
                    }

                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size);
                    if (!forceQuickMode)
                    {
                        // Open a stream for media item to detect mimeType.
                        using (Stream mediaStream = fsra.OpenRead())
                        {
                            string mimeType = MimeTypeDetector.GetMimeType(mediaStream) ?? DEFAULT_MIMETYPE;
                            providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mimeType);
                        }
                    }
                    else
                    {
                        string mimeType = MimeTypeDetector.GetMimeTypeFromExtension(fileName) ?? DEFAULT_MIMETYPE;
                        providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mimeType);
                    }
                }

                MediaItemAspect mediaAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, MediaAspect.Metadata);
                mediaAspect.SetAttribute(MediaAspect.ATTR_ISVIRTUAL, false);
                MediaItemAspect imageAspect = MediaItemAspect.GetOrCreateAspect(extractedAspectData, ImageAspect.Metadata);

                if (!refresh)
                {
                    mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, ProviderPathHelper.GetFileNameWithoutExtension(fileName));

                    if (!forceQuickMode)
                    {
                        // Extract EXIF information from media item.
                        using (ExifMetaInfo.ExifMetaInfo exif = new ExifMetaInfo.ExifMetaInfo(fsra))
                        {
                            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);
                            }
                        }
                    }
                    else
                    {
                        mediaAspect.SetAttribute(MediaAspect.ATTR_RECORDINGTIME, fsra.LastChanged);
                        imageAspect.SetAttribute(ImageAspect.ATTR_ORIENTATION, 0);
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(true);
                    }

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                            if (localFsResourcePath != null)
                            {
                                // Thumbnail extraction
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, forceQuickMode, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                }
                            }
                        }
                    return(true);
                }
                else
                {
                    bool   updated   = false;
                    double?latitude  = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LATITUDE);
                    double?longitude = imageAspect.GetAttributeValue <double?>(ImageAspect.ATTR_LONGITUDE);
                    if (!forceQuickMode && IncludeGeoLocationDetails && latitude.HasValue && longitude.HasValue &&
                        string.IsNullOrEmpty(imageAspect.GetAttributeValue <string>(ImageAspect.ATTR_COUNTRY)))
                    {
                        var geoCoordinate = new GeoCoordinate(latitude.Value, longitude.Value);
                        var lookupResult  = await GeoLocationService.Instance.TryLookupAsync(geoCoordinate).ConfigureAwait(false);

                        if (lookupResult.Success)
                        {
                            CivicAddress locationInfo = lookupResult.Result;
                            imageAspect.SetAttribute(ImageAspect.ATTR_CITY, locationInfo.City);
                            imageAspect.SetAttribute(ImageAspect.ATTR_STATE, locationInfo.StateProvince);
                            imageAspect.SetAttribute(ImageAspect.ATTR_COUNTRY, locationInfo.CountryRegion);
                            updated = true;
                        }
                    }

                    byte[] thumbData;
                    // We only want to create missing thumbnails here, so check for existing ones first
                    if (MediaItemAspect.TryGetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, out thumbData) && thumbData != null)
                    {
                        return(updated);
                    }

                    using (LocalFsResourceAccessorHelper rah = new LocalFsResourceAccessorHelper(mediaItemAccessor))
                        using (rah.LocalFsResourceAccessor.EnsureLocalFileSystemAccess())
                        {
                            string localFsResourcePath = rah.LocalFsResourceAccessor.LocalFileSystemPath;
                            if (localFsResourcePath != null)
                            {
                                // In quick mode only allow thumbs taken from cache.
                                bool cachedOnly = forceQuickMode;
                                // Thumbnail extraction
                                IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>();
                                ImageType           imageType;
                                if (generator.GetThumbnail(localFsResourcePath, cachedOnly, out thumbData, out imageType))
                                {
                                    MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData);
                                    updated = true;
                                }
                            }
                        }
                    return(updated);
                }
            }
            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);
        }
        public bool TryExtractMetadata(IResourceAccessor mediaItemAccessor, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode)
        {
            try
              {
            IResourceAccessor ra = mediaItemAccessor.Clone();
            try
            {
              using (ILocalFsResourceAccessor fsra = StreamedResourceToLocalFsAccessBridge.GetLocalFsResourceAccessor(ra))
            if (fsra != null && fsra.IsDirectory && fsra.ResourceExists("BDMV"))
            {
              IFileSystemResourceAccessor fsraBDMV = fsra.GetResource("BDMV");
              if (fsraBDMV != null && fsraBDMV.ResourceExists("index.bdmv"))
              {
                // BluRay
                MediaItemAspect mediaAspect;
                if (!extractedAspectData.TryGetValue(MediaAspect.ASPECT_ID, out mediaAspect))
                  extractedAspectData[MediaAspect.ASPECT_ID] = mediaAspect = new MediaItemAspect(MediaAspect.Metadata);
                MediaItemAspect videoAspect;
                if (!extractedAspectData.TryGetValue(VideoAspect.ASPECT_ID, out videoAspect))
                  extractedAspectData[VideoAspect.ASPECT_ID] = new MediaItemAspect(VideoAspect.Metadata);

                mediaAspect.SetAttribute(MediaAspect.ATTR_MIME_TYPE, "video/bluray"); // BluRay disc

                string bdmvDirectory = fsra.LocalFileSystemPath;
                BDInfoExt bdinfo = new BDInfoExt(bdmvDirectory);
                mediaAspect.SetAttribute(MediaAspect.ATTR_TITLE, bdinfo.GetTitle() ?? mediaItemAccessor.ResourceName);
                return true;
              }
            }
            }
            catch
            {
              ra.Dispose();
              throw;
            }
            return false;
              }
              catch
              {
            // Only log at the info level here - And simply return false. This makes the importer know that we
            // couldn't perform our task here
            if (mediaItemAccessor != null)
              ServiceRegistration.Get<ILogger>().Info("BluRayMetadataExtractor: Exception reading source '{0}'", mediaItemAccessor.ResourcePathName);
            return false;
              }
        }
        /// <summary>
        /// Instantiates all the necessary DataflowBlocks for the given ImportJob
        /// </summary>
        /// <remarks>
        /// We first have to distinguish between two cases here:
        ///  - BasePath points to a resource for which we can only create an IResourceAccessor - not an IFilesystemResourceAccessor
        ///    For this case we only import that single resource and don't have to take care of directories and subdirectories
        ///    ToDo: This still needs to be implemented
        /// - BasePath points to a resource for which we can create an IFilesystemResourceAccessor
        ///   Here we first check whether the resource on the given BasePath exists. If not, we do nothing.
        ///   If it does exist, we distinguish two cases:
        ///   - The ImportJob was restored from disk, in which case we push the existing PendingImportResources to the respective DataflowBlocks.
        ///   - The ImportJob was freshly created, in which case we push the BasePath to the first DataFlowBlock.
        ///     In this case there are three subcases:
        ///     - BasePath points to a single resource
        ///     - BasePath points to a directory which is not a single resource and the ImportJob does not include subdirectories
        ///     - BasePath points to a directory which is not a single resource and the ImportJob does include subdirectories
        ///     These subcases, however, are taken care of by the DataflowBlocks - not by the ImportJobController
        /// </remarks>
        private void SetupDataflowBlocks(IEnumerable <PendingImportResourceNewGen> pendingImportResources)
        {
            // If we cannot access the BasePath at all, we just log and return
            IResourceAccessor ra = null;

            try
            {
                if (!_importJobInformation.BasePath.TryCreateLocalResourceAccessor(out ra))
                {
                    ServiceRegistration.Get <ILogger>().Warn("ImporterWorker.{0}: Unable to access resource path '{1}'.", this, _importJobInformation.BasePath);
                    return;
                }
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Error while creating ResourceAccessor for resource path '{1}'.", e, this, _importJobInformation.BasePath);
                if (ra != null)
                {
                    ra.Dispose();
                }
                return;
            }

            try
            {
                // As of now we have a ResourceAccessor that needs to be disposed
                using (ra)
                {
                    // If we have a ResourceAccessor which is not an IFileSystemResourceAccessor, just import that single resource
                    if (!(ra is IFileSystemResourceAccessor))
                    {
                        // ToDo: Implement import of Non-IFilesSystemResourceAccessors
                        return;
                    }

                    // Now we are sure it is an IFileSystemResourceAccessor
                    var fsra = ra as IFileSystemResourceAccessor;

                    // If the BasePath does not exist, we do nothing. This is necessary to avoid whole shares being removed from
                    // the MediaLibrary when a RefreshImport is scheduled while e.g. network resources are unavailable.
                    // If fsra is a NetworkNeighborhoddResourceAccessor and its IsServerPath() method returns true, fsra.Exists()
                    // will always return true. If therefore the BasePath of this Import points to a whole server and this server
                    // is not available during a RefreshImport, the whole share will be deleted from the MediaLibrary.
                    // ToDo: Rework this in NetworkNeighborhoodResourceAccessor
                    if (!fsra.Exists)
                    {
                        ServiceRegistration.Get <ILogger>().Warn("ImporterWorker.{0}: Resource '{1}' does not exists or is not available.", this, _importJobInformation.BasePath);
                        return;
                    }

                    // Now we are sure that we need a DataflowBlock network

                    // Create the blocks
                    _dataflowBlocks.Add(new DirectoryUnfoldBlock(_cts.Token, _importJobInformation, this));
                    _dataflowBlocks.Add(new DirectorySaveBlock(_cts.Token, _importJobInformation, this));
                    _dataflowBlocks.Add(new FileUnfoldBlock(_cts.Token, _importJobInformation, this));
                    _dataflowBlocks.Add(new MediaItemLoadBlock(_cts.Token, _importJobInformation, this));
                    _dataflowBlocks.Add(new MetadataExtractorBlock(_cts.Token, _importJobInformation, this, false));
                    _dataflowBlocks.Add(new MediaItemSaveBlock(_cts.Token, _importJobInformation, this));
                    _dataflowBlocks.Add(new RelationshipExtractorBlock(_cts.Token, _importJobInformation, this));

                    // Link the blocks
                    for (int i = 0; i < _dataflowBlocks.Count - 1; i++)
                    {
                        _dataflowBlocks[i].LinkTo(_dataflowBlocks[i + 1], new DataflowLinkOptions {
                            PropagateCompletion = true
                        });
                    }
                    _dataflowBlocks[_dataflowBlocks.Count - 1].LinkTo(DataflowBlock.NullTarget <PendingImportResourceNewGen>());

                    // Fill the blocks
                    var  completeFirstBlockAfterTheseTasks = new HashSet <Task>();
                    bool firstBlockNeedsCompletion         = true;
                    if (pendingImportResources == null)
                    {
                        // This ImportJob was freshly created and not persisted to disk before
                        // Just post the BasePath as new PendingImportResource
                        var rootImportResource = new PendingImportResourceNewGen(null, fsra.Clone() as IFileSystemResourceAccessor, DirectoryUnfoldBlock.BLOCK_NAME, this);
                        _dataflowBlocks[0].Post(rootImportResource);
                        firstBlockNeedsCompletion = false;
                    }
                    else
                    {
                        // This ImportJob was persisted to disk before
                        int numberOfRestoredPendingResources = 0;
                        foreach (var pendingImportResource in pendingImportResources)
                        {
                            pendingImportResource.InitializeAfterDeserialization(this);
                            ImporterWorkerDataflowBlockBase block = _dataflowBlocks.Find(b => b.ToString() == pendingImportResource.CurrentBlock);
                            if (block != null)
                            {
                                completeFirstBlockAfterTheseTasks.Add(block.SendAsync(pendingImportResource, _cts.Token));
                                numberOfRestoredPendingResources++;
                                if (block == _dataflowBlocks[0])
                                {
                                    firstBlockNeedsCompletion = false;
                                }
                            }
                            else
                            {
                                ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Could not add {1} after deserialization. DataflowBlock with name {2} does not exist.", this, pendingImportResource, pendingImportResource.CurrentBlock);
                                pendingImportResource.Dispose();
                            }
                        }
                        ServiceRegistration.Get <ILogger>().Debug("ImporterWorker.{0}: {1} PendingImportResources restored.", this, numberOfRestoredPendingResources);
                    }
                    completeFirstBlockAfterTheseTasks.Add(_firstBlockHasFinished.Task);
                    if (firstBlockNeedsCompletion)
                    {
                        FirstBlockHasFinished();
                    }

                    // The first DataflowBlock in the network (DirectoryUnfoldBlock) must be set to completed when
                    // (a) The DirectoryUnfoldBlock has signaled that it is finished (by calling FirstBlockHasFinished()) and
                    // (b) in case of an ImportJob that has been restored from disk, all restored PendingImportResources
                    //     have been put into the Dataflow network
                    Task.WhenAll(completeFirstBlockAfterTheseTasks).ContinueWith(previousTask => _dataflowBlocks[0].Complete());
                }
            }
            catch (Exception e)
            {
                ServiceRegistration.Get <ILogger>().Error("ImporterWorker.{0}: Error while setting up DataflowBlocks for resource path '{1}.", e, this, _importJobInformation.BasePath);
            }
        }