public async Task <bool> TryExtractRelationshipsAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > aspects, IList <IDictionary <Guid, IList <MediaItemAspect> > > extractedLinkedAspects) { AlbumInfo albumInfo = new AlbumInfo(); if (!albumInfo.FromMetadata(aspects)) { return(false); } AudioMetadataExtractor.TryUpdateAlbum(mediaItemAccessor, albumInfo); if (AudioMetadataExtractor.IncludeArtistDetails && !AudioMetadataExtractor.SkipOnlineSearches) { await OnlineMatcherService.Instance.UpdateAlbumPersonsAsync(albumInfo, PersonAspect.OCCUPATION_ARTIST).ConfigureAwait(false); } foreach (PersonInfo person in albumInfo.Artists) { IDictionary <Guid, IList <MediaItemAspect> > personAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); if (person.SetMetadata(personAspects) && personAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { extractedLinkedAspects.Add(personAspects); } } return(extractedLinkedAspects.Count > 0); }
public MusicAlbumInfo(MediaItem mediaItem) { try { AlbumInfo album = new AlbumInfo(); album.FromMetadata(mediaItem.Aspects); ItemId = mediaItem.MediaItemId; Summery = album.Description.Text; Artist = String.Join(", ", album.Artists); Genre = String.Join(", ", album.Genres.Select(g => g.Name)); Disc = album.DiscNum; DiscTotal = album.TotalDiscs; Rating = Convert.ToString(album.Rating.RatingValue ?? 0); RatingCount = Convert.ToString(album.Rating.VoteCount ?? 0); Title = album.Album; TrackTotal = album.TotalTracks; Year = album.ReleaseDate.Value.Year; ImageName = Helper.GetImageBaseURL(mediaItem, FanArtMediaTypes.Album, FanArtTypes.Cover); } catch (Exception e) { ServiceRegistration.Get <ILogger>().Error("WifiRemote: Error getting album info", e); } }
public void CacheExtractedItem(Guid extractedItemId, IDictionary <Guid, IList <MediaItemAspect> > extractedAspects) { AlbumInfo album = new AlbumInfo(); album.FromMetadata(extractedAspects); AddToCache(extractedItemId, album, false); }
public async Task <bool> TryExtractRelationshipsAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > aspects, IList <IDictionary <Guid, IList <MediaItemAspect> > > extractedLinkedAspects) { TrackInfo trackInfo = new TrackInfo(); if (!trackInfo.FromMetadata(aspects)) { return(false); } AlbumInfo reimport = null; if (aspects.ContainsKey(ReimportAspect.ASPECT_ID)) { reimport = trackInfo.CloneBasicInstance <AlbumInfo>(); } IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData = extractedLinkedAspects.Count > 0 ? extractedLinkedAspects[0] : new Dictionary <Guid, IList <MediaItemAspect> >(); if (!await TryExtractAlbumMetadataAsync(mediaItemAccessor, extractedAspectData, reimport).ConfigureAwait(false)) { return(false); } AlbumInfo albumInfo = new AlbumInfo(); if (!albumInfo.FromMetadata(extractedAspectData)) { return(false); } IGenreConverter converter = ServiceRegistration.Get <IGenreConverter>(); foreach (var genre in albumInfo.Genres) { if (!genre.Id.HasValue && converter.GetGenreId(genre.Name, GenreCategory.Music, null, out int genreId)) { genre.Id = genreId; } } albumInfo.SetMetadata(extractedAspectData); if (!extractedAspectData.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { return(false); } bool trackVirtual; if (MediaItemAspect.TryGetAttribute(aspects, MediaAspect.ATTR_ISVIRTUAL, false, out trackVirtual)) { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_ISVIRTUAL, trackVirtual); } extractedLinkedAspects.Clear(); extractedLinkedAspects.Add(extractedAspectData); return(true); }
public override void Update(MediaItem mediaItem) { base.Update(mediaItem); if (mediaItem == null) { return; } AlbumInfo album = new AlbumInfo(); if (!album.FromMetadata(mediaItem.Aspects)) { return; } Album = album.Album ?? ""; Description = album.Description.Text ?? ""; int?count; if (mediaItem.Aspects.ContainsKey(AudioAlbumAspect.ASPECT_ID)) { if (MediaItemAspect.TryGetAttribute(mediaItem.Aspects, AudioAlbumAspect.ATTR_AVAILABLE_TRACKS, out count)) { AvailableTracks = count.Value.ToString(); } else { AvailableTracks = ""; } if (MediaItemAspect.TryGetAttribute(mediaItem.Aspects, AudioAlbumAspect.ATTR_NUMTRACKS, out count)) { TotalTracks = count.Value.ToString(); } else { TotalTracks = ""; } if (VirtualMediaHelper.ShowVirtualAudioMedia) { Tracks = string.IsNullOrEmpty(TotalTracks) ? AvailableTracks : TotalTracks; } else { Tracks = AvailableTracks; } } FireChange(); }
public bool TryMatch(IDictionary <Guid, IList <MediaItemAspect> > extractedAspects, IDictionary <Guid, IList <MediaItemAspect> > existingAspects) { if (existingAspects.ContainsKey(AudioAlbumAspect.ASPECT_ID)) { AlbumInfo extracted = new AlbumInfo(); extracted.FromMetadata(extractedAspects); AlbumInfo existing = new AlbumInfo(); existing.FromMetadata(existingAspects); return(existing.Equals(extracted)); } return(false); }
/// <summary> /// Verifies if the album being reimported matches the album in the nfo file /// </summary> /// <param name="reader">Reader used read the album information from the nfo file</param> /// <param name="reimport">The album being reimported</param> /// <returns>Result of the verification</returns> protected bool VerifyAlbumReimport(NfoAlbumReader reader, AlbumInfo reimport) { if (reimport == null) { return(true); } IDictionary <Guid, IList <MediaItemAspect> > aspectData = new Dictionary <Guid, IList <MediaItemAspect> >(); if (reader.TryWriteMetadata(aspectData)) { AlbumInfo info = new AlbumInfo(); info.FromMetadata(aspectData); if (reimport.Equals(info)) { return(true); } } return(false); }
public IDictionary <Guid, IList <MediaItemAspect> > GetBaseChildAspectsFromExistingAspects(IDictionary <Guid, IList <MediaItemAspect> > existingChildAspects, IDictionary <Guid, IList <MediaItemAspect> > existingParentAspects) { if (existingParentAspects.ContainsKey(AudioAlbumAspect.ASPECT_ID)) { AlbumInfo album = new AlbumInfo(); album.FromMetadata(existingParentAspects); if (existingChildAspects.ContainsKey(AudioAspect.ASPECT_ID)) { TrackInfo track = new TrackInfo(); track.FromMetadata(existingChildAspects); TrackInfo basicTrack = album.CloneBasicInstance <TrackInfo>(); basicTrack.TrackNum = track.TrackNum; IDictionary <Guid, IList <MediaItemAspect> > aspects = new Dictionary <Guid, IList <MediaItemAspect> >(); basicTrack.SetMetadata(aspects, true); return(aspects); } } return(null); }
public async Task <bool> TryExtractRelationshipsAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <MediaItemAspect> > aspects, IList <IDictionary <Guid, IList <MediaItemAspect> > > extractedLinkedAspects) { AlbumInfo albumInfo = new AlbumInfo(); if (!albumInfo.FromMetadata(aspects)) { return(false); } if (AudioMetadataExtractor.IncludeMusicLabelDetails && !AudioMetadataExtractor.SkipOnlineSearches) { await OnlineMatcherService.Instance.UpdateAlbumCompaniesAsync(albumInfo, CompanyAspect.COMPANY_MUSIC_LABEL).ConfigureAwait(false); } foreach (CompanyInfo company in albumInfo.MusicLabels) { IDictionary <Guid, IList <MediaItemAspect> > companyAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); if (company.SetMetadata(companyAspects) && companyAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { extractedLinkedAspects.Add(companyAspects); } } return(extractedLinkedAspects.Count > 0); }
public bool TryExtractRelationships(IDictionary <Guid, IList <MediaItemAspect> > aspects, bool importOnly, out IList <RelationshipItem> extractedLinkedAspects) { extractedLinkedAspects = null; if (!AudioMetadataExtractor.IncludeArtistDetails) { return(false); } AlbumInfo albumInfo = new AlbumInfo(); if (!albumInfo.FromMetadata(aspects)) { return(false); } if (CheckCacheContains(albumInfo)) { return(false); } UpdatePersons(aspects, albumInfo.Artists, true); int count = 0; if (!AudioMetadataExtractor.SkipOnlineSearches) { OnlineMatcherService.Instance.UpdateAlbumPersons(albumInfo, PersonAspect.OCCUPATION_ARTIST, importOnly); count = albumInfo.Artists.Where(p => p.HasExternalId).Count(); if (!albumInfo.IsRefreshed) { albumInfo.HasChanged = true; //Force save to update external Ids for metadata found by other MDEs } } else { count = albumInfo.Artists.Where(p => !string.IsNullOrEmpty(p.Name)).Count(); } if (albumInfo.Artists.Count == 0) { return(false); } if (BaseInfo.CountRelationships(aspects, LinkedRole) < count || (BaseInfo.CountRelationships(aspects, LinkedRole) == 0 && albumInfo.Artists.Count > 0)) { albumInfo.HasChanged = true; //Force save if no relationship exists } if (!albumInfo.HasChanged && !importOnly) { return(false); } AddToCheckCache(albumInfo); extractedLinkedAspects = new List <RelationshipItem>(); foreach (PersonInfo person in albumInfo.Artists) { person.AssignNameId(); person.HasChanged = albumInfo.HasChanged; IDictionary <Guid, IList <MediaItemAspect> > personAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); person.SetMetadata(personAspects); if (personAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { Guid existingId; if (TryGetIdFromCache(person, out existingId)) { extractedLinkedAspects.Add(new RelationshipItem(personAspects, existingId)); } else { extractedLinkedAspects.Add(new RelationshipItem(personAspects, Guid.Empty)); } } } return(extractedLinkedAspects.Count > 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); } }
public bool TryExtractRelationships(IDictionary <Guid, IList <MediaItemAspect> > aspects, bool importOnly, out IList <RelationshipItem> extractedLinkedAspects) { extractedLinkedAspects = null; if (!AudioMetadataExtractor.IncludeMusicLabelDetails) { return(false); } if (importOnly) { return(false); } AlbumInfo albumInfo = new AlbumInfo(); if (!albumInfo.FromMetadata(aspects)) { return(false); } if (CheckCacheContains(albumInfo)) { return(false); } int count = 0; if (!AudioMetadataExtractor.SkipOnlineSearches) { OnlineMatcherService.Instance.UpdateAlbumCompanies(albumInfo, CompanyAspect.COMPANY_MUSIC_LABEL, importOnly); count = albumInfo.MusicLabels.Where(c => c.HasExternalId).Count(); if (!albumInfo.IsRefreshed) { albumInfo.HasChanged = true; //Force save to update external Ids for metadata found by other MDEs } } else { count = albumInfo.MusicLabels.Where(c => !string.IsNullOrEmpty(c.Name)).Count(); } if (albumInfo.MusicLabels.Count == 0) { return(false); } if (BaseInfo.CountRelationships(aspects, LinkedRole) < count || (BaseInfo.CountRelationships(aspects, LinkedRole) == 0 && albumInfo.MusicLabels.Count > 0)) { albumInfo.HasChanged = true; //Force save if no relationship exists } if (!albumInfo.HasChanged) { return(false); } AddToCheckCache(albumInfo); extractedLinkedAspects = new List <RelationshipItem>(); foreach (CompanyInfo company in albumInfo.MusicLabels) { company.AssignNameId(); company.HasChanged = albumInfo.HasChanged; IDictionary <Guid, IList <MediaItemAspect> > companyAspects = new Dictionary <Guid, IList <MediaItemAspect> >(); company.SetMetadata(companyAspects); if (companyAspects.ContainsKey(ExternalIdentifierAspect.ASPECT_ID)) { Guid existingId; if (TryGetIdFromCache(company, out existingId)) { extractedLinkedAspects.Add(new RelationshipItem(companyAspects, existingId)); } else { extractedLinkedAspects.Add(new RelationshipItem(companyAspects, Guid.Empty)); } } } return(extractedLinkedAspects.Count > 0); }