private static bool ExtractMovieData(ILocalFsResourceAccessor lfsra, IDictionary <Guid, MediaItemAspect> extractedAspectData) { string[] pathsToTest = new [] { lfsra.LocalFileSystemPath, lfsra.CanonicalLocalResourcePath.ToString() }; string title; if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) && !string.IsNullOrEmpty(title)) { MovieInfo movieInfo = new MovieInfo { MovieName = title, }; // Allow the online lookup to choose best matching language for metadata ICollection <string> movieLanguages; if (MediaItemAspect.TryGetAttribute(extractedAspectData, VideoAspect.ATTR_AUDIOLANGUAGES, out movieLanguages) && movieLanguages.Count > 0) { movieInfo.Languages.AddRange(movieLanguages); } // Try to use an existing IMDB id for exact mapping string imdbId; if (MediaItemAspect.TryGetAttribute(extractedAspectData, MovieAspect.ATTR_IMDB_ID, out imdbId) || pathsToTest.Any(path => ImdbIdMatcher.TryMatchImdbId(path, out imdbId)) || NfoReader.TryMatchImdbId(lfsra, out imdbId)) { movieInfo.ImdbId = imdbId; } // Also test the full path year, using a dummy. This is useful if the path contains the real name and year. foreach (string path in pathsToTest) { MovieInfo dummy = new MovieInfo { MovieName = path }; if (NamePreprocessor.MatchTitleYear(dummy)) { movieInfo.MovieName = dummy.MovieName; movieInfo.Year = dummy.Year; break; } } // When searching movie title, the year can be relevant for multiple titles with same name but different years DateTime recordingDate; if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, out recordingDate)) { movieInfo.Year = recordingDate.Year; } if (MovieTheMovieDbMatcher.Instance.FindAndUpdateMovie(movieInfo)) { movieInfo.SetMetadata(extractedAspectData); return(true); } } return(false); }
public async Task <bool> TryExtractRelationshipsAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > aspects, IList <IDictionary <Guid, IList <MediaItemAspect> > > extractedLinkedAspects) { if (MovieMetadataExtractor.OnlyLocalMedia) { return(false); } MovieCollectionInfo collectionInfo = new MovieCollectionInfo(); if (!collectionInfo.FromMetadata(aspects)) { return(false); } if (!MovieMetadataExtractor.SkipOnlineSearches && collectionInfo.HasExternalId) { await OnlineMatcherService.Instance.UpdateCollectionAsync(collectionInfo, true, _category).ConfigureAwait(false); } for (int i = 0; i < collectionInfo.Movies.Count; i++) { MovieInfo movieInfo = collectionInfo.Movies[i]; movieInfo.CollectionNameId = collectionInfo.NameId; IDictionary <Guid, IList <MediaItemAspect> > movieAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); if (movieInfo.SetMetadata(movieAspects)) { MediaItemAspect.SetAttribute(movieAspects, MediaAspect.ATTR_ISVIRTUAL, true); if (movieAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { extractedLinkedAspects.Add(movieAspects); } } } return(extractedLinkedAspects.Count > 0); }
public bool TryMerge(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects, IDictionary <Guid, IList <MediaItemAspect> > existingAspects) { try { MovieInfo existing = new MovieInfo(); MovieInfo extracted = new MovieInfo(); //Extracted aspects IList <MultipleMediaItemAspect> providerResourceAspects; if (!MediaItemAspect.TryGetAspects(extractedAspects, ProviderResourceAspect.Metadata, out providerResourceAspects)) { return(false); } //Existing aspects IList <MultipleMediaItemAspect> existingProviderResourceAspects; MediaItemAspect.TryGetAspects(existingAspects, ProviderResourceAspect.Metadata, out existingProviderResourceAspects); //Don't merge virtual resources if (!providerResourceAspects.Where(p => p.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_VIRTUAL).Any()) { //Replace if existing is a virtual resource if (existingProviderResourceAspects.Where(p => p.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_VIRTUAL).Any()) { //Don't allow merge of subtitles into virtual item if (extractedAspects.ContainsKey(SubtitleAspect.ASPECT_ID) && !extractedAspects.ContainsKey(VideoStreamAspect.ASPECT_ID)) { return(false); } MediaItemAspect.SetAttribute(existingAspects, MediaAspect.ATTR_ISVIRTUAL, false); MediaItemAspect.SetAttribute(existingAspects, MediaAspect.ATTR_ISSTUB, providerResourceAspects.Where(p => p.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_STUB).Any()); var now = DateTime.Now; MediaItemAspect.SetAttribute(existingAspects, ImporterAspect.ATTR_DATEADDED, now); MediaItemAspect.SetAttribute(existingAspects, ImporterAspect.ATTR_LAST_IMPORT_DATE, now); existingAspects.Remove(ProviderResourceAspect.ASPECT_ID); foreach (Guid aspect in extractedAspects.Keys) { if (!existingAspects.ContainsKey(aspect)) { existingAspects.Add(aspect, extractedAspects[aspect]); } } existing.FromMetadata(existingAspects); extracted.FromMetadata(extractedAspects); existing.MergeWith(extracted, true); existing.SetMetadata(existingAspects); return(true); } //Merge if (providerResourceAspects.Where(p => p.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_STUB).Any() || existingProviderResourceAspects.Where(p => p.GetAttributeValue <int>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_STUB).Any()) { MediaItemAspect.SetAttribute(existingAspects, MediaAspect.ATTR_ISVIRTUAL, false); MediaItemAspect.SetAttribute(existingAspects, MediaAspect.ATTR_ISSTUB, true); if (!ResourceAspectMerger.MergeVideoResourceAspects(extractedAspects, existingAspects)) { return(false); } } } existing.FromMetadata(existingAspects); extracted.FromMetadata(extractedAspects); existing.MergeWith(extracted, true); existing.SetMetadata(existingAspects); if (!ResourceAspectMerger.MergeVideoResourceAspects(extractedAspects, existingAspects)) { return(false); } 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("MovieMergeHandler: Exception merging resources (Text: '{0}')", e.Message); return(false); } }
private async Task <bool> ExtractMovieData(ILocalFsResourceAccessor lfsra, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData) { // VideoAspect must be present to be sure it is actually a video resource. if (!extractedAspectData.ContainsKey(VideoAspect.ASPECT_ID) && !extractedAspectData.ContainsKey(SubtitleAspect.ASPECT_ID)) { return(false); } // Calling EnsureLocalFileSystemAccess not necessary; only string operation string[] pathsToTest = new[] { lfsra.LocalFileSystemPath, lfsra.CanonicalLocalResourcePath.ToString() }; string title = null; string sortTitle = null; bool isReimport = extractedAspectData.ContainsKey(ReimportAspect.ASPECT_ID); MovieInfo movieInfo = new MovieInfo(); if (extractedAspectData.ContainsKey(MovieAspect.ASPECT_ID)) { movieInfo.FromMetadata(extractedAspectData); } if (movieInfo.MovieName.IsEmpty) { //Try to get title if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) && !string.IsNullOrEmpty(title) && !lfsra.ResourceName.StartsWith(title, StringComparison.InvariantCultureIgnoreCase)) { //The title may still contain tags and other noise, try and parse it for a title and year. MovieNameMatcher.MatchTitleYear(title, movieInfo); } } if (movieInfo.MovieNameSort.IsEmpty) { //Try to get sort title if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, out sortTitle) && !string.IsNullOrEmpty(sortTitle)) { movieInfo.MovieNameSort = sortTitle; } } if (!isReimport) //Ignore tags or file based information for reimport because they might be the cause of the wrong import { if (movieInfo.MovieDbId == 0) { try { // Try to use an existing TMDB id for exact mapping string tmdbId = await MatroskaMatcher.TryMatchTmdbIdAsync(lfsra).ConfigureAwait(false); if (!string.IsNullOrEmpty(tmdbId)) { movieInfo.MovieDbId = Convert.ToInt32(tmdbId); } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading TMDB ID for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } if (string.IsNullOrEmpty(movieInfo.ImdbId)) { try { // Try to use an existing IMDB id for exact mapping string imdbId = await MatroskaMatcher.TryMatchImdbIdAsync(lfsra).ConfigureAwait(false); if (!string.IsNullOrEmpty(imdbId)) { movieInfo.ImdbId = imdbId; } else if (pathsToTest.Any(path => ImdbIdMatcher.TryMatchImdbId(path, out imdbId))) { movieInfo.ImdbId = imdbId; } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading IMDB ID for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } if (!movieInfo.IsBaseInfoPresent || !movieInfo.ReleaseDate.HasValue) { // Also test the full path year. This is useful if the path contains the real name and year. foreach (string path in pathsToTest) { if (MovieNameMatcher.MatchTitleYear(path, movieInfo)) { break; } } //Fall back to MediaAspect.ATTR_TITLE if (movieInfo.MovieName.IsEmpty && !string.IsNullOrEmpty(title)) { movieInfo.MovieName = title; } /* Clear the names from unwanted strings */ MovieNameMatcher.CleanupTitle(movieInfo); } if (!movieInfo.ReleaseDate.HasValue && !movieInfo.HasExternalId) { // When searching movie title, the year can be relevant for multiple titles with same name but different years DateTime recordingDate; if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, out recordingDate)) { movieInfo.ReleaseDate = recordingDate; } } try { await MatroskaMatcher.ExtractFromTagsAsync(lfsra, movieInfo).ConfigureAwait(false); MP4Matcher.ExtractFromTags(lfsra, movieInfo); } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading tags for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } // Allow the online lookup to choose best matching language for metadata if (movieInfo.Languages.Count == 0) { IList <MultipleMediaItemAspect> audioAspects; if (MediaItemAspect.TryGetAspects(extractedAspectData, VideoAudioStreamAspect.Metadata, out audioAspects)) { foreach (MultipleMediaItemAspect aspect in audioAspects) { string language = (string)aspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE); if (!string.IsNullOrEmpty(language) && !movieInfo.Languages.Contains(language)) { movieInfo.Languages.Add(language); } } } } if (SkipOnlineSearches && !SkipFanArtDownload) { MovieInfo tempInfo = movieInfo.Clone(); if (await OnlineMatcherService.Instance.FindAndUpdateMovieAsync(tempInfo).ConfigureAwait(false)) { movieInfo.CopyIdsFrom(tempInfo); movieInfo.HasChanged = tempInfo.HasChanged; } } else if (!SkipOnlineSearches) { await OnlineMatcherService.Instance.FindAndUpdateMovieAsync(movieInfo).ConfigureAwait(false); } //Asign genre ids if (movieInfo.Genres.Count > 0) { IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>(); foreach (var genre in movieInfo.Genres) { if (!genre.Id.HasValue && converter.GetGenreId(genre.Name, GenreCategory.Movie, null, out int genreId)) { genre.Id = genreId; movieInfo.HasChanged = true; } } } //Send it to the videos section if (!SkipOnlineSearches && !movieInfo.HasExternalId) { return(false); } //Create custom collection (overrides online collection) MovieCollectionInfo collectionInfo = movieInfo.CloneBasicInstance <MovieCollectionInfo>(); string collectionName; if (string.IsNullOrEmpty(collectionInfo.NameId) && CollectionFolderHasFanArt(lfsra, out collectionName)) { collectionInfo = new MovieCollectionInfo(); collectionInfo.CollectionName = collectionName; if (!collectionInfo.CollectionName.IsEmpty) { movieInfo.CollectionName = collectionInfo.CollectionName; movieInfo.CopyIdsFrom(collectionInfo); //Reset ID's movieInfo.HasChanged = true; } } if (movieInfo.MovieNameSort.IsEmpty) { if (!movieInfo.CollectionName.IsEmpty && movieInfo.ReleaseDate.HasValue) { movieInfo.MovieNameSort = $"{movieInfo.CollectionName.Text} {movieInfo.ReleaseDate.Value.Year}-{movieInfo.ReleaseDate.Value.Month.ToString("00")}"; } else if (!movieInfo.MovieName.IsEmpty) { movieInfo.MovieNameSort = BaseInfo.GetSortTitle(movieInfo.MovieName.Text); } else { movieInfo.MovieNameSort = BaseInfo.GetSortTitle(title); } } movieInfo.SetMetadata(extractedAspectData); return(movieInfo.IsBaseInfoPresent); }
public bool TryExtractRelationships(IDictionary <Guid, IList <MediaItemAspect> > aspects, bool importOnly, out IList <RelationshipItem> extractedLinkedAspects) { extractedLinkedAspects = null; if (importOnly) { return(false); } if (MovieMetadataExtractor.OnlyLocalMedia) { return(false); } MovieCollectionInfo collectionInfo = new MovieCollectionInfo(); if (!collectionInfo.FromMetadata(aspects)) { return(false); } if (CheckCacheContains(collectionInfo)) { return(false); } if (!MovieMetadataExtractor.SkipOnlineSearches && collectionInfo.HasExternalId) { OnlineMatcherService.Instance.UpdateCollection(collectionInfo, true, importOnly); } if (collectionInfo.Movies.Count == 0) { return(false); } if (BaseInfo.CountRelationships(aspects, LinkedRole) < collectionInfo.Movies.Count) { collectionInfo.HasChanged = true; //Force save for new movies } else { return(false); } if (!collectionInfo.HasChanged) { return(false); } AddToCheckCache(collectionInfo); extractedLinkedAspects = new List <RelationshipItem>(); for (int i = 0; i < collectionInfo.Movies.Count; i++) { MovieInfo movieInfo = collectionInfo.Movies[i]; movieInfo.CollectionNameId = collectionInfo.NameId; IDictionary <Guid, IList <MediaItemAspect> > movieAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); movieInfo.SetMetadata(movieAspects); MediaItemAspect.SetAttribute(movieAspects, MediaAspect.ATTR_ISVIRTUAL, true); if (movieAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { extractedLinkedAspects.Add(new RelationshipItem(movieAspects, Guid.Empty)); } } return(extractedLinkedAspects.Count > 0); }
private bool ExtractMovieData(ILocalFsResourceAccessor lfsra, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData, bool importOnly) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string[] pathsToTest = new[] { lfsra.LocalFileSystemPath, lfsra.CanonicalLocalResourcePath.ToString() }; string title = null; string sortTitle = null; // VideoAspect must be present to be sure it is actually a video resource. if (!extractedAspectData.ContainsKey(VideoStreamAspect.ASPECT_ID) && !extractedAspectData.ContainsKey(SubtitleAspect.ASPECT_ID)) { return(false); } if (extractedAspectData.ContainsKey(SubtitleAspect.ASPECT_ID) && !importOnly) { return(false); //Subtitles can only be imported not refreshed } bool refresh = false; if (extractedAspectData.ContainsKey(MovieAspect.ASPECT_ID)) { refresh = true; } MovieInfo movieInfo = new MovieInfo(); if (refresh) { movieInfo.FromMetadata(extractedAspectData); } if (movieInfo.MovieName.IsEmpty) { //Try to get title if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, out title) && !string.IsNullOrEmpty(title) && !lfsra.ResourceName.StartsWith(title, StringComparison.InvariantCultureIgnoreCase)) { movieInfo.MovieName = title; /* Clear the names from unwanted strings */ MovieNameMatcher.CleanupTitle(movieInfo); } } if (movieInfo.MovieNameSort.IsEmpty) { //Try to get sort title if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_SORT_TITLE, out sortTitle) && !string.IsNullOrEmpty(sortTitle)) { movieInfo.MovieNameSort = sortTitle; } } if (movieInfo.MovieDbId == 0) { try { // Try to use an existing TMDB id for exact mapping string tmdbId; if (MatroskaMatcher.TryMatchTmdbId(lfsra, out tmdbId)) { movieInfo.MovieDbId = Convert.ToInt32(tmdbId); } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading TMDB ID for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } if (string.IsNullOrEmpty(movieInfo.ImdbId)) { try { // Try to use an existing IMDB id for exact mapping string imdbId = null; if (pathsToTest.Any(path => MatroskaMatcher.TryMatchImdbId(lfsra, out imdbId))) { movieInfo.ImdbId = imdbId; } else if (pathsToTest.Any(path => ImdbIdMatcher.TryMatchImdbId(path, out imdbId))) { movieInfo.ImdbId = imdbId; } } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading IMDB ID for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } if (!movieInfo.IsBaseInfoPresent) { // Also test the full path year. This is useful if the path contains the real name and year. foreach (string path in pathsToTest) { if (MovieNameMatcher.MatchTitleYear(path, movieInfo)) { break; } } //Fall back to MediaAspect.ATTR_TITLE if (movieInfo.MovieName.IsEmpty && !string.IsNullOrEmpty(title)) { movieInfo.MovieName = title; } /* Clear the names from unwanted strings */ MovieNameMatcher.CleanupTitle(movieInfo); } if (!movieInfo.ReleaseDate.HasValue && !movieInfo.HasExternalId) { // When searching movie title, the year can be relevant for multiple titles with same name but different years DateTime recordingDate; if (MediaItemAspect.TryGetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, out recordingDate)) { movieInfo.ReleaseDate = recordingDate; } } // Allow the online lookup to choose best matching language for metadata if (movieInfo.Languages.Count == 0) { IList <MultipleMediaItemAspect> audioAspects; if (MediaItemAspect.TryGetAspects(extractedAspectData, VideoAudioStreamAspect.Metadata, out audioAspects)) { foreach (MultipleMediaItemAspect aspect in audioAspects) { string language = (string)aspect.GetAttributeValue(VideoAudioStreamAspect.ATTR_AUDIOLANGUAGE); if (!string.IsNullOrEmpty(language) && !movieInfo.Languages.Contains(language)) { movieInfo.Languages.Add(language); } } } } if (importOnly) { try { MatroskaMatcher.ExtractFromTags(lfsra, movieInfo); MP4Matcher.ExtractFromTags(lfsra, movieInfo); } catch (Exception ex) { ServiceRegistration.Get <ILogger>().Debug("MoviesMetadataExtractor: Exception reading tags for '{0}'", ex, lfsra.CanonicalLocalResourcePath); } } if (SkipOnlineSearches && !SkipFanArtDownload) { MovieInfo tempInfo = movieInfo.Clone(); OnlineMatcherService.Instance.FindAndUpdateMovie(tempInfo, importOnly); movieInfo.CopyIdsFrom(tempInfo); movieInfo.HasChanged = tempInfo.HasChanged; } else if (!SkipOnlineSearches) { OnlineMatcherService.Instance.FindAndUpdateMovie(movieInfo, importOnly); } //Send it to the videos section if (!SkipOnlineSearches && !movieInfo.HasExternalId) { return(false); } if (importOnly) { //Create custom collection (overrides online collection) MovieCollectionInfo collectionInfo = movieInfo.CloneBasicInstance <MovieCollectionInfo>(); string collectionName; if (string.IsNullOrEmpty(collectionInfo.NameId) && CollectionFolderHasFanArt(lfsra, out collectionName)) { collectionInfo = new MovieCollectionInfo(); collectionInfo.CollectionName = collectionName; if (!collectionInfo.CollectionName.IsEmpty) { movieInfo.CollectionName = collectionInfo.CollectionName; movieInfo.CopyIdsFrom(collectionInfo); //Reset ID's movieInfo.HasChanged = true; } } } movieInfo.AssignNameId(); if (refresh) { if ((IncludeActorDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_ACTOR) && movieInfo.Actors.Count > 0) || (IncludeCharacterDetails && !BaseInfo.HasRelationship(extractedAspectData, CharacterAspect.ROLE_CHARACTER) && movieInfo.Characters.Count > 0) || (IncludeDirectorDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_DIRECTOR) && movieInfo.Directors.Count > 0) || (IncludeWriterDetails && !BaseInfo.HasRelationship(extractedAspectData, PersonAspect.ROLE_WRITER) && movieInfo.Writers.Count > 0) || (IncludeProductionCompanyDetails && !BaseInfo.HasRelationship(extractedAspectData, CompanyAspect.ROLE_COMPANY) && movieInfo.ProductionCompanies.Count > 0)) { movieInfo.HasChanged = true; } } if (!movieInfo.HasChanged && !importOnly) { return(false); } movieInfo.SetMetadata(extractedAspectData); return(movieInfo.IsBaseInfoPresent); }