id3v2

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 15, 2025 License: MIT Imports: 19 Imported by: 0

README

id3v2

Implementation of ID3 v2.3 and v2.4 in native Go.

This is a fork of https://github.com/n10v/id3v2/v2.
I'll try to keep this version up-to-date with the original library, but no promises.

Updates

  • Updated Go version support.
  • Added support for SYLT frames (synchronized lyrics/text).

All credit for the original library goes to Albert Nigmatzianov.

Installation

go get -u github.com/oshokin/id3v2

Documentation

Full documentation can be found at original project page.

Usage example

package main

import (
	"fmt"
	"log"

	"github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	defer tag.Close()

	// Read tags
	fmt.Println(tag.Artist())
	fmt.Println(tag.Title())

	// Set tags
	tag.SetArtist("Benjah")
	tag.SetTitle("All That I Need")

	// Add comment frame
	comment := id3v2.CommentFrame{
		Encoding:    id3v2.EncodingUTF8,
		Language:    "eng",
		Description: "My opinion",
		Text:        "I like this song!",
	}

	tag.AddCommentFrame(comment)

	// Write tag to file.mp3
	if err = tag.Save(); err != nil {
		log.Fatal("Error while saving a tag: ", err)
	}
}

Adding a SYLT Frame (Synchronized Lyrics/Text)

syltFrame := id3v2.SynchronisedLyricsFrame{
	Encoding:          id3v2.EncodingUTF8,
	Language:          "eng",
	TimestampFormat:   id3v2.SYLTAbsoluteMillisecondsTimestampFormat,
	ContentType:       id3v2.SYLTLyricsContentType,
	ContentDescriptor: "Lyrics",
	SynchronizedTexts: []id3v2.SyncedText{
		{Text: "Hello", Timestamp: 0},
		{Text: "world", Timestamp: 1000},
	},
}

tag.AddSynchronisedLyricsFrame(syltFrame)

Documentation

Overview

Package id3v2 provides functionality for reading, writing, and manipulating ID3v2 tags in MP3 files. ID3v2 tags are used to store metadata such as title, artist, album, and more in MP3 files. This library supports ID3v2.3 and ID3v2.4 tags, including text frames, picture frames, comments, and custom frames.

Example
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	// Open file and parse tag in it.
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}
	defer tag.Close()

	// Read frames.
	fmt.Println(tag.Artist())
	fmt.Println(tag.Title())

	// Set simple text frames.
	tag.SetArtist("Artist")
	tag.SetTitle("Title")

	// Set comment frame.
	comment := id3v2.CommentFrame{
		Encoding:    id3v2.EncodingUTF8,
		Language:    id3v2.EnglishISO6392Code,
		Description: "My opinion",
		Text:        "Very good song",
	}
	tag.AddCommentFrame(comment)

	// Write tag to file.
	if err = tag.Save(); err != nil {
		log.Fatal("Error while saving a tag: ", err)
	}
}
Example (Concurrent)
package main

import (
	"fmt"
	"log"
	"os"
	"sync"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tagPool := sync.Pool{New: func() any {
		return id3v2.NewEmptyTag()
	}}

	var wg sync.WaitGroup

	wg.Add(100)

	for range 100 {
		go func() {
			defer wg.Done()

			tag := tagPool.Get().(*id3v2.Tag)
			defer tagPool.Put(tag)

			file, err := os.Open("file.mp3")
			if err != nil {
				log.Fatal("Error while opening file:", err)
			}
			defer file.Close()

			if err := tag.Reset(file, id3v2.Options{Parse: true}); err != nil {
				log.Fatal("Error while reseting tag to file:", err)
			}

			fmt.Println(tag.Artist() + " - " + tag.Title())
		}()
	}

	wg.Wait()
}

Index

Examples

Constants

View Source
const (
	EnglishISO6392Code = "eng" // ISO 639-2 code for English.
	GermanISO6392Code  = "ger" // ISO 639-2 code for German.
)

Constants for commonly used ISO 639-2 language codes.

View Source
const (
	ArtistFrameDescription    = "Artist" // Description for the artist frame.
	SubtitleRefinementFrameID = "TIT3"   // ID for the subtitle refinement frame.
	TitleFrameDescription     = "Title"  // Description for the title frame.
	TitleFrameID              = "TIT2"   // ID for the title frame.
	UserDefinedTextFrameID    = "TXXX"   // ID for user-defined text frames.
)

Constants for commonly used frame descriptions and IDs.

View Source
const (
	PTOther                   = iota // Other type of image
	PTFileIcon                       // 32x32 PNG file icon
	PTOtherFileIcon                  // Other file icon
	PTFrontCover                     // Front cover image (e.g., album art)
	PTBackCover                      // Back cover image
	PTLeafletPage                    // Leaflet page (e.g., booklet)
	PTMedia                          // Media image (e.g., CD label)
	PTLeadArtistSoloist              // Lead artist or soloist image
	PTArtistPerformer                // Artist or performer image
	PTConductor                      // Conductor image
	PTBandOrchestra                  // Band or orchestra image
	PTComposer                       // Composer image
	PTLyricistTextWriter             // Lyricist or text writer image
	PTRecordingLocation              // Recording location image
	PTDuringRecording                // Image captured during recording
	PTDuringPerformance              // Image captured during performance
	PTMovieScreenCapture             // Movie or video screen capture
	PTBrightColouredFish             // Bright-colored fish image (used for testing)
	PTIllustration                   // Illustration image
	PTBandArtistLogotype             // Band or artist logotype
	PTPublisherStudioLogotype        // Publisher or studio logotype
)

Available picture types for picture frames (APIC frames). These constants define the type of image stored in the picture frame.

View Source
const (
	SYLTAbsoluteMpegFramesTimestampFormat   byte = iota + 1 // Timestamps are in MPEG frames.
	SYLTAbsoluteMillisecondsTimestampFormat                 // Timestamps are in milliseconds.
)

Constants for the timestamp format in a SYLT frame.

View Source
const (
	SYLTOtherContentType             = iota // The content type is unspecified or other.
	SYLTLyricsContentType                   // The content is lyrics.
	SYLTTextTranscriptionContentType        // The content is a text transcription.
	SYLTMovementContentType                 // The content describes movements (e.g., dance steps).
	SYLTEventsContentType                   // The content describes events (e.g., sound effects).
	SYLTChordContentType                    // The content is chord information.
	SYLTTriviaContentType                   // The content is trivia or additional information.
	SYLTWebpageURLsContentType              // The content contains URLs to webpages.
	SYLTImageURLsContentType                // The content contains URLs to images.
)

Constants for the content type in a SYLT frame.

View Source
const (
	// IgnoredOffset is a special value indicating that an offset should be ignored.
	IgnoredOffset = 0xFFFFFFFF
)

Variables

View Source
var (
	// V23CommonIDs maps human-readable descriptions to their corresponding frame IDs in ID3v2.3.
	// For example, "Album/Movie/Show title" maps to "TALB".
	V23CommonIDs = map[string]string{
		"Album/Movie/Show title":         "TALB",
		"Attached picture":               "APIC",
		"Band/Orchestra/Accompaniment":   "TPE2",
		"BPM":                            "TBPM",
		"Chapters":                       "CHAP",
		"Comments":                       "COMM",
		"Composer":                       "TCOM",
		"Conductor/performer refinement": "TPE3",
		"Content group description":      "TIT1",
		"Content type":                   "TCON",
		"Copyright message":              "TCOP",
		"Date":                           "TDAT",
		"Encoded by":                     "TENC",
		"File owner/licensee":            "TOWN",
		"File type":                      "TFLT",
		"Initial key":                    "TKEY",
		"Internet radio station name":    "TRSN",
		"Internet radio station owner":   "TRSO",
		"Interpreted, remixed, or otherwise modified by": "TPE4",
		"ISRC":     "TSRC",
		"Language": "TLAN",
		"Lead artist/Lead performer/Soloist/Performing group": "TPE1",
		"Length":                          "TLEN",
		"Lyricist/Text writer":            "TEXT",
		"Media type":                      "TMED",
		"Original album/movie/show title": "TOAL",
		"Original artist/performer":       "TOPE",
		"Original filename":               "TOFN",
		"Original lyricist/text writer":   "TOLY",
		"Original release year":           "TORY",
		"Part of a set":                   "TPOS",
		"Playlist delay":                  "TDLY",
		"Popularimeter":                   "POPM",
		"Publisher":                       "TPUB",
		"Recording dates":                 "TRDA",
		"Size":                            "TSIZ",
		"Software/Hardware and settings used for encoding": "TSSE",
		"Subtitle/Description refinement":                  SubtitleRefinementFrameID,
		"Synchronised lyrics/text":                         "SYLT",
		"Time":                                             "TIME",
		"Title/Songname/Content description":               TitleFrameID,
		"Track number/Position in set":                     "TRCK",
		"Unique file identifier":                           "UFID",
		"Unsynchronised lyrics/text transcription":         "USLT",
		"User defined text information frame":              UserDefinedTextFrameID,
		"Year":                                             "TYER",

		ArtistFrameDescription: "TPE1",
		"Genre":                "TCON",
		"Title":                TitleFrameID,
	}

	// V24CommonIDs maps human-readable descriptions to their corresponding frame IDs in ID3v2.4.
	// This includes additional frames and updated mappings for ID3v2.4.
	V24CommonIDs = map[string]string{
		"Album sort order":               "TSOA",
		"Album/Movie/Show title":         "TALB",
		"Attached picture":               "APIC",
		"Band/Orchestra/Accompaniment":   "TPE2",
		"BPM":                            "TBPM",
		"Chapters":                       "CHAP",
		"Comments":                       "COMM",
		"Composer":                       "TCOM",
		"Conductor/performer refinement": "TPE3",
		"Content group description":      "TIT1",
		"Content type":                   "TCON",
		"Copyright message":              "TCOP",
		"Encoded by":                     "TENC",
		"Encoding time":                  "TDEN",
		"File owner/licensee":            "TOWN",
		"File type":                      "TFLT",
		"Initial key":                    "TKEY",
		"Internet radio station name":    "TRSN",
		"Internet radio station owner":   "TRSO",
		"Interpreted, remixed, or otherwise modified by": "TPE4",
		"Involved people list":                           "TIPL",
		"ISRC":                                           "TSRC",
		"Language":                                       "TLAN",
		"Lead artist/Lead performer/Soloist/Performing group": "TPE1",
		"Length":                          "TLEN",
		"Lyricist/Text writer":            "TEXT",
		"Media type":                      "TMED",
		"Mood":                            "TMOO",
		"Musician credits list":           "TMCL",
		"Original album/movie/show title": "TOAL",
		"Original artist/performer":       "TOPE",
		"Original filename":               "TOFN",
		"Original lyricist/text writer":   "TOLY",
		"Original release time":           "TDOR",
		"Part of a set":                   "TPOS",
		"Performer sort order":            "TSOP",
		"Playlist delay":                  "TDLY",
		"Popularimeter":                   "POPM",
		"Produced notice":                 "TPRO",
		"Publisher":                       "TPUB",
		"Recording time":                  "TDRC",
		"Release time":                    "TDRL",
		"Set subtitle":                    "TSST",
		"Software/Hardware and settings used for encoding": "TSSE",
		"Subtitle/Description refinement":                  SubtitleRefinementFrameID,
		"Synchronised lyrics/text":                         "SYLT",
		"Tagging time":                                     "TDTG",
		"Title sort order":                                 "TSOT",
		"Title/Songname/Content description":               TitleFrameID,
		"Track number/Position in set":                     "TRCK",
		"Unique file identifier":                           "UFID",
		"Unsynchronised lyrics/text transcription":         "USLT",
		"User defined text information frame":              UserDefinedTextFrameID,

		"Date":                  "TDRC",
		"Original release year": "TDOR",
		"Recording dates":       "TDRC",
		"Size":                  "",
		"Time":                  "TDRC",
		"Year":                  "TDRC",

		ArtistFrameDescription: "TPE1",
		"Genre":                "TCON",
		"Title":                TitleFrameID,
	}
)

Common IDs for ID3v2.3 and ID3v2.4.

View Source
var (
	// EncodingISO is ISO-8859-1 encoding, commonly used in older ID3v2 tags.
	EncodingISO = Encoding{
		Name:             "ISO-8859-1",
		Key:              0,
		TerminationBytes: []byte{0},
	}

	// EncodingUTF16 is UTF-16 encoded Unicode with a Byte Order Mark (BOM).
	EncodingUTF16 = Encoding{
		Name:             "UTF-16 encoded Unicode with BOM",
		Key:              1,
		TerminationBytes: []byte{0, 0},
	}

	// EncodingUTF16BE is UTF-16BE encoded Unicode without a BOM.
	EncodingUTF16BE = Encoding{
		Name:             "UTF-16BE encoded Unicode without BOM",
		Key:              2,
		TerminationBytes: []byte{0, 0},
	}

	// EncodingUTF8 is UTF-8 encoded Unicode, the most widely used encoding.
	EncodingUTF8 = Encoding{
		Name:             "UTF-8 encoded Unicode",
		Key:              3,
		TerminationBytes: []byte{0},
	}
)

Available encodings supported by ID3v2.

View Source
var (
	// ErrSmallHeaderSize is returned when the size of the tag header is smaller than expected.
	ErrSmallHeaderSize = errors.New("size of tag header is less than expected")

	// ErrNoTag is returned when the file does not contain an ID3v2 tag.
	ErrNoTag = errors.New("there is no tag in file")
)
View Source
var (
	// ErrUnsupportedVersion is returned when the ID3v2 tag version is less than 3.
	ErrUnsupportedVersion = errors.New("unsupported version of ID3 tag")

	// ErrBodyOverflow is returned when a frame's size exceeds the remaining space in the tag.
	ErrBodyOverflow = errors.New("frame went over tag area")

	// ErrBlankFrame is returned when a frame's ID or size is empty or invalid.
	ErrBlankFrame = errors.New("id or size of frame are blank")
)
View Source
var (
	// ErrInvalidSizeFormat is returned when the size format of a tag or frame is invalid.
	ErrInvalidSizeFormat = errors.New("invalid format of tag's/frame's size")

	// ErrSizeOverflow is returned when the size of a tag or frame exceeds the maximum allowed size.
	ErrSizeOverflow = errors.New("size of tag/frame is greater than allowed in id3 tag")
)
View Source
var (
	ContentType = map[int]string{
		SYLTOtherContentType:             "Other",
		SYLTLyricsContentType:            "Lyrics",
		SYLTTextTranscriptionContentType: "Transcription",
		SYLTMovementContentType:          "Movement",
		SYLTEventsContentType:            "Events",
		SYLTChordContentType:             "Chord",
		SYLTTriviaContentType:            "Trivia",
		SYLTWebpageURLsContentType:       "WebpageUrls",
		SYLTImageURLsContentType:         "ImageUrls",
	}
)

ContentType maps content type constants to their human-readable descriptions. This is useful for debugging or displaying the content type in a user-friendly way.

View Source
var ErrInvalidLanguageLength = errors.New("language code must consist of three letters according to ISO 639-2")

ErrInvalidLanguageLength is returned when a language code does not meet the ISO 639-2 standard, which requires language codes to be exactly three letters long.

View Source
var ErrNoFile = errors.New("tag was not initialized with file")

ErrNoFile is returned when a tag operation is attempted on a tag that wasn't initialized with a file. For example, if you try to save or close a tag that was created without a file.

Functions

This section is empty.

Types

type ChapterFrame

type ChapterFrame struct {
	ElementID   string        // Unique identifier for the chapter.
	StartTime   time.Duration // Start time of the chapter.
	EndTime     time.Duration // End time of the chapter.
	StartOffset uint32        // Start offset in bytes (optional, use IgnoredOffset to ignore).
	EndOffset   uint32        // End offset in bytes (optional, use IgnoredOffset to ignore).
	Title       *TextFrame    // Title of the chapter (optional).
	Description *TextFrame    // Description of the chapter (optional).
	Link        *LinkFrame    // Link associated with the chapter (optional).
	Artwork     *PictureFrame // Artwork associated with the chapter (optional).
}

ChapterFrame represents a chapter frame in an ID3v2 tag, as defined by the ID3v2 chapters specification here - // according to spec from http://id3.org/id3v2-chapters-1.0. It supports a single TIT2 subframe (Title field) and ignores other subframes. If StartOffset or EndOffset equals IgnoredOffset, the corresponding time (StartTime or EndTime) should be used instead.

func (ChapterFrame) Size

func (cf ChapterFrame) Size() int

Size calculates the total size of the ChapterFrame in bytes, including all its subframes.

func (ChapterFrame) UniqueIdentifier

func (cf ChapterFrame) UniqueIdentifier() string

UniqueIdentifier returns the unique identifier for the ChapterFrame, which is its ElementID.

func (ChapterFrame) WriteTo

func (cf ChapterFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the ChapterFrame to the provided io.Writer, including all its subframes.

type CommentFrame

type CommentFrame struct {
	Encoding    Encoding // The text encoding used for the description and comment text.
	Language    string   // A three-letter language code (e.g., "eng" for English).
	Description string   // A short description of the comment (e.g., "Recording Info").
	Text        string   // The actual comment text.
}

CommentFrame represents a comment frame in an ID3v2 tag, commonly used for storing comments about the audio file. Each comment frame includes a language code, a description, and the actual comment text. The language code must be a valid three-letter ISO 639-2 code. ISO 639-2 code list: https://www.loc.gov/standards/iso639-2/php/code_list.php.

To add a comment frame to a tag, use the `tag.AddCommentFrame()` method.

Example (Add)
package main

import (
	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag := id3v2.NewEmptyTag()
	comment := id3v2.CommentFrame{
		Encoding:    id3v2.EncodingUTF8,
		Language:    id3v2.EnglishISO6392Code,
		Description: "My opinion",
		Text:        "Very good song",
	}
	tag.AddCommentFrame(comment)
}
Example (Get)
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	comments := tag.GetFrames(tag.CommonID("Comments"))
	for _, f := range comments {
		comment, ok := f.(id3v2.CommentFrame)
		if !ok {
			log.Fatal("Couldn't assert comment frame")
		}

		// Do something with comment frame.
		// For example, print the text:
		fmt.Println(comment.Text)
	}
}

func (CommentFrame) Size

func (cf CommentFrame) Size() int

Size calculates the total size of the comment frame in bytes, including the encoding byte, language code, description, termination bytes, and comment text.

func (CommentFrame) UniqueIdentifier

func (cf CommentFrame) UniqueIdentifier() string

UniqueIdentifier returns a string that uniquely identifies this comment frame. It combines the language code and description to ensure uniqueness, as multiple comment frames can exist in a tag as long as their language and description differ.

func (CommentFrame) WriteTo

func (cf CommentFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the comment frame to the provided io.Writer. It returns the number of bytes written and any error encountered during the write operation.

type Encoding

type Encoding struct {
	Name             string // Name of the encoding (e.g., "ISO-8859-1").
	Key              byte   // Key used in ID3v2 frames to identify this encoding.
	TerminationBytes []byte // Bytes that mark the end of a string in this encoding.
}

Encoding represents a text encoding used in ID3v2 tags. It includes the encoding name, a key (used in ID3v2 frames), and the termination bytes that mark the end of a string in this encoding.

func (Encoding) Equals

func (e Encoding) Equals(other Encoding) bool

Equals checks if this Encoding is equal to another Encoding by comparing their keys.

func (Encoding) String

func (e Encoding) String() string

String returns the name of the encoding.

type Framer

type Framer interface {
	// Size returns the size of the frame's body in bytes.
	Size() int

	// UniqueIdentifier returns a string that uniquely distinguishes this frame from others
	// with the same frame ID. For example, frames like TXXX or APIC can have multiple instances
	// in a tag, differentiated by properties like descriptions or picture types.
	//
	// For frames that can only appear once with the same ID (e.g., text frames), this method
	// should return an empty string ("").
	UniqueIdentifier() string

	// WriteTo writes the frame's body to the provided io.Writer.
	// It returns the number of bytes written and any error encountered during the write operation.
	WriteTo(w io.Writer) (n int64, err error)
}

Framer is an interface that defines the behavior of an ID3v2 frame. Any custom frame implementation must satisfy this interface to be compatible with the ID3v2 package.

type LinkFrame

type LinkFrame struct {
	Encoding Encoding // The text encoding used for the URL.
	URL      string   // The actual URL or link.
}

LinkFrame represents a frame that contains a URL or link. It is used for frames like "WXXX" (User-defined URL link) in ID3v2 tags.

func (LinkFrame) Size

func (lf LinkFrame) Size() int

Size calculates the total size of the LinkFrame in bytes. This includes the encoding byte, the encoded URL, and the termination bytes.

func (LinkFrame) UniqueIdentifier

func (lf LinkFrame) UniqueIdentifier() string

UniqueIdentifier returns a unique identifier for the LinkFrame. Since LinkFrame doesn't have a natural unique identifier, it uses a constant value.

func (LinkFrame) WriteTo

func (lf LinkFrame) WriteTo(w io.Writer) (int64, error)

WriteTo writes the LinkFrame to the provided io.Writer. It encodes the URL using the specified encoding and writes the frame's data. Returns the number of bytes written and any error encountered.

type Options

type Options struct {
	// Parse determines whether the tag should be parsed.
	// If set to true, the tag will be parsed; otherwise, it will be skipped.
	Parse bool

	// ParseFrames specifies which frames should be parsed.
	// For example, setting `ParseFrames: []string{"Artist", "Title"}` will only parse
	// the artist and title frames.
	// You can use either frame IDs (e.g., "TPE1", "TIT2")
	// or descriptions (e.g., "Artist", "Title").
	// If ParseFrames is empty or nil, all frames in the tag will be parsed.
	// This option only takes effect if Parse is true.
	//
	// This is particularly useful for improving performance.
	// For instance, if you only need certain text frames, the library will skip parsing
	// large or irrelevant frames like pictures or unknown frames.
	ParseFrames []string
}

Options defines the settings that influence how the tag is processed.

type PictureFrame

type PictureFrame struct {
	Encoding    Encoding // The text encoding used for the description.
	MimeType    string   // The MIME type of the image (e.g., "image/jpeg").
	PictureType byte     // The type of picture (e.g., front cover, back cover).
	Description string   // A description of the picture.
	Picture     []byte   // The raw binary data of the image.
}

PictureFrame represents an ID3v2 picture frame (APIC), which is used to store images like album art. To add a picture frame to a tag, use the `tag.AddAttachedPicture` method.

The frame includes metadata like the MIME type, picture type (e.g., front cover, back cover), a description, and the actual image data.

Example (Add)
package main

import (
	"log"
	"os"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag := id3v2.NewEmptyTag()

	artwork, err := os.ReadFile("artwork.jpg")
	if err != nil {
		log.Fatal("Error while reading artwork file", err)
	}

	pic := id3v2.PictureFrame{
		Encoding:    id3v2.EncodingUTF8,
		MimeType:    "image/jpeg",
		PictureType: id3v2.PTFrontCover,
		Description: "Front cover",
		Picture:     artwork,
	}
	tag.AddAttachedPicture(pic)
}
Example (Get)
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	pictures := tag.GetFrames(tag.CommonID("Attached picture"))
	for _, f := range pictures {
		pic, ok := f.(id3v2.PictureFrame)
		if !ok {
			log.Fatal("Couldn't assert picture frame")
		}

		// Do something with picture frame.
		// For example, print the description:
		fmt.Println(pic.Description)
	}
}

func (PictureFrame) Size

func (pf PictureFrame) Size() int

Size calculates the total size of the PictureFrame in bytes. This includes the encoding byte, MIME type, picture type, description, and image data.

func (PictureFrame) UniqueIdentifier

func (pf PictureFrame) UniqueIdentifier() string

UniqueIdentifier generates a unique string identifier for the PictureFrame. This is used to distinguish between multiple picture frames in a tag. The identifier combines the picture type and description.

func (PictureFrame) WriteTo

func (pf PictureFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the PictureFrame to the provided io.Writer. It returns the number of bytes written and any error encountered. This method is used when saving the frame to an MP3 file.

type PopularimeterFrame

type PopularimeterFrame struct {
	// Email is the identifier for the POPM frame. It typically represents the email address
	// of the user who rated or played the track.
	Email string

	// Rating is the user's rating for the track. It ranges from 1 to 255, where:
	// - 1 is the worst rating.
	// - 255 is the best rating.
	// - 0 means the rating is unknown.
	Rating uint8

	// Counter is the number of times the track has been played by the user identified by the Email field.
	// It is stored as a big.Int to support very large play counts.
	Counter *big.Int
}

PopularimeterFrame represents a Popularimeter (POPM) frame in an ID3v2 tag. The Popularimeter frame is used to store user-specific play count and rating information for a track. For more details, see: https://id3.org/id3v2.3.0#Popularimeter

Example (Add)
package main

import (
	"math/big"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag := id3v2.NewEmptyTag()

	popmFrame := id3v2.PopularimeterFrame{
		Email:   "foo@bar.com",
		Rating:  128,
		Counter: big.NewInt(10000000000000000),
	}
	tag.AddFrame(tag.CommonID("Popularimeter"), popmFrame)
}
Example (Get)
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	f := tag.GetLastFrame(tag.CommonID("Popularimeter"))

	popm, ok := f.(id3v2.PopularimeterFrame)
	if !ok {
		log.Fatal("Couldn't assert POPM frame")
	}

	// do something with POPM Frame
	fmt.Printf("Email: %s, Rating: %d, Counter: %d", popm.Email, popm.Rating, popm.Counter)
}

func (PopularimeterFrame) Size

func (pf PopularimeterFrame) Size() int

Size calculates the total size of the PopularimeterFrame in bytes. This includes the size of the Email, Rating, and Counter fields.

func (PopularimeterFrame) UniqueIdentifier

func (pf PopularimeterFrame) UniqueIdentifier() string

UniqueIdentifier returns a unique identifier for the PopularimeterFrame. For POPM frames, the unique identifier is the Email field, as each email address corresponds to a unique user's rating and play count.

func (PopularimeterFrame) WriteTo

func (pf PopularimeterFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the PopularimeterFrame to the provided io.Writer. It returns the number of bytes written and any error encountered during the write operation.

type SynchronisedLyricsFrame

type SynchronisedLyricsFrame struct {
	Encoding          Encoding           // The text encoding used for the lyrics and descriptor.
	Language          string             // The language of the lyrics (e.g., "eng" for English).
	TimestampFormat   byte               // The format of the timestamps (e.g., milliseconds or MPEG frames).
	ContentType       byte               // The type of content (e.g., lyrics, transcription, or events).
	ContentDescriptor string             // A description of the content (e.g., "Verse 1").
	SynchronizedTexts []SynchronizedText // A list of synchronized text entries with their timestamps.
}

SynchronisedLyricsFrame represents a SYLT (Synchronised Lyrics) frame in an ID3v2 tag. This frame is used to store lyrics or text that are synchronized to specific timestamps in the audio. For example, you can use this to display karaoke lyrics or subtitles that match the timing of the song.

To add a SYLT frame to a tag, use the `tag.AddSynchronisedLyricsFrame` function.

The `Language` field must be a valid three-letter language code from the ISO 639-2 standard. You can find the list of codes here: https://www.loc.gov/standards/iso639-2/php/code_list.php

func (SynchronisedLyricsFrame) Size

func (sylf SynchronisedLyricsFrame) Size() int

Size calculates the total size of the SYLT frame in bytes. This is used when writing the frame to a file to determine how much space it will occupy.

func (SynchronisedLyricsFrame) UniqueIdentifier

func (sylf SynchronisedLyricsFrame) UniqueIdentifier() string

UniqueIdentifier returns a unique identifier for the SYLT frame. This is used to distinguish between multiple SYLT frames in a tag.

func (SynchronisedLyricsFrame) WriteTo

func (sylf SynchronisedLyricsFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the SYLT frame to the provided io.Writer. This is used when saving the frame to an MP3 file.

type SynchronizedText

type SynchronizedText struct {
	Text      string // The text to display (e.g., a line of lyrics).
	Timestamp uint32 // The timestamp in the audio when the text should be displayed.
}

SynchronizedText represents a single synchronized text entry with its associated timestamp. For example, this could be a line of lyrics and the time it should be displayed.

type Tag

type Tag struct {
	// contains filtered or unexported fields
}

Tag represents an ID3v2 tag in an MP3 file. It stores all the metadata frames, sequences, and other relevant information about the tag. You can use it to read, modify, or create ID3v2 tags.

func NewEmptyTag

func NewEmptyTag() *Tag

NewEmptyTag creates and returns a new empty ID3v2.4 tag. The tag has no frames and no associated reader. This is useful for creating a new tag from scratch.

func Open

func Open(name string, opts Options) (*Tag, error)

Open opens the MP3 file specified by `name` and parses its ID3v2 tag. If the file does not contain an ID3v2 tag, a new one is created with ID3v2.4 version. The `opts` parameter controls parsing behavior, such as whether to parse all frames or specific ones. Returns a pointer to the Tag and an error if the file cannot be opened or parsed.

func ParseReader

func ParseReader(rd io.Reader, opts Options) (*Tag, error)

ParseReader reads from the provided `io.Reader` and parses the ID3v2 tag. If no tag is found, a new ID3v2.4 tag is created. The `opts` parameter controls parsing behavior, such as whether to parse all frames or specific ones. Returns a pointer to the Tag and an error if parsing fails.

func (*Tag) AddAttachedPicture

func (tag *Tag) AddAttachedPicture(pf PictureFrame)

AddAttachedPicture adds a picture frame (e.g., album art) to the tag.

Example
package main

import (
	"log"
	"os"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	artwork, err := os.ReadFile("artwork.jpg")
	if err != nil {
		log.Fatal("Error while reading artwork file", err)
	}

	pic := id3v2.PictureFrame{
		Encoding:    id3v2.EncodingUTF8,
		MimeType:    "image/jpeg",
		PictureType: id3v2.PTFrontCover,
		Description: "Front cover",
		Picture:     artwork,
	}
	tag.AddAttachedPicture(pic)
}

func (*Tag) AddChapterFrame

func (tag *Tag) AddChapterFrame(cf ChapterFrame)

AddChapterFrame adds a chapter frame to the tag. Chapters are used to divide an audio file into sections.

func (*Tag) AddCommentFrame

func (tag *Tag) AddCommentFrame(cf CommentFrame)

AddCommentFrame adds a comment frame to the tag. Comments can include a description and text.

Example
package main

import (
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	comment := id3v2.CommentFrame{
		Encoding:    id3v2.EncodingUTF8,
		Language:    id3v2.EnglishISO6392Code,
		Description: "My opinion",
		Text:        "Very good song",
	}
	tag.AddCommentFrame(comment)
}

func (*Tag) AddFrame

func (tag *Tag) AddFrame(id string, f Framer)

AddFrame adds a frame to the tag with the specified ID. If the ID is empty or the frame is nil, the function does nothing. For frames that can appear multiple times (e.g., pictures or comments), use the specialized methods like AddAttachedPicture, AddCommentFrame or AddUnsynchronisedLyricsFrame.

func (*Tag) AddSynchronisedLyricsFrame

func (tag *Tag) AddSynchronisedLyricsFrame(sylf SynchronisedLyricsFrame)

AddSynchronisedLyricsFrame adds a synchronized lyrics frame to the tag. These frames store lyrics with timing information for synchronization with the audio.

func (*Tag) AddTextFrame

func (tag *Tag) AddTextFrame(id string, encoding Encoding, text string)

AddTextFrame creates a text frame with the specified encoding and text, then adds it to the tag.

func (*Tag) AddUFIDFrame

func (tag *Tag) AddUFIDFrame(ufid UFIDFrame)

AddUFIDFrame adds a unique file identifier frame (UFID) to the tag. These frames store a unique identifier for the file.

func (*Tag) AddUnsynchronisedLyricsFrame

func (tag *Tag) AddUnsynchronisedLyricsFrame(uslf UnsynchronisedLyricsFrame)

AddUnsynchronisedLyricsFrame adds an unsynchronized lyrics frame to the tag. These frames store lyrics without timing information.

Example
package main

import (
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	uslt := id3v2.UnsynchronisedLyricsFrame{
		Encoding:          id3v2.EncodingUTF8,
		Language:          id3v2.GermanISO6392Code,
		ContentDescriptor: "Deutsche Nationalhymne",
		Lyrics:            "Einigkeit und Recht und Freiheit...",
	}
	tag.AddUnsynchronisedLyricsFrame(uslt)
}

func (*Tag) AddUserDefinedTextFrame

func (tag *Tag) AddUserDefinedTextFrame(udtf UserDefinedTextFrame)

AddUserDefinedTextFrame adds a user-defined text frame (TXXX) to the tag. These frames allow custom metadata to be stored.

func (*Tag) Album

func (tag *Tag) Album() string

Album returns the album stored in the tag.

func (*Tag) AllFrames

func (tag *Tag) AllFrames() map[string][]Framer

AllFrames returns a map of all frames in the tag. The key is the frame ID, and the value is a slice of frames. This is useful for inspecting all metadata in the tag.

func (*Tag) Artist

func (tag *Tag) Artist() string

Artist returns the artist stored in the tag.

func (*Tag) Close

func (tag *Tag) Close() error

Close closes the tag's file if it was initialized with a file. Returns ErrNoFile if the tag wasn't initialized with a file.

func (*Tag) CommonID

func (tag *Tag) CommonID(description string) string

CommonID returns the frame ID corresponding to the given description. For example, passing "Title" returns "TIT2". If the description isn't found, it returns the description itself. All descriptions can be found in the common_ids.go.

func (*Tag) Count

func (tag *Tag) Count() int

Count returns the total number of frames in the tag.

func (*Tag) DefaultEncoding

func (tag *Tag) DefaultEncoding() Encoding

DefaultEncoding returns the default text encoding used for text frames in the tag.

func (*Tag) DeleteAllFrames

func (tag *Tag) DeleteAllFrames()

DeleteAllFrames removes all frames from the tag. This is useful for starting fresh when creating a new tag.

func (*Tag) DeleteFrames

func (tag *Tag) DeleteFrames(id string)

DeleteFrames removes all frames with the specified ID from the tag.

func (*Tag) Genre

func (tag *Tag) Genre() string

Genre returns the genre stored in the tag.

func (*Tag) GetFrames

func (tag *Tag) GetFrames(id string) []Framer

GetFrames returns all frames with the specified ID. If no frames exist, it returns nil.

Example
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	pictures := tag.GetFrames(tag.CommonID("Attached picture"))
	for _, f := range pictures {
		pic, ok := f.(id3v2.PictureFrame)
		if !ok {
			log.Fatal("Couldn't assert picture frame")
		}
		// Do something with picture frame.
		// For example, print description of picture frame:
		fmt.Println(pic.Description)
	}
}

func (*Tag) GetLastFrame

func (tag *Tag) GetLastFrame(id string) Framer

GetLastFrame returns the last frame from the slice returned by GetFrames. This is useful for frames that should only appear once, like text frames.

Example
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	bpmFramer := tag.GetLastFrame(tag.CommonID("BPM"))
	if bpmFramer != nil {
		bpm, ok := bpmFramer.(id3v2.TextFrame)
		if !ok {
			log.Fatal("Couldn't assert bpm frame")
		}

		fmt.Println(bpm.Text)
	}
}

func (*Tag) GetTextFrame

func (tag *Tag) GetTextFrame(id string) TextFrame

GetTextFrame returns the text frame with the specified ID. If no such frame exists, it returns an empty TextFrame.

func (*Tag) HasFrames

func (tag *Tag) HasFrames() bool

HasFrames checks if the tag contains any frames. This is faster than checking Count() > 0.

func (*Tag) Reset

func (tag *Tag) Reset(rd io.Reader, opts Options) error

Reset clears all frames in the tag and re-parses the provided reader with the given options. This is useful for reusing a tag instance.

func (*Tag) Save

func (tag *Tag) Save() error

Save writes the tag to the file if the tag was initialized with a file. If there are no frames, it writes only the music part without any ID3v2 information. Returns ErrNoFile if the tag wasn't initialized with a file.

func (*Tag) SetAlbum

func (tag *Tag) SetAlbum(album string)

SetAlbum sets the album in the tag.

func (*Tag) SetArtist

func (tag *Tag) SetArtist(artist string)

SetArtist sets the artist in the tag.

func (*Tag) SetDefaultEncoding

func (tag *Tag) SetDefaultEncoding(encoding Encoding)

SetDefaultEncoding sets the default text encoding for the tag. This encoding is used when adding text frames without explicitly specifying an encoding.

func (*Tag) SetGenre

func (tag *Tag) SetGenre(genre string)

SetGenre sets the genre in the tag.

func (*Tag) SetTitle

func (tag *Tag) SetTitle(title string)

SetTitle sets the title in the tag.

func (*Tag) SetVersion

func (tag *Tag) SetVersion(version byte)

SetVersion sets the ID3v2 version of the tag. If the version is invalid (less than 3 or greater than 4), the function does nothing.

func (*Tag) SetYear

func (tag *Tag) SetYear(year string)

SetYear sets the year in the tag.

func (*Tag) Size

func (tag *Tag) Size() int

Size returns the total size of the tag in bytes, including the tag header and all frames.

func (*Tag) Title

func (tag *Tag) Title() string

Title returns the title stored in the tag.

func (*Tag) Version

func (tag *Tag) Version() byte

Version returns the ID3v2 version of the tag (e.g., 3 or 4).

func (*Tag) WriteTo

func (tag *Tag) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the entire tag to the provided writer. It returns the number of bytes written and any error encountered. If there are no frames, it writes nothing.

func (*Tag) Year

func (tag *Tag) Year() string

Year returns the year stored in the tag.

type TextFrame

type TextFrame struct {
	Encoding Encoding // The encoding used for the text (e.g., UTF-8, ISO-8859-1).
	Text     string   // The primary text value of the frame.
	Multi    []string // Additional text values, used for frames that support multiple entries.
}

TextFrame is used to work with all text frames in ID3v2 tags. These frames are identified by IDs starting with "T" (e.g., TIT2 for title, TALB for album). It stores text data along with its encoding and supports multiple values for certain frames.

Example (Add)
package main

import (
	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag := id3v2.NewEmptyTag()
	textFrame := id3v2.TextFrame{
		Encoding: id3v2.EncodingUTF8,
		Text:     "Happy",
	}
	tag.AddFrame(tag.CommonID("Mood"), textFrame)
}
Example (Get)
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	tf := tag.GetTextFrame(tag.CommonID("Mood"))
	fmt.Println(tf.Text)
}

func (TextFrame) Size

func (tf TextFrame) Size() int

Size calculates the total size of the TextFrame in bytes. This includes the encoding byte, the encoded text, and the termination bytes.

func (TextFrame) UniqueIdentifier

func (tf TextFrame) UniqueIdentifier() string

UniqueIdentifier returns a unique identifier for the TextFrame. Since text frames don't have a unique identifier in the ID3v2 spec, this returns a constant.

func (TextFrame) WriteTo

func (tf TextFrame) WriteTo(w io.Writer) (int64, error)

WriteTo writes the TextFrame to the provided io.Writer. It encodes the text using the specified encoding and writes the frame's data. Returns the number of bytes written and any error encountered.

type UFIDFrame

type UFIDFrame struct {
	OwnerIdentifier string // The owner of the unique identifier (e.g., "https://musicbrainz.org").
	Identifier      []byte // The unique identifier itself, stored as a byte slice.
}

UFIDFrame represents a "Unique File Identifier" frame in an ID3v2 tag. This frame is used to store a unique identifier for the file, typically associated with an owner (e.g., a service like MusicBrainz) and a binary identifier.

func (UFIDFrame) Size

func (ufid UFIDFrame) Size() int

Size calculates the total size of the UFID frame in bytes. This includes the size of the owner identifier (encoded in ISO-8859-1), the termination bytes, and the size of the identifier itself.

func (UFIDFrame) UniqueIdentifier

func (ufid UFIDFrame) UniqueIdentifier() string

UniqueIdentifier returns a string that uniquely identifies this frame. For UFID frames, this is the OwnerIdentifier, as it distinguishes this frame from others.

func (UFIDFrame) WriteTo

func (ufid UFIDFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the UFID frame to the provided io.Writer. It returns the number of bytes written and any error encountered during the write operation. The frame is written in the following format:

  • Owner identifier (encoded in ISO-8859-1)
  • Termination bytes (0x00 for ISO-8859-1)
  • Identifier (raw bytes)

type UnknownFrame

type UnknownFrame struct {
	Body []byte // Raw byte data of the unknown frame.
}

UnknownFrame represents an ID3v2 frame that the library doesn't know how to parse or interpret. It stores the raw byte data of the frame, allowing the library to handle unknown frame types without losing their content. This is useful for preserving custom or proprietary frames.

func (UnknownFrame) Size

func (uf UnknownFrame) Size() int

Size returns the size of the UnknownFrame's body in bytes. This is used to calculate the total size of the frame when writing it to a file.

func (UnknownFrame) UniqueIdentifier

func (uf UnknownFrame) UniqueIdentifier() string

UniqueIdentifier generates a unique identifier for the UnknownFrame. Since the frame type is unknown, this method uses a random integer to ensure uniqueness. This is necessary because ID3v2 frames typically have unique identifiers, but unknown frames don't have a predefined ID.

func (UnknownFrame) WriteTo

func (uf UnknownFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the raw byte data of the UnknownFrame to the provided io.Writer. It returns the number of bytes written and any error encountered during the write operation. This method is used to serialize the UnknownFrame back into an ID3v2 tag.

type UnsynchronisedLyricsFrame

type UnsynchronisedLyricsFrame struct {
	Encoding          Encoding // The text encoding used for the lyrics and content descriptor.
	Language          string   // The language of the lyrics (e.g., "eng" for English).
	ContentDescriptor string   // A short description of the lyrics (e.g., "Verse 1").
	Lyrics            string   // The actual lyrics or text content.
}

UnsynchronisedLyricsFrame represents an ID3v2 unsynchronized lyrics/text frame (USLT). This frame is used to store lyrics or text that is not synchronized with the audio. For example, it can be used to store the full lyrics of a song.

To add this frame to a tag, use the `tag.AddUnsynchronisedLyricsFrame` method.

The `Language` field must be a valid three-letter language code from the ISO 639-2 standard. You can find the list of valid codes here: https://www.loc.gov/standards/iso639-2/php/code_list.php

Example (Add)
package main

import (
	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag := id3v2.NewEmptyTag()
	uslt := id3v2.UnsynchronisedLyricsFrame{
		Encoding:          id3v2.EncodingUTF8,
		Language:          id3v2.GermanISO6392Code,
		ContentDescriptor: "Deutsche Nationalhymne",
		Lyrics:            "Einigkeit und Recht und Freiheit...",
	}
	tag.AddUnsynchronisedLyricsFrame(uslt)
}
Example (Get)
package main

import (
	"fmt"
	"log"

	id3v2 "github.com/oshokin/id3v2"
)

func main() {
	tag, err := id3v2.Open("file.mp3", id3v2.Options{Parse: true})
	if tag == nil || err != nil {
		log.Fatal("Error while opening mp3 file: ", err)
	}

	uslfs := tag.GetFrames(tag.CommonID("Unsynchronised lyrics/text transcription"))
	for _, f := range uslfs {
		uslf, ok := f.(id3v2.UnsynchronisedLyricsFrame)
		if !ok {
			log.Fatal("Couldn't assert USLT frame")
		}

		// Do something with USLT frame.
		// For example, print the lyrics:
		fmt.Println(uslf.Lyrics)
	}
}

func (UnsynchronisedLyricsFrame) Size

func (uslf UnsynchronisedLyricsFrame) Size() int

Size calculates the total size of the UnsynchronisedLyricsFrame in bytes. This includes the encoding byte, language code, content descriptor, and lyrics, as well as the termination bytes required by the encoding.

func (UnsynchronisedLyricsFrame) UniqueIdentifier

func (uslf UnsynchronisedLyricsFrame) UniqueIdentifier() string

UniqueIdentifier returns a string that uniquely identifies this frame. For UnsynchronisedLyricsFrame, the identifier is a combination of the language and content descriptor. This ensures that frames with the same language and descriptor are treated as the same frame.

func (UnsynchronisedLyricsFrame) WriteTo

func (uslf UnsynchronisedLyricsFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the UnsynchronisedLyricsFrame to the provided io.Writer. It returns the number of bytes written and any error encountered during the write. If the language code is not exactly 3 characters long, it returns ErrInvalidLanguageLength.

type UserDefinedTextFrame

type UserDefinedTextFrame struct {
	Encoding    Encoding // The text encoding used for the description and value.
	Description string   // A unique description for this frame (e.g., "My Custom Field").
	Value       string   // The actual value associated with the description.
	Multi       []string // A slice of multiple values, if applicable (used for multi-value fields).
}

UserDefinedTextFrame represents a TXXX frame in an ID3v2 tag. TXXX frames are used to store custom, user-defined text information. You can have multiple TXXX frames in a tag, but each one must have a unique description.

func (UserDefinedTextFrame) Size

func (udtf UserDefinedTextFrame) Size() int

Size calculates the total size of the UserDefinedTextFrame in bytes. This includes the encoding byte, the description, termination bytes, and the value.

func (UserDefinedTextFrame) UniqueIdentifier

func (udtf UserDefinedTextFrame) UniqueIdentifier() string

UniqueIdentifier returns a string that uniquely identifies this frame. For UserDefinedTextFrame, the description is used as the unique identifier since it must be unique within the tag.

func (UserDefinedTextFrame) WriteTo

func (udtf UserDefinedTextFrame) WriteTo(w io.Writer) (n int64, err error)

WriteTo writes the UserDefinedTextFrame to the provided io.Writer. It returns the number of bytes written and any error encountered.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL