tag

repository·master·Indexed 20 days ago

https://github.com/dhowden/tag

A Go library for detecting, parsing, and extracting metadata and artwork from MP3, MP4, OGG, and FLAC files. It provides a unified Metadata interface for accessing common audio tags across different formats and includes tools for generating metadata-invariant SHA1 audio checksums. The package also includes CLI tools for metadata extraction, audio summing, and music collection validation.

Tokens
7.8K
Snippets
36
Records
47
Agent score
71%

What's inside tag

  1. Install and use the tag CLI tools

    master

    You can install command-line tools to demonstrate tag extraction and audio summing:

    1. Install the tools: go install github.com/dhowden/tag/cmd/tag@latest
    2. Use ./tag <filename> to extract metadata.
    3. Use ./sum <filename> to calculate the metadata-invariant SHA1 checksum.
    $ go install github.com/dhowden/tag/cmd/tag@latest
    $ ./tag 11\ High\ Hopes.m4a
    $ ./sum 11\ High\ Hopes.m4a
  2. Detect and parse audio metadata from an io.ReadSeeker

    master

    Use tag.ReadFrom(r io.ReadSeeker) to detect and parse metadata from an audio file (such as an *os.File). The function returns a Metadata interface which provides a consistent API regardless of whether the underlying format is MP3, MP4, OGG, or FLAC.

    m, err := tag.ReadFrom(f)
    if err != nil {
    	log.Fatal(err)
    }
    log.Print(m.Format()) // The detected format.
    log.Print(m.Title())  // The title of the track
  3. How oggDemuxer works

    master

    The oggDemuxer is an internal mechanism used by ReadOGGTags to parse OGG pages and reconstruct packets.

    It handles:

    1. Page Validation: Verifies the OggS magic number and validates the CRC32 checksum of the page header, segment table, and segment data.
    2. Packet Reconstruction: OGG packets can span multiple pages. The demuxer uses the SerialNumber and the Flags (specifically the continuation bit) to buffer and reassemble fragmented packets.
    3. Segment Handling: It processes the segment table to correctly slice the segmentsData into individual packets.

    Note: While oggDemuxer is available in the package, it is primarily intended to support the high-level ReadOGGTags API.

  4. Understand the ID3v2 Metadata structure

    master

    When calling ReadID3v2Tags, the returned Metadata is an interface that encapsulates the parsed ID3v2 header and frames. The frames are stored in a map where keys are the frame names (e.g., TXXX, APIC, COMM) and values are the parsed content of those frames.

    Common frame types handled include:

    • Text Frames (starting with T): Parsed via readTFrame.
    • Encoded Text Frames (starting with W): Parsed via readWFrame.
    • User Defined Text Frames (TXXX, TXX): Parsed with description support.
    • Comments/Lyrics (COMM, COM, USLT, ULT): Parsed with language and encoding support.
    • Images (APIC, PIC): Parsed as picture frames.
    • UFID (UFID, UFI): Parsed as Universal Unique Identifier frames.
  5. Use the Metadata interface to access track information

    master

    The Metadata interface provides a unified way to access common audio tags across different file formats. Supported methods include:

    • Format() Format: Returns the detected metadata format.
    • FileType() FileType: Returns the file type.
    • Title() string, Album() string, Artist() string, AlbumArtist() string, Composer() string, Genre() string: Returns basic descriptive strings.
    • Year() int: Returns the release year.
    • Track() (int, int): Returns the current track number and the total number of tracks.
    • Disc() (int, int): Returns the current disc number and the total number of discs.
    • Picture() *Picture: Returns the artwork associated with the track.
    • Lyrics() string: Returns the track lyrics.
    • Comment() string: Returns track comments.
    • Raw() map[string]interface{}: Returns the raw tags. Note that raw tag names are not consistent across different formats.
    type Metadata interface {
    	Format() Format
    	FileType() FileType
    
    	Title() string
    	Album() string
    	Artist() string
    	AlbumArtist() string
    	Composer() string
    	Genre() string
    	Year() int
    
    	Track() (int, int) // Number, Total
    	Disc() (int, int) // Number, Total
    
    	Picture() *Picture // Artwork
    	Lyrics() string
    	Comment() string
    
    	Raw() map[string]interface{} // NB: raw tag names are not consistent across formats.
    }
  6. Calculate a metadata-invariant audio checksum (SHA1)

    master
    The package provides a way to generate a checksum of the audio data itself, ignoring any metadata. This ensures that the checksum remains the same even if tags (like title or artist) are modified. Use the tag.Sum function for this purpose.
  7. Handle 'no tags found' errors

    master

    When tag.ReadFrom cannot identify a metadata format or find any tags, it returns the ErrNoTagsFound error. You should check for this specific error to distinguish between a file that simply lacks metadata and a file that failed to parse due to other I/O issues.

    var ErrNoTagsFound = errors.New("no tags found")
    
    // Usage pattern:
    m, err := tag.ReadFrom(f)
    if err == tag.ErrNoTagsFound {
    	// Handle file with no metadata
    }
  8. Extract MusicBrainz data with the tag CLI

    master

    The -mbz flag uses the mbz.Extract(m) function to retrieve MusicBrainz-specific metadata from the provided tag.Metadata. The output is formatted as an indented JSON string.

    tag -mbz filename.mp3
  9. Extract raw tag data with the tag CLI

    master

    When using the -raw flag, the tool iterates through the map returned by m.Raw() and prints each key and value. Note that *tag.Picture values are printed using %v instead of the more verbose %#v to maintain readability.

    tag -raw filename.mp3
  10. Access ID3v2 metadata fields

    master

    The metadataID3v2 type implements the Metadata interface for ID3v2 tags. It provides methods to retrieve common audio metadata such as title, artist, album, and more. The library automatically handles the mapping of these fields to the correct ID3v2 frame names based on the tag version (ID3v2.2, ID3v2.3, or ID3v2.4).

    // Assuming 'm' is an instance of Metadata implementing metadataID3v2
    fmt.Println(m.Title())
    fmt.Println(m.Artist())
    fmt.Println(m.Album())
    fmt.Println(m.AlbumArtist())
    fmt.Println(m.Composer())
    fmt.Println(m.Genre())
    fmt.Println(m.Year())
    fmt.Println(m.Track())
    fmt.Println(m.Disc())
    fmt.Println(m.Lyrics())
    fmt.Println(m.Comment())
    
    pic := m.Picture()
    if pic != nil {
        // use picture
    }
  11. Access common MP4 metadata fields

    master

    The Metadata interface returned by ReadAtoms for MP4 files provides the following methods to retrieve common tags:

    • Title() string: Returns the track title.
    • Artist() string: Returns the performer/artist.
    • Album() string: Returns the album name.
    • AlbumArtist() string: Returns the album artist.
    • Composer() string: Returns the composer.
    • Genre() string: Returns the genre.
    • Year() int: Returns the year (extracted from the first 4 characters of the year atom).
    • Track() (int, int): Returns the current track number and the total number of tracks in the album.
    • Disc() (int, int): Returns the current disc number and the total number of discs.
    • Lyrics() string: Returns the lyrics if present.
    • Comment() string: Returns the comment field.
    • Picture() *Picture: Returns a *Picture object containing image data (e.g., from the covr atom) if available.
  12. Detect and parse audio metadata with ReadFrom

    master

    Use tag.ReadFrom(r) to automatically detect and parse metadata from an io.ReadSeeker (such as an *os.File). The function identifies the format (ID3v1, ID3v2, MP4, FLAC, etc.) and returns a Metadata interface for accessing track information. If the format cannot be identified, it returns ErrNoTagsFound.

    m, err := tag.ReadFrom(f)
    if err != nil {
    	log.Fatal(err)
    }
    log.Print(m.Format()) // The detected format.
    log.Print(m.Title()) // The title of the track