From 0921b05e8ab8b01880b970c984cdea91d6244782 Mon Sep 17 00:00:00 2001 From: William Brockhus Date: Mon, 2 Oct 2023 11:00:11 +1100 Subject: [PATCH] feat(id3): support apple MVNM/MVIN frame --- .../TaggingFormats/Id3V2Test.cs | 48 +++++++++++++++++++ src/TaglibSharp/Id3v2/FrameFactory.cs | 5 +- src/TaglibSharp/Id3v2/FrameHeader.cs | 8 ++-- src/TaglibSharp/Id3v2/FrameTypes.cs | 2 + .../Id3v2/Frames/TextIdentificationFrame.cs | 4 +- 5 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/TaglibSharp.Tests/TaggingFormats/Id3V2Test.cs b/src/TaglibSharp.Tests/TaggingFormats/Id3V2Test.cs index b50ba7b3..9457dbba 100644 --- a/src/TaglibSharp.Tests/TaggingFormats/Id3V2Test.cs +++ b/src/TaglibSharp.Tests/TaggingFormats/Id3V2Test.cs @@ -1499,6 +1499,54 @@ public void TestUserTextInformationFrame () }); } + [Test] + public void TestMovementNameFrame () + { + ByteVector id = "MVNM"; + var frame = new TextInformationFrame (id) { + Text = val_mult + }; + + FrameTest (frame, 2, + delegate (Frame f, StringType e) { + (f as TextInformationFrame).TextEncoding = e; + }, + (d, v) => new TextInformationFrame (d, v), + + delegate (Frame f, string m) { + var g = (f as TextInformationFrame); + Assert.AreEqual (id, g.FrameId, m); + Assert.AreEqual (val_mult.Length, g.Text.Length, m); + for (int i = 0; i < val_mult.Length; i++) { + Assert.AreEqual (val_mult[i], g.Text[i], m); + } + }); + } + + [Test] + public void TestMovementNumberFrame () + { + ByteVector id = "MVIN"; + var frame = new TextInformationFrame (id) { + Text = val_mult + }; + + FrameTest (frame, 2, + delegate (Frame f, StringType e) { + (f as TextInformationFrame).TextEncoding = e; + }, + (d, v) => new TextInformationFrame (d, v), + + delegate (Frame f, string m) { + var g = (f as TextInformationFrame); + Assert.AreEqual (id, g.FrameId, m); + Assert.AreEqual (val_mult.Length, g.Text.Length, m); + for (int i = 0; i < val_mult.Length; i++) { + Assert.AreEqual (val_mult[i], g.Text[i], m); + } + }); + } + [Test] public void TestUniqueFileIdentifierFrame () { diff --git a/src/TaglibSharp/Id3v2/FrameFactory.cs b/src/TaglibSharp/Id3v2/FrameFactory.cs index 737805db..0bcdd2b1 100644 --- a/src/TaglibSharp/Id3v2/FrameFactory.cs +++ b/src/TaglibSharp/Id3v2/FrameFactory.cs @@ -216,7 +216,10 @@ public static Frame CreateFrame (ByteVector data, File file, ref int offset, byt if (header.FrameId == FrameType.TXXX) return new UserTextInformationFrame (data, position, header, version); - if (header.FrameId[0] == (byte)'T') + // Apple proprietary MVNM (Movement Name), MVIN (Movement Number) are in fact text frames. + if (header.FrameId[0] == (byte)'T' || + header.FrameId == "MVNM" || + header.FrameId == "MVIN") return new TextInformationFrame (data, position, header, version); // Involved People List (frames 4.4 in 2.3. in 2.4 this is a TIPL frame) diff --git a/src/TaglibSharp/Id3v2/FrameHeader.cs b/src/TaglibSharp/Id3v2/FrameHeader.cs index 3bd86854..16e05973 100644 --- a/src/TaglibSharp/Id3v2/FrameHeader.cs +++ b/src/TaglibSharp/Id3v2/FrameHeader.cs @@ -127,7 +127,7 @@ public struct FrameHeader /// /// /// If the data size is smaller than the size of a full - /// header, the data is just treated as a frame identifier + /// header, the data is just treated as a frame identifier /// and the remaining values are zeroed. /// /// @@ -381,7 +381,7 @@ static ReadOnlyByteVector ConvertId (ByteVector id, byte version, bool toVersion } static readonly ReadOnlyByteVector[,] version2_frames = - new ReadOnlyByteVector[59, 2] { + new ReadOnlyByteVector[61, 2] { { "BUF", "RBUF" }, { "CNT", "PCNT" }, { "COM", "COMM" }, @@ -440,7 +440,9 @@ static ReadOnlyByteVector ConvertId (ByteVector id, byte version, bool toVersion { "WCP", "WCOP" }, { "WPB", "WPUB" }, { "WXX", "WXXX" }, - { "XRV", "RVA2" } + { "XRV", "RVA2" }, + { "MVN", "MVNM" }, + { "MVI", "MVIN" } }; static readonly ReadOnlyByteVector[,] version3_frames = diff --git a/src/TaglibSharp/Id3v2/FrameTypes.cs b/src/TaglibSharp/Id3v2/FrameTypes.cs index 430810eb..170024bd 100644 --- a/src/TaglibSharp/Id3v2/FrameTypes.cs +++ b/src/TaglibSharp/Id3v2/FrameTypes.cs @@ -101,5 +101,7 @@ static class FrameType public static readonly ReadOnlyByteVector WPUB = "WPUB"; public static readonly ReadOnlyByteVector WXXX = "WXXX"; public static readonly ReadOnlyByteVector ETCO = "ETCO"; + public static readonly ReadOnlyByteVector MVNM = "MVNM"; // Movement Name + public static readonly ReadOnlyByteVector MVIN = "MVIN"; // Movement Number/Count } } diff --git a/src/TaglibSharp/Id3v2/Frames/TextIdentificationFrame.cs b/src/TaglibSharp/Id3v2/Frames/TextIdentificationFrame.cs index 48f0ec91..d5f558e4 100644 --- a/src/TaglibSharp/Id3v2/Frames/TextIdentificationFrame.cs +++ b/src/TaglibSharp/Id3v2/Frames/TextIdentificationFrame.cs @@ -875,7 +875,9 @@ protected void ParseRawData () FrameId == FrameType.TPE1 || FrameId == FrameType.TPE2 || FrameId == FrameType.TPE3 || - FrameId == FrameType.TPE4) { + FrameId == FrameType.TPE4 || + FrameId == FrameType.MVNM || + FrameId == FrameType.MVIN) { field_list.AddRange (value.Split ('/')); } else if (FrameId == FrameType.TCON) { while (value.Length > 1 && value[0] == '(') {