Читать APEv2 mp3 тег с TagLibSharp?

СЦЕНАРИЙ


Я обычно использую приложение MP3Gain, чтобы установить усиление воспроизведения mp3-файлов.

Приложение может создать следующие поля в теге APEv2 mp3-файлов:

введите описание изображения здесь

(скриншот взят из плеера WinAmp)

ВОПРОС


С библиотекой TagLibSharp я написал парсер ID3v1 и ID3v2, теперь мне интересно, смогу ли я читать и писать упомянутые поля APEv2, используя эту библиотеку?.

ИССЛЕДОВАНИЕ


Я думаю, что приложение MP3Gain использует уникальные имена для полей, поэтому, вероятно, TagLibsharp не поддерживает их, однако библиотека TagLibsharp имеет ReadBlock(), Removeblock(), Find() а также RFind() методы, для которых я думаю, это то, что мне нужно использовать, но я не знаю точно, как использовать их в сочетании...

Это единственное, что у меня есть:

Dim file As New TagLib.Mpeg.AudioFile("C:\input.mp3")
Dim data As Byte() = Encoding.ASCII.GetBytes("MP3GAIN_MINMAX")
Dim vector As New ByteVector(data)
Dim offset As Long = file.Find(vector)

И это псевдокод, написанный на Vb.Net только для демонстрации ожидаемой абстракции или поведения.

Imports TagLib

Public NotInheritable Class Mp3File

    Private tagFile As Global.TagLib.Mpeg.AudioFile

    Public ReadOnly Property APEv2 As APEv2Tag
        Get
            Return Me.apeTagB
        End Get
    End Property
    Private ReadOnly apeTagB As APEv2Tag

    Public Sub New(ByVal file As FileInfo)
        Me.tagFile = New Global.TagLib.Mpeg.AudioFile(file.FullName)
        Me.apeTagB = New APEv2Tag(Me.tagFile)
    End Sub

End Class

''' <summary>
''' Represents the APEv2 tag for a MP3 file.
''' </summary>
Public Class APEv2Tag

    Protected ReadOnly mp3File As Global.TagLib.Mpeg.AudioFile

    Public Sub New(ByVal mp3File As Global.TagLib.Mpeg.AudioFile)
        Me.mp3File = mp3File
    End Sub

    Public Overridable Property MP3GAIN_MINMAX As Double
        Get
            If field exists then...
                Return TheValue...
            End If
        End Get
        Set(ByVal value As Double)
            ...
        End Set
    End Property

    ' More properties here...

End Class

ОБНОВИТЬ:

Я думаю, что я, наконец, закончил часть "Чтение", однако я не уверен, как записать блоки, потому что, если поле не существует, я могу перезаписать / повредить файл...

    ''' ----------------------------------------------------------------------------------------------------
    ''' <summary>
    ''' Gets the <c>MP3GAIN_MINMAX</c> metatada field of the audio file.
    ''' </summary>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <returns>
    ''' The <c>MP3GAIN_MINMAX</c> field value.
    ''' </returns>
    ''' ----------------------------------------------------------------------------------------------------
    <DebuggerStepThrough>
    Private Function GetFieldMP3GainMinMax() As String

        Dim data As Byte() = Encoding.UTF8.GetBytes("MP3GAIN_MINMAX")
        Dim vector As New ByteVector(data)
        Dim offset As Long = Me.mp3File.Find(vector)
        Dim result As String

        If (offset = -1) Then
            Return String.Empty

        Else
            Try
                offset += ("MP3GAIN_MINMAX".Length + 1)
                Me.mp3File.Seek(offset, SeekOrigin.Begin)
                result = Me.mp3File.ReadBlock(8).ToString.TrimEnd()
                Return result

            Catch ex As Exception
                Throw

            Finally
                Me.mp3File.Seek(0, SeekOrigin.Begin)

            End Try

        End If

    End Function

    ''' ----------------------------------------------------------------------------------------------------
    ''' <summary>
    ''' Gets the <c>MP3GAIN_UNDO</c> metatada field of the audio file.
    ''' </summary>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <returns>
    ''' The <c>MP3GAIN_UNDO</c> field value.
    ''' </returns>
    ''' ----------------------------------------------------------------------------------------------------
    <DebuggerStepThrough>
    Private Function GetFieldMP3GainUndo() As String

        Dim data As Byte() = Encoding.UTF8.GetBytes("MP3GAIN_UNDO")
        Dim vector As New ByteVector(data)
        Dim offset As Long = Me.mp3File.Find(vector)
        Dim result As String

        If (offset = -1) Then
            Return String.Empty

        Else
            Try
                offset += ("MP3GAIN_UNDO".Length + 1)
                Me.mp3File.Seek(offset, SeekOrigin.Begin)
                result = Me.mp3File.ReadBlock(12).ToString.TrimEnd()
                Return result

            Catch ex As Exception
                Throw

            Finally
                Me.mp3File.Seek(0, SeekOrigin.Begin)

            End Try

        End If

    End Function

    ''' ----------------------------------------------------------------------------------------------------
    ''' <summary>
    ''' Gets the <c>REPLAYGAIN_TRACK_GAIN</c> metatada field of the audio file.
    ''' </summary>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <returns>
    ''' The <c>REPLAYGAIN_TRACK_GAIN</c> field value.
    ''' </returns>
    ''' ----------------------------------------------------------------------------------------------------
    <DebuggerStepThrough>
    Private Function GetFieldReplayGainTrackGain() As String

        Dim data As Byte() = Encoding.UTF8.GetBytes("REPLAYGAIN_TRACK_GAIN")
        Dim vector As New ByteVector(data)
        Dim offset As Long = Me.mp3File.Find(vector)
        Dim result As String

        If (offset = -1) Then
            Return String.Empty

        Else
            Try
                offset += ("REPLAYGAIN_TRACK_GAIN".Length + 1)
                Me.mp3File.Seek(offset, SeekOrigin.Begin)
                result = Me.mp3File.ReadBlock(12).ToString.TrimEnd()
                Return result

            Catch ex As Exception
                Throw

            Finally
                Me.mp3File.Seek(0, SeekOrigin.Begin)

            End Try

        End If

    End Function

    ''' ----------------------------------------------------------------------------------------------------
    ''' <summary>
    ''' Gets the <c>REPLAYGAIN_TRACK_PEAK</c> metatada field of the audio file.
    ''' </summary>
    ''' ----------------------------------------------------------------------------------------------------
    ''' <returns>
    ''' The <c>REPLAYGAIN_TRACK_PEAK</c> field value.
    ''' </returns>
    ''' ----------------------------------------------------------------------------------------------------
    <DebuggerStepThrough>
    Private Function GetFieldReplayGainTrackPeak() As String

        Dim data As Byte() = Encoding.UTF8.GetBytes("REPLAYGAIN_TRACK_PEAK")
        Dim vector As New ByteVector(data)
        Dim offset As Long = Me.mp3File.Find(vector)
        Dim result As String

        If (offset = -1) Then
            Return String.Empty

        Else
            Try
                offset += ("REPLAYGAIN_TRACK_PEAK".Length + 1)
                Me.mp3File.Seek(offset, SeekOrigin.Begin)
                result = Me.mp3File.ReadBlock(8).ToString.TrimEnd()
                Return result

            Catch ex As Exception
                Throw

            Finally
                Me.mp3File.Seek(0, SeekOrigin.Begin)

            End Try

        End If

    End Function

1 ответ

Решение

Процесс получения APEv2-специфичной информации из файла TagLib# аналогичен процессу для тега ID3v2, описанному в этом ответе.

Вот как прочитать значение:

// Get the APEv2 tag if it exists.
TagLib.Ape.Tag ape_tag = (TagLib.Ape.Tag)file.GetTag(TagLib.TagTypes.Ape, false);

if(ape_tag != null) {

    // Get the item.
    TagLib.Ape.Item item = ape_tag.GetItem("MP3GAIN_MINMAX");

    if (item != null) {
        Console.Log(item.ToStringArray());
    }
}

Я не уверен из скриншота, является ли поле одной строкой или двумя показанными строками, соединенными запятой.

Сохранение будет в обратном направлении, но немного проще:

// Get the APEv2 tag if it exists.
TagLib.Ape.Tag ape_tag = (TagLib.Ape.Tag)file.GetTag(TagLib.TagTypes.Ape, true);

if(ape_tag != null) {
    ape_tag.SetValue("MP3GAIN_MINMAX", value);
}

file.Save();

Пример для Vb.Net:

Поля:

ReadOnly mp3File As Global.TagLib.Mpeg.AudioFile = ...

Свойства (связанные с MP3Gain):

Property MP3GainMinMax As String
    Get
        Return Me.GetField("MP3GAIN_MINMAX")
    End Get
    Set(ByVal value As String)
        Me.SetField("MP3GAIN_MINMAX", value)
    End Set
End Property

Property MP3GainUndo As String
    Get
        Return Me.GetField("MP3GAIN_UNDO")
    End Get
    Set(ByVal value As String)
        Me.SetField("MP3GAIN_UNDO", value)
    End Set
End Property

Property ReplayGainTrackGain As String
    Get
        Return Me.GetField("REPLAYGAIN_TRACK_GAIN")
    End Get
    Set(ByVal value As String)
        Me.SetField("REPLAYGAIN_TRACK_GAIN", value)
    End Set
End Property

Property ReplayGainTrackPeak As String
    Get
        Return Me.GetField("REPLAYGAIN_TRACK_PEAK")
    End Get
    Set(ByVal value As String)
        Me.SetField("REPLAYGAIN_TRACK_PEAK", value)
    End Set
End Property

Функция "Получить":

Function GetField(ByVal fieldName As String) As String

    Dim apeTag As TagLib.Ape.Tag =
        DirectCast(Me.mp3File.GetTag(TagTypes.Ape, create:=False), TagLib.Ape.Tag)

    If (apeTag IsNot Nothing) Then
        Dim item As TagLib.Ape.Item = apeTag.GetItem(fieldName)

        If (item IsNot Nothing) Then
            Return item.ToString()
        End If
    End If

    Return String.Empty

End Function

Метод "Установить":

Sub SetField(ByVal fieldName As String, ByVal value As String)

    Dim apeTag As TagLib.Ape.Tag = 
        DirectCast(Me.mp3File.GetTag(TagTypes.Ape, create:=True), TagLib.Ape.Tag)

    apeTag.SetValue(fieldName, value)

End Sub
Другие вопросы по тегам