예제 #1
0
        /// <summary>
        /// Verifies if the movie being reimported matches the movie in the nfo file
        /// </summary>
        /// <param name="reader">Reader used read the movie information from the nfo file</param>
        /// <param name="reimport">The movie being reimported</param>
        /// <returns>Result of the verification</returns>
        protected bool VerifyMovieReimport(NfoMovieReader reader, MovieInfo reimport)
        {
            if (reimport == null)
            {
                return(true);
            }

            IDictionary <Guid, IList <MediaItemAspect> > aspectData = new Dictionary <Guid, IList <MediaItemAspect> >();

            if (reader.TryWriteMetadata(aspectData))
            {
                MovieInfo info = new MovieInfo();
                info.FromMetadata(aspectData);
                if (reimport.Equals(info))
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #2
0
        public void TestNfoMovieReaderWriteMetadata()
        {
            //Arrange
            MovieStub      movieStub       = CreateTestMovieStub(CreateTestActors());
            NfoMovieReader readerVideoOnly = new NfoMovieReader(new ConsoleLogger(LogLevel.All, true), 1, true, false, false, null, new NfoMovieMetadataExtractorSettings());

            readerVideoOnly.GetMovieStubs().Add(movieStub);
            NfoMovieReader readerMovieOnly = new NfoMovieReader(new ConsoleLogger(LogLevel.All, true), 1, false, false, false, null, new NfoMovieMetadataExtractorSettings());

            readerMovieOnly.GetMovieStubs().Add(movieStub);

            //Act
            IDictionary <Guid, IList <MediaItemAspect> > aspectsVideoOnly = new Dictionary <Guid, IList <MediaItemAspect> >();

            readerVideoOnly.TryWriteMetadata(aspectsVideoOnly);
            IDictionary <Guid, IList <MediaItemAspect> > aspectsMovieOnly = new Dictionary <Guid, IList <MediaItemAspect> >();

            readerMovieOnly.TryWriteMetadata(aspectsMovieOnly);

            //Assert

            //Video aspects only
            MediaItemAspect mediaAspect = MediaItemAspect.GetAspect(aspectsVideoOnly, MediaAspect.Metadata);

            Assert.NotNull(mediaAspect);
            Assert.AreEqual(movieStub.Title, mediaAspect.GetAttributeValue <string>(MediaAspect.ATTR_TITLE));
            Assert.AreEqual(movieStub.SortTitle, mediaAspect.GetAttributeValue <string>(MediaAspect.ATTR_SORT_TITLE));
            Assert.AreEqual(movieStub.Premiered, mediaAspect.GetAttributeValue <DateTime?>(MediaAspect.ATTR_RECORDINGTIME));
            Assert.AreEqual(movieStub.PlayCount, mediaAspect.GetAttributeValue <int?>(MediaAspect.ATTR_PLAYCOUNT));
            Assert.AreEqual(movieStub.LastPlayed, mediaAspect.GetAttributeValue <DateTime?>(MediaAspect.ATTR_LASTPLAYED));

            MediaItemAspect videoAspect = MediaItemAspect.GetAspect(aspectsVideoOnly, VideoAspect.Metadata);

            Assert.NotNull(videoAspect);
            Assert.AreEqual(movieStub.Plot, videoAspect.GetAttributeValue <string>(VideoAspect.ATTR_STORYPLOT));
            CollectionAssert.AreEqual(movieStub.Actors.OrderBy(p => p.Order).Select(p => p.Name), videoAspect.GetCollectionAttribute <string>(VideoAspect.ATTR_ACTORS));
            Assert.AreEqual(movieStub.Director, videoAspect.GetCollectionAttribute <string>(VideoAspect.ATTR_DIRECTORS).First());
            CollectionAssert.AreEqual(movieStub.Credits, videoAspect.GetCollectionAttribute <string>(VideoAspect.ATTR_WRITERS));

            //ToDo: Rework Genre Mapper to make it testable, currently depends on IPathManager/language files!
            //IList<MediaItemAspect> genreAspects;
            //Assert.IsTrue(aspects.TryGetValue(GenreAspect.ASPECT_ID, out genreAspects));
            //CollectionAssert.AreEqual(movieStub.Genres, genreAspects.Select(g => g.GetAttributeValue<string>(GenreAspect.ATTR_GENRE)));

            MediaItemAspect thumbnailAspect = MediaItemAspect.GetAspect(aspectsVideoOnly, ThumbnailLargeAspect.Metadata);

            Assert.NotNull(thumbnailAspect);
            CollectionAssert.AreEqual(movieStub.Thumb, thumbnailAspect.GetAttributeValue <byte[]>(ThumbnailLargeAspect.ATTR_THUMBNAIL));

            //Movie aspects only
            MediaItemAspect movieAspect = MediaItemAspect.GetAspect(aspectsMovieOnly, MovieAspect.Metadata);

            Assert.NotNull(movieAspect);
            CollectionAssert.AreEqual(movieStub.Companies, movieAspect.GetCollectionAttribute <string>(MovieAspect.ATTR_COMPANIES));
            Assert.AreEqual(movieStub.Title, movieAspect.GetAttributeValue <string>(MovieAspect.ATTR_MOVIE_NAME));
            Assert.AreEqual(movieStub.OriginalTitle, movieAspect.GetAttributeValue <string>(MovieAspect.ATTR_ORIG_MOVIE_NAME));
            Assert.AreEqual(movieStub.Sets.OrderBy(set => set.Order).First().Name, movieAspect.GetAttributeValue <string>(MovieAspect.ATTR_COLLECTION_NAME));
            Assert.AreEqual((int)movieStub.Runtime.Value.TotalMinutes, movieAspect.GetAttributeValue <int?>(MovieAspect.ATTR_RUNTIME_M));
            Assert.AreEqual("US_PG", movieAspect.GetAttributeValue <string>(MovieAspect.ATTR_CERTIFICATION));
            Assert.AreEqual(movieStub.Tagline, movieAspect.GetAttributeValue <string>(MovieAspect.ATTR_TAGLINE));
            Assert.AreEqual((double)movieStub.Rating, movieAspect.GetAttributeValue <double?>(MovieAspect.ATTR_TOTAL_RATING));
            Assert.AreEqual(movieStub.Votes, movieAspect.GetAttributeValue <int?>(MovieAspect.ATTR_RATING_COUNT));

            IList <MediaItemAspect> externalIdentifiers;

            Assert.IsTrue(aspectsMovieOnly.TryGetValue(ExternalIdentifierAspect.ASPECT_ID, out externalIdentifiers));
            Assert.IsTrue(TestUtils.HasExternalId(externalIdentifiers, ExternalIdentifierAspect.SOURCE_TMDB, ExternalIdentifierAspect.TYPE_MOVIE, movieStub.TmdbId.ToString()));
            Assert.IsTrue(TestUtils.HasExternalId(externalIdentifiers, ExternalIdentifierAspect.SOURCE_TMDB, ExternalIdentifierAspect.TYPE_COLLECTION, movieStub.TmdbCollectionId.ToString()));
            Assert.IsTrue(TestUtils.HasExternalId(externalIdentifiers, ExternalIdentifierAspect.SOURCE_IMDB, ExternalIdentifierAspect.TYPE_MOVIE, movieStub.Id));
            Assert.IsTrue(TestUtils.HasExternalId(externalIdentifiers, ExternalIdentifierAspect.SOURCE_ALLOCINE, ExternalIdentifierAspect.TYPE_MOVIE, movieStub.Allocine.ToString()));
            Assert.IsTrue(TestUtils.HasExternalId(externalIdentifiers, ExternalIdentifierAspect.SOURCE_CINEPASSION, ExternalIdentifierAspect.TYPE_MOVIE, movieStub.Cinepassion.ToString()));
        }
        /// <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> TryExtractMovieMetadataAsync(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);

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

                // 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);
                }

                // 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);
                }

                // 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 there is an error parsing the nfo-file with XmlNfoReader, we at least try to parse for a valid IMDB-ID.
                // If no metadata was found, nothing can be stored in the MediaItemAspects.
                NfoMovieReader nfoReader = new NfoMovieReader(_debugLogger, miNumber, false, forceQuickMode, isStub, _httpClient, _settings);
                using (nfoFsra)
                {
                    if (!await nfoReader.TryReadMetadataAsync(nfoFsra).ConfigureAwait(false) &&
                        !await nfoReader.TryParseForImdbId(nfoFsra).ConfigureAwait(false))
                    {
                        _debugLogger.Warn("[#{0}]: No valid metadata found", miNumber);
                        return(false);
                    }
                    else if (isStub)
                    {
                        Stubs.MovieStub movie = nfoReader.GetMovieStubs().FirstOrDefault();
                        if (movie != null)
                        {
                            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 (movie.FileInfo != null && movie.FileInfo.Count > 0)
                                {
                                    mime = MimeTypeDetector.GetMimeTypeFromExtension("file" + movie.FileInfo.First().Container);
                                }
                                if (mime != null)
                                {
                                    providerResourceAspect.SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, mime);
                                }
                            }

                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, movie.Title);
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, movie.SortTitle != null ? movie.SortTitle : BaseInfo.GetSortTitle(movie.Title));
                            MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, movie.Premiered.HasValue ? movie.Premiered.Value : movie.Year.HasValue ? movie.Year.Value : (DateTime?)null);

                            if (movie.FileInfo != null && movie.FileInfo.Count > 0)
                            {
                                extractedAspectData.Remove(VideoStreamAspect.ASPECT_ID);
                                extractedAspectData.Remove(VideoAudioStreamAspect.ASPECT_ID);
                                extractedAspectData.Remove(SubtitleAspect.ASPECT_ID);
                                StubParser.ParseFileInfo(extractedAspectData, movie.FileInfo, movie.Title, movie.Fps);
                            }
                        }
                    }
                }

                //Check reimport
                if (extractedAspectData.ContainsKey(ReimportAspect.ASPECT_ID))
                {
                    MovieInfo reimport = new MovieInfo();
                    reimport.FromMetadata(extractedAspectData);
                    if (!VerifyMovieReimport(nfoReader, reimport))
                    {
                        ServiceRegistration.Get <ILogger>().Info("NfoMovieMetadataExtractor: Nfo movie metadata from resource '{0}' ignored because it does not match reimport {1}", mediaItemAccessor, reimport);
                        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);
                ServiceRegistration.Get <ILogger>().Debug("NfoMovieMetadataExtractor: Assigned nfo movie metadata for resource '{0}'", mediaItemAccessor);
                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);
            }
        }
    /// <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;
      }
    }
예제 #5
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> 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);
            }
        }