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