public static void SetCustomField(this File tagFile, string key, string value) { if (tagFile.GetTag(TagTypes.Id3v2) is Tag id3V2Tag) { UserTextInformationFrame userTextInformationFrame = UserTextInformationFrame.Get(id3V2Tag, key, StringType.UTF8, true, true); if (string.IsNullOrEmpty(value)) { id3V2Tag.RemoveFrame(userTextInformationFrame); } else { userTextInformationFrame.Text = value.Split(';'); } } else if (tagFile.GetTag(TagTypes.Xiph) is XiphComment xiphComment) { xiphComment.SetField(key.ToUpperInvariant(), value); } else { throw new ArgumentException(nameof(tagFile)); } }
private void WriteId3Tag(TagLib.Id3v2.Tag tag, string id, string value) { var frame = UserTextInformationFrame.Get(tag, id, true); if (value.IsNotNullOrWhiteSpace()) { frame.Text = value.Split(';'); } else { tag.RemoveFrame(frame); } }
/// <summary> /// Attempt to write a private frame /// </summary> private bool TryWriteUserFrame(string name, string value) { try { TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)mp3File.GetTag(TagTypes.Id3v2, true); var userFrame = UserTextInformationFrame.Get(tag, name, true); userFrame.Text = value == null ? new string[] { string.Empty } : value.Split(';'); return(true); } catch { return(false); } }
/// <summary> /// Attempt to read a user frame /// </summary> private bool TryReadUserFrame(string name, out string value) { try { TagLib.Id3v2.Tag tag = (TagLib.Id3v2.Tag)mp3File.GetTag(TagTypes.Id3v2); var userFrame = UserTextInformationFrame.Get(tag, name, false); value = stringArrayToString(userFrame.Text); return(true); } catch { value = string.Empty; return(false); } }
public static string GetCustomField(this File tagFile, string key) { if (tagFile.GetTag(TagTypes.Id3v2) is Tag id3V2Tag) { UserTextInformationFrame userTextInformationFrame = UserTextInformationFrame.Get(id3V2Tag, key, StringType.UTF8, false, true); return(userTextInformationFrame != null?string.Join(';', userTextInformationFrame.Text) : null); } if (tagFile.GetTag(TagTypes.Xiph) is XiphComment xiphComment) { return(xiphComment.GetFirstField(key.ToUpperInvariant())); } throw new ArgumentException(nameof(tagFile)); }
public void Read(string path) { Logger.Debug($"Starting tag read for {path}"); IsValid = false; TagLib.File file = null; try { file = TagLib.File.Create(path); var tag = file.Tag; Title = tag.Title ?? tag.TitleSort; Performers = tag.Performers ?? tag.PerformersSort; AlbumArtists = tag.AlbumArtists ?? tag.AlbumArtistsSort; Track = tag.Track; TrackCount = tag.TrackCount; Album = tag.Album ?? tag.AlbumSort; Disc = tag.Disc; DiscCount = tag.DiscCount; Year = tag.Year; Publisher = tag.Publisher; Duration = file.Properties.Duration; Genres = tag.Genres; ImageSize = tag.Pictures.FirstOrDefault()?.Data.Count ?? 0; MusicBrainzReleaseCountry = tag.MusicBrainzReleaseCountry; MusicBrainzReleaseStatus = tag.MusicBrainzReleaseStatus; MusicBrainzReleaseType = tag.MusicBrainzReleaseType; MusicBrainzReleaseId = tag.MusicBrainzReleaseId; MusicBrainzArtistId = tag.MusicBrainzArtistId; MusicBrainzReleaseArtistId = tag.MusicBrainzReleaseArtistId; MusicBrainzReleaseGroupId = tag.MusicBrainzReleaseGroupId; MusicBrainzTrackId = tag.MusicBrainzTrackId; DateTime tempDate; // Do the ones that aren't handled by the generic taglib implementation if (file.TagTypesOnDisk.HasFlag(TagTypes.Id3v2)) { var id3tag = (TagLib.Id3v2.Tag)file.GetTag(TagTypes.Id3v2); Media = id3tag.GetTextAsString("TMED"); Date = ReadId3Date(id3tag, "TDRC"); OriginalReleaseDate = ReadId3Date(id3tag, "TDOR"); MusicBrainzAlbumComment = UserTextInformationFrame.Get(id3tag, "MusicBrainz Album Comment", false)?.Text.ExclusiveOrDefault(); MusicBrainzReleaseTrackId = UserTextInformationFrame.Get(id3tag, "MusicBrainz Release Track Id", false)?.Text.ExclusiveOrDefault(); } else if (file.TagTypesOnDisk.HasFlag(TagTypes.Xiph)) { // while publisher is handled by taglib, it seems to be mapped to 'ORGANIZATION' and not 'LABEL' like Picard is // https://picard.musicbrainz.org/docs/mappings/ var flactag = (TagLib.Ogg.XiphComment)file.GetTag(TagLib.TagTypes.Xiph); Media = flactag.GetField("MEDIA").ExclusiveOrDefault(); Date = DateTime.TryParse(flactag.GetField("DATE").ExclusiveOrDefault(), out tempDate) ? tempDate : default(DateTime?); OriginalReleaseDate = DateTime.TryParse(flactag.GetField("ORIGINALDATE").ExclusiveOrDefault(), out tempDate) ? tempDate : default(DateTime?); Publisher = flactag.GetField("LABEL").ExclusiveOrDefault(); MusicBrainzAlbumComment = flactag.GetField("MUSICBRAINZ_ALBUMCOMMENT").ExclusiveOrDefault(); MusicBrainzReleaseTrackId = flactag.GetField("MUSICBRAINZ_RELEASETRACKID").ExclusiveOrDefault(); // If we haven't managed to read status/type, try the alternate mapping if (MusicBrainzReleaseStatus.IsNullOrWhiteSpace()) { MusicBrainzReleaseStatus = flactag.GetField("RELEASESTATUS").ExclusiveOrDefault(); } if (MusicBrainzReleaseType.IsNullOrWhiteSpace()) { MusicBrainzReleaseType = flactag.GetField("RELEASETYPE").ExclusiveOrDefault(); } } else if (file.TagTypesOnDisk.HasFlag(TagTypes.Ape)) { var apetag = (TagLib.Ape.Tag)file.GetTag(TagTypes.Ape); Media = apetag.GetItem("Media")?.ToString(); Date = DateTime.TryParse(apetag.GetItem("Year")?.ToString(), out tempDate) ? tempDate : default(DateTime?); OriginalReleaseDate = DateTime.TryParse(apetag.GetItem("Original Date")?.ToString(), out tempDate) ? tempDate : default(DateTime?); Publisher = apetag.GetItem("Label")?.ToString(); MusicBrainzAlbumComment = apetag.GetItem("MUSICBRAINZ_ALBUMCOMMENT")?.ToString(); MusicBrainzReleaseTrackId = apetag.GetItem("MUSICBRAINZ_RELEASETRACKID")?.ToString(); } else if (file.TagTypesOnDisk.HasFlag(TagTypes.Asf)) { var asftag = (TagLib.Asf.Tag)file.GetTag(TagTypes.Asf); Media = asftag.GetDescriptorString("WM/Media"); Date = DateTime.TryParse(asftag.GetDescriptorString("WM/Year"), out tempDate) ? tempDate : default(DateTime?); OriginalReleaseDate = DateTime.TryParse(asftag.GetDescriptorString("WM/OriginalReleaseTime"), out tempDate) ? tempDate : default(DateTime?); Publisher = asftag.GetDescriptorString("WM/Publisher"); MusicBrainzAlbumComment = asftag.GetDescriptorString("MusicBrainz/Album Comment"); MusicBrainzReleaseTrackId = asftag.GetDescriptorString("MusicBrainz/Release Track Id"); } else if (file.TagTypesOnDisk.HasFlag(TagTypes.Apple)) { var appletag = (TagLib.Mpeg4.AppleTag)file.GetTag(TagTypes.Apple); Media = appletag.GetDashBox("com.apple.iTunes", "MEDIA"); Date = DateTime.TryParse(appletag.DataBoxes(FixAppleId("day")).FirstOrDefault()?.Text, out tempDate) ? tempDate : default(DateTime?); OriginalReleaseDate = DateTime.TryParse(appletag.GetDashBox("com.apple.iTunes", "Original Date"), out tempDate) ? tempDate : default(DateTime?); MusicBrainzAlbumComment = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Album Comment"); MusicBrainzReleaseTrackId = appletag.GetDashBox("com.apple.iTunes", "MusicBrainz Release Track Id"); } OriginalYear = OriginalReleaseDate.HasValue ? (uint)OriginalReleaseDate?.Year : 0; foreach (ICodec codec in file.Properties.Codecs) { IAudioCodec acodec = codec as IAudioCodec; if (acodec != null && (acodec.MediaTypes & MediaTypes.Audio) != MediaTypes.None) { int bitrate = acodec.AudioBitrate; if (bitrate == 0) { // Taglib can't read bitrate for Opus. bitrate = EstimateBitrate(file, path); } Logger.Debug("Audio Properties: " + acodec.Description + ", Bitrate: " + bitrate + ", Sample Size: " + file.Properties.BitsPerSample + ", SampleRate: " + acodec.AudioSampleRate + ", Channels: " + acodec.AudioChannels); Quality = QualityParser.ParseQuality(file.Name, acodec.Description, bitrate, file.Properties.BitsPerSample); Logger.Debug($"Quality parsed: {Quality}, Source: {Quality.QualityDetectionSource}"); MediaInfo = new MediaInfoModel { AudioFormat = acodec.Description, AudioBitrate = bitrate, AudioChannels = acodec.AudioChannels, AudioBits = file.Properties.BitsPerSample, AudioSampleRate = acodec.AudioSampleRate }; } } IsValid = true; } catch (Exception ex) { if (ex is CorruptFileException) { Logger.Warn(ex, $"Tag reading failed for {path}. File is corrupt"); } else { // Log as error so it goes to sentry with correct fingerprint Logger.Error(ex, "Tag reading failed for {0}", path); } } finally { file?.Dispose(); } // make sure these are initialized to avoid errors later on if (Quality == null) { Quality = QualityParser.ParseQuality(path, null, EstimateBitrate(file, path)); Logger.Debug($"Unable to parse qulity from tag, Quality parsed from file path: {Quality}, Source: {Quality.QualityDetectionSource}"); } MediaInfo = MediaInfo ?? new MediaInfoModel(); }