/// <summary> /// Initializes a new instance. /// </summary> private void Initialize() { Log.Debug("BassMODFileInputSource.Initialize()"); const BASSFlag flags = BASSFlag.BASS_SAMPLE_SOFTWARE | BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MUSIC_AUTOFREE | BASSFlag.BASS_MUSIC_PRESCAN; int handle; ILocalFsResourceAccessor lfra = _accessor as ILocalFsResourceAccessor; if (lfra == null) { // Build stream reading procs for the resource's input stream Stream inputStream = _accessor.OpenRead(); int length = (int)inputStream.Length; byte[] audioData = new byte[length]; inputStream.Read(audioData, 0, length); handle = Bass.BASS_MusicLoad(audioData, 0, length, flags, 0); } else { // Optimize access to local filesystem resource using (lfra.EnsureLocalFileSystemAccess()) handle = Bass.BASS_MusicLoad(lfra.LocalFileSystemPath, 0, 0, flags, 0); } if (handle == BassConstants.BassInvalidHandle) { throw new BassLibraryException("BASS_MusicLoad"); } _bassStream = BassStream.Create(handle); }
/// <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); }
private bool CollectionFolderHasFanArt(ILocalFsResourceAccessor lfsra, out string collectionName) { collectionName = null; // File based access try { using (lfsra.EnsureLocalFileSystemAccess()) { string collectionMediaItemDirectoryPath; if (Directory.GetParent(lfsra.LocalFileSystemPath) != null && Directory.GetParent(Directory.GetParent(lfsra.LocalFileSystemPath).FullName) != null) { DirectoryInfo dir = Directory.GetParent(Directory.GetParent(lfsra.LocalFileSystemPath).FullName); collectionMediaItemDirectoryPath = dir.FullName; collectionName = dir.Name; } else { return(false); } var potentialFanArtFiles = GetPotentialFanArtFiles(collectionMediaItemDirectoryPath); if ((from potentialFanArtFile in potentialFanArtFiles let potentialFanArtFileNameWithoutExtension = Path.GetFileNameWithoutExtension(potentialFanArtFile.ToString()).ToLowerInvariant() where potentialFanArtFileNameWithoutExtension == "poster" || potentialFanArtFileNameWithoutExtension == "folder" || potentialFanArtFileNameWithoutExtension == "keyart" || potentialFanArtFileNameWithoutExtension.StartsWith("backdrop") || potentialFanArtFileNameWithoutExtension.StartsWith("fanart") || potentialFanArtFileNameWithoutExtension == "banner" || potentialFanArtFileNameWithoutExtension.StartsWith("movieset-") select potentialFanArtFile).Count() > 0) { return(true); } string fanArtFolder = Path.Combine(collectionMediaItemDirectoryPath, "ExtraFanArt"); if (Directory.Exists(fanArtFolder)) { if (GetPotentialFanArtFiles(fanArtFolder).Count() > 0) { return(true); } } } } catch { } return(false); }
protected void ExtractThumbnailData(ILocalFsResourceAccessor lfsra, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { // In quick mode only allow thumbs taken from cache. bool cachedOnly = forceQuickMode; // Thumbnail extraction IThumbnailGenerator generator = ServiceRegistration.Get <IThumbnailGenerator>(); byte[] thumbData; ImageType imageType; using (lfsra.EnsureLocalFileSystemAccess()) if (generator.GetThumbnail(lfsra.LocalFileSystemPath, 256, 256, cachedOnly, out thumbData, out imageType)) { MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData); } }
public static bool ExtractFromTags(ILocalFsResourceAccessor folderOrFileLfsra, MovieInfo movieInfo) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(folderOrFileLfsra.LocalFileSystemPath)).ToUpper(); // Try to get extended information out of MP4 files) if (extensionUpper != ".MP4") { return(false); } using (folderOrFileLfsra.EnsureLocalFileSystemAccess()) { TagLib.File mp4File = TagLib.File.Create(folderOrFileLfsra.LocalFileSystemPath); if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null)) { return(false); } TagLib.Tag tag = mp4File.Tag; if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0) { List <GenreInfo> genreList = tag.Genres.Select(s => new GenreInfo { Name = s }).ToList(); OnlineMatcherService.Instance.AssignMissingMovieGenreIds(genreList); movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Genres, genreList, movieInfo.Genres.Count == 0); } if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0) { movieInfo.HasChanged |= MetadataUpdater.SetOrUpdateList(movieInfo.Actors, tag.Performers.Select(t => new PersonInfo() { Name = t, Occupation = PersonAspect.OCCUPATION_ACTOR, MediaName = movieInfo.MovieName.Text }).ToList(), false); } //Clean up memory mp4File.Dispose(); return(true); } }
protected void ExtractMp4Tags(ILocalFsResourceAccessor lfsra, IDictionary <Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(lfsra.LocalFileSystemPath)).ToUpper(); // Try to get extended information out of MP4 files) if (extensionUpper != ".MP4") { return; } using (lfsra.EnsureLocalFileSystemAccess()) { TagLib.File mp4File = TagLib.File.Create(lfsra.LocalFileSystemPath); if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null)) { return; } TagLib.Tag tag = mp4File.Tag; string title = tag.Title; if (!string.IsNullOrEmpty(title)) { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title); } int year = (int)tag.Year; if (year != 0) { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1)); } if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0) { MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_GENRES, tag.Genres); } if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0) { MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_ACTORS, tag.Performers); } } }
/// <summary> /// Tries to create a LocalResourceAccessor for the given <paramref name="metaFilePath"/> and to read the contents to match the IMDB id. /// </summary> /// <param name="metaFilePath">Path to file</param> /// <param name="imdbId">Returns a valid IMDB or <c>null</c></param> /// <returns>true if matched</returns> private static bool TryRead(string metaFilePath, out string imdbId) { imdbId = null; IResourceAccessor metaFileAccessor; if (!ResourcePath.Deserialize(metaFilePath).TryCreateLocalResourceAccessor(out metaFileAccessor)) { return(false); } using (metaFileAccessor) { ILocalFsResourceAccessor lfsra = metaFileAccessor as ILocalFsResourceAccessor; if (lfsra == null || !lfsra.Exists) { return(false); } string content; using (lfsra.EnsureLocalFileSystemAccess()) content = File.ReadAllText(lfsra.LocalFileSystemPath); return(ImdbIdMatcher.TryMatchImdbId(content, out imdbId)); } }
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); }
protected void ExtractThumbnailData(ILocalFsResourceAccessor lfsra, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { // In quick mode only allow thumbs taken from cache. bool cachedOnly = forceQuickMode; // Thumbnail extraction IThumbnailGenerator generator = ServiceRegistration.Get<IThumbnailGenerator>(); byte[] thumbData; ImageType imageType; using (lfsra.EnsureLocalFileSystemAccess()) if (generator.GetThumbnail(lfsra.LocalFileSystemPath, 256, 256, cachedOnly, out thumbData, out imageType)) MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, thumbData); }
protected void ExtractMp4Tags(ILocalFsResourceAccessor lfsra, IDictionary<Guid, MediaItemAspect> extractedAspectData, bool forceQuickMode) { // Calling EnsureLocalFileSystemAccess not necessary; only string operation string extensionUpper = StringUtils.TrimToEmpty(Path.GetExtension(lfsra.LocalFileSystemPath)).ToUpper(); // Try to get extended information out of MP4 files) if (extensionUpper != ".MP4") return; using (lfsra.EnsureLocalFileSystemAccess()) { TagLib.File mp4File = TagLib.File.Create(lfsra.LocalFileSystemPath); if (ReferenceEquals(mp4File, null) || ReferenceEquals(mp4File.Tag, null)) return; TagLib.Tag tag = mp4File.Tag; string title = tag.Title; if (!string.IsNullOrEmpty(title)) MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title); int year = (int)tag.Year; if (year != 0) MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_RECORDINGTIME, new DateTime(year, 1, 1)); if (!ReferenceEquals(tag.Genres, null) && tag.Genres.Length > 0) MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_GENRES, tag.Genres); if (!ReferenceEquals(tag.Performers, null) && tag.Performers.Length > 0) MediaItemAspect.SetCollectionAttribute(extractedAspectData, VideoAspect.ATTR_ACTORS, tag.Performers); } }
private Task <bool> ExtractThumbnailAsync(ILocalFsResourceAccessor lfsra, IDictionary <Guid, IList <MediaItemAspect> > extractedAspectData) { // We can only work on files and make sure this file was detected by a lower MDE before (title is set then). // VideoAspect must be present to be sure it is actually a video resource. if (!lfsra.IsFile || !extractedAspectData.ContainsKey(VideoStreamAspect.ASPECT_ID)) { return(Task.FromResult(false)); } //ServiceRegistration.Get<ILogger>().Info("OCVVideoThumbnailer: Evaluate {0}", lfsra.ResourceName); bool isPrimaryResource = false; IList <MultipleMediaItemAspect> resourceAspects; if (MediaItemAspect.TryGetAspects(extractedAspectData, ProviderResourceAspect.Metadata, out resourceAspects)) { foreach (MultipleMediaItemAspect pra in resourceAspects) { string accessorPath = (string)pra.GetAttributeValue(ProviderResourceAspect.ATTR_RESOURCE_ACCESSOR_PATH); ResourcePath resourcePath = ResourcePath.Deserialize(accessorPath); if (resourcePath.Equals(lfsra.CanonicalLocalResourcePath)) { if (pra.GetAttributeValue <int?>(ProviderResourceAspect.ATTR_TYPE) == ProviderResourceAspect.TYPE_PRIMARY) { isPrimaryResource = true; break; } } } } if (!isPrimaryResource) //Ignore subtitles { return(Task.FromResult(false)); } // Check for a reasonable time offset int defaultVideoOffset = 720; long videoDuration; double downscale = 2; // Reduces the video frame size to a half of original IList <MultipleMediaItemAspect> videoAspects; if (MediaItemAspect.TryGetAspects(extractedAspectData, VideoStreamAspect.Metadata, out videoAspects)) { if ((videoDuration = videoAspects[0].GetAttributeValue <long>(VideoStreamAspect.ATTR_DURATION)) > 0) { if (defaultVideoOffset > videoDuration * 1 / 3) { defaultVideoOffset = Convert.ToInt32(videoDuration * 1 / 3); } } double width = videoAspects[0].GetAttributeValue <int>(VideoStreamAspect.ATTR_WIDTH); double height = videoAspects[0].GetAttributeValue <int>(VideoStreamAspect.ATTR_HEIGHT); downscale = width / 256.0; //256 is max size of large thumbnail aspect } using (lfsra.EnsureLocalFileSystemAccess()) { using (VideoCapture capture = new VideoCapture()) { capture.Open(lfsra.LocalFileSystemPath); capture.PosMsec = defaultVideoOffset * 1000; using (var mat = capture.RetrieveMat()) { if (mat.Height > 0 && mat.Width > 0) { double width = mat.Width; double height = mat.Height; ServiceRegistration.Get <ILogger>().Debug("OCVVideoThumbnailer: Scaling thumbnail of size {1}x{2} for resource '{0}'", lfsra.LocalFileSystemPath, width, height); using (var scaledMat = mat.Resize(new OpenCvSharp.Size(width / downscale, height / downscale))) { var binary = scaledMat.ToBytes(); MediaItemAspect.SetAttribute(extractedAspectData, ThumbnailLargeAspect.ATTR_THUMBNAIL, binary); ServiceRegistration.Get <ILogger>().Info("OCVVideoThumbnailer: Successfully created thumbnail for resource '{0}'", lfsra.LocalFileSystemPath); } } else { ServiceRegistration.Get <ILogger>().Warn("OCVVideoThumbnailer: Failed to create thumbnail for resource '{0}'", lfsra.LocalFileSystemPath); } } } } return(Task.FromResult(true)); }
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); } }
public override async Task <bool> TryExtractMetadataAsync(IResourceAccessor mediaItemAccessor, IDictionary <Guid, IList <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); } if (extractedAspectData.ContainsKey(ReimportAspect.ASPECT_ID)) //Ignore for reimports because the tags might be the cause of the wrong match { 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; } } TrackInfo trackInfo = new TrackInfo(); if (extractedAspectData.ContainsKey(AudioAspect.ASPECT_ID)) { trackInfo.FromMetadata(extractedAspectData); } else { MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_TITLE, title); IList <MultipleMediaItemAspect> providerResourceAspect; if (MediaItemAspect.TryGetAspects(extractedAspectData, ProviderResourceAspect.Metadata, out providerResourceAspect)) { providerResourceAspect[0].SetAttribute(ProviderResourceAspect.ATTR_SIZE, fsra.Size); // Calling EnsureLocalFileSystemAccess not necessary; only string operation providerResourceAspect[0].SetAttribute(ProviderResourceAspect.ATTR_MIME_TYPE, "audio/" + Path.GetExtension(fsra.LocalFileSystemPath).Substring(1)); } MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_BITRATE, tags.bitrate); MediaItemAspect.SetAttribute(extractedAspectData, MediaAspect.ATTR_COMMENT, StringUtils.TrimToNull(tags.comment)); MediaItemAspect.SetAttribute(extractedAspectData, AudioAspect.ATTR_DURATION, (long)tags.duration); } if (!trackInfo.IsBaseInfoPresent) { trackInfo.TrackName = title; trackInfo.Album = StringUtils.TrimToNull(tags.album); if (trackNo.HasValue) { trackInfo.TrackNum = (int)trackNo.Value; } trackInfo.Artists = new List <PersonInfo>(); foreach (string artistName in ApplyAdditionalSeparator(artists)) { trackInfo.Artists.Add(new PersonInfo() { Name = artistName, Occupation = PersonAspect.OCCUPATION_ARTIST, ParentMediaName = trackInfo.Album, MediaName = trackInfo.TrackName }); } IEnumerable <string> albumArtists = SplitTagEnum(tags.albumartist); albumArtists = PatchID3v23Enumeration(albumArtists); trackInfo.AlbumArtists = new List <PersonInfo>(); foreach (string artistName in ApplyAdditionalSeparator(albumArtists)) { trackInfo.AlbumArtists.Add(new PersonInfo() { Name = artistName, Occupation = PersonAspect.OCCUPATION_ARTIST, ParentMediaName = trackInfo.Album, MediaName = trackInfo.TrackName }); } IEnumerable <string> composers = SplitTagEnum(tags.composer); composers = PatchID3v23Enumeration(composers); trackInfo.Composers = new List <PersonInfo>(); foreach (string composerName in ApplyAdditionalSeparator(composers)) { trackInfo.Composers.Add(new PersonInfo() { Name = composerName, Occupation = PersonAspect.OCCUPATION_COMPOSER, ParentMediaName = trackInfo.Album, MediaName = trackInfo.TrackName }); } IEnumerable <string> genres = SplitTagEnum(tags.genre); genres = PatchID3v23Enumeration(genres); trackInfo.Genres = ApplyAdditionalSeparator(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; } } int year; if (int.TryParse(tags.year, out year)) { if (year >= 30 && year <= 99) { year += 1900; } if (year >= 1930 && year <= 2030) { trackInfo.ReleaseDate = new DateTime(year, 1, 1); } } if (!trackInfo.HasThumbnail) { // 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 (MemoryStream result = new MemoryStream()) { cover.Save(result, ImageFormat.Jpeg); trackInfo.Thumbnail = result.ToArray(); trackInfo.HasChanged = true; } } // Decoding of invalid image data can fail, but main MediaItem is correct. catch { } } } } if (!SkipOnlineSearches && !forceQuickMode) { await OnlineMatcherService.Instance.FindAndUpdateTrackAsync(trackInfo).ConfigureAwait(false); } if (!trackInfo.HasChanged) { return(false); } trackInfo.SetMetadata(extractedAspectData); return(trackInfo.IsBaseInfoPresent); } 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); }
private void ReadFile(params ElementDescriptor[] elements) { IEnumerable <ElementDescriptor> wantedElements = elements; if (wantedElements.Count() > 0 && wantedElements.All(e => _elementsRead.Contains(e.Identifier.EncodedValue))) { return; } SortedSet <long> wantedElementPositions = new SortedSet <long>(); using (_lfsra.EnsureLocalFileSystemAccess()) using (var fs = new FileStream(_lfsra.LocalFileSystemPath, FileMode.Open, FileAccess.Read)) using (EbmlReader ebmlReader = new EbmlReader(fs)) { if (fs.Length == 0) { return; } try { while (ebmlReader.ReadNext()) { //Segment element contains all the data we need if (ebmlReader.ElementId == SegmentElement.Identifier) { ebmlReader.EnterContainer(); while (ebmlReader.ReadNext()) { //Find file position of relevant elements via seek heads if (ebmlReader.ElementId == SeekHeadElement.Identifier) { long elementOffset = ebmlReader.ElementPosition; var seekElements = ReadSeekHeads(ebmlReader); if (seekElements?.Count > 0) { //Find all the wanted or possible elements var availableSegments = seekElements.Select(a => a.Element); var newElements = wantedElements.Count() > 0 ? wantedElements.Intersect(availableSegments) : availableSegments.AsEnumerable(); if (newElements != null) { wantedElements = newElements; } //Find file positions of wanted elements foreach (var e in seekElements.Where(e => wantedElements.Any(n => n.Identifier == e.Element.Identifier))) { wantedElementPositions.Add(Convert.ToInt64(e.Position) + elementOffset); } } } else if (ShouldReadElement(ebmlReader.ElementId, wantedElements.ToArray())) { //Read wanted elements if (ebmlReader.ElementId == SegmentInfoElement.Identifier) { ReadInfo(ebmlReader); } else if (ebmlReader.ElementId == TagsElement.Identifier) { ReadTags(ebmlReader); } else if (ebmlReader.ElementId == TracksElement.Identifier) { ReadTracks(ebmlReader); } else if (ebmlReader.ElementId == AttachmentsElement.Identifier) { ReadAttachments(ebmlReader); } _elementsRead.Add(ebmlReader.ElementId.EncodedValue); } //All wanted elements read so exit if (wantedElements.Count() == 0 || wantedElements.All(e => _elementsRead.Contains(e.Identifier.EncodedValue))) { return; } //Skip to next position in file if possible wantedElementPositions.RemoveWhere(p => p < (fs.Position)); if (fs.Position < wantedElementPositions.FirstOrDefault()) { fs.Position = wantedElementPositions.First(); } //Exit if we reading past the file length if ((fs.Position + ebmlReader.ElementSize) >= fs.Length) { return; } } ebmlReader.LeaveContainer(); break; } //Exit if we reading past the file length if ((fs.Position + ebmlReader.ElementSize) >= fs.Length) { break; } } } catch (EbmlDataFormatException) { //Rest of the EBML seems to be invalid so ignore it ServiceRegistration.Get <ILogger>().Warn("MatroskaInfoReader: Matroska file '{0}' has invalid EBML elements", _lfsra.LocalFileSystemPath); } } }