Manipulate UserDefined tag (TXXX frame) with Taglib-Sharp

nixda picture nixda · Aug 23, 2015 · Viewed 7k times · Source

Situation & Task

I have a large music collection and I want to clean their ID3V2 tags with PowerShell and taglip-sharp. Some tags like comment or encoding should be deleted while others like artist or title should not.

Usually you manipulate ID3 tags this way (Simplified version)

# Add taglib dll 
[Void][System.Reflection.Assembly]::LoadFrom("$PSScriptRoot\taglib-sharp.dll")

# Load example mp3 into memory as [taglib.file]
$media = [TagLib.File]::Create("C:\path\to\musicFile.mp3")

# Change comment tag 
$media.tag.tags[0].Comment = "Hello World"

# Save tags back to mp3 file
$Media.Save()

Problem

Many music files store custom information like URL or Shop Name in a frame called TXXX. Unfortunately, this frame is not accessible with the method shown above. Or I haven't found a way yet.

Instead you use

# Read UserTextInformationFrame
$media.GetTag([TagLib.TagTypes]::Id3v2).GetFrames("TXXX")

This User defined text information frame can hold multiple values. And some are useful since music players like Foobar store PERFORMER, DATE or replay_track_gain tags in TXXX.

Example output for the line above could be:

Description  : replaygain_track_gain
Text         : {-5.00 dB}
FieldList    : {-5.00 dB}
TextEncoding : Latin1
FrameId      : {84, 88, 88, 88}
Size         : 32
Flags        : None
GroupId      : -1
EncryptionId : -1

Description  : URL
Text         : {www.amazon.com}
FieldList    : {www.amazon.com}
TextEncoding : UTF16
FrameId      : {84, 88, 88, 88}
Size         : 43
Flags        : None
GroupId      : -1
EncryptionId : -1

After this, I was able to filter out all unnecessary TXXX values

# Create a whitelist of TXXX frames
$goodTXXX  = 'performer','replaygain_track_gain','date'

# Read UserTextInformationFrame AND filter it
$newTXXX = $Media.GetTag([TagLib.TagTypes]::Id3v2).GetFrames("TXXX") | 
  where { $goodTXXX -contains $_.Description }   

Question: How to write multiple values to TXXX frame

So my question is, how do I save my filtered results back to mp3 file?
My failed attempts were:

$media.GetTag([TagLib.TagTypes]::Id3v2).RemoveFrames("TXXX")
$media.GetTag([TagLib.TagTypes]::Id3v2).SetTextFrame("TXXX",$newTXXX)
# Removes old values, but does not show anything in Foobar

#$media.GetTag([TagLib.TagTypes]::Id3v2).GetFrames("TXXX").SetText("Hello World")
# Shows garbage in Foobar. And it's not usable for multiple values

Taglib-Sharp documentation for SetTextFrame


Bonus question: Is taglib-sharp able to strip out Id3v1 and ID3v2.4 tags while saving new tags as ID3v2.3 tags? (Related SO answer, but doesn't distinguish between v2.3 and v2.4)

Answer

nixda picture nixda · Aug 24, 2015

I found a way with try & error. It's not elegant since you have to remove all TXXX values and add them back if you just want to change a single one

# Add taglib dll 
[Void][System.Reflection.Assembly]::LoadFrom("$PSScriptRoot\taglib-sharp.dll")

# Load example mp3 into memory as [taglib.file]
$media = [TagLib.File]::Create("C:\path\to\musicFile.mp3")

# Get or create the ID3v2 tag.
[TagLib.Id3v2.Tag]$id3v2tag = $media.GetTag([TagLib.TagTypes]::Id3v2, 1)

# Create new 'TXXX frame' object
$TXXXFrame = [TagLib.Id3v2.UserTextInformationFrame]("WWW")

# Delete complete TXXX frame first, or else all values are just appended
$id3v2tag.RemoveFrames("TXXX")

# Set the value/text in the newly created TXXX frame, default Text encoding is UTF8
# Use curly brackets instead of single quotation marks
$TXXXFrame.Text = {www.myurl.com}

# Add TXXX frame to tag
$id3v2tag.AddFrame($TXXXFrame)

# Write all changed tags back to file
$media.Save()