tag

package module
v0.0.0-...-8b3dabc Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2026 License: BSD-2-Clause Imports: 19 Imported by: 0

README

MP3/MP4/OGG/FLAC metadata library (read + write)

GoDoc

This package provides MP3 (ID3v1,2.{2,3,4}), MP4 (AAC, M4A, ALAC), OGG, FLAC, WAV, and Monkey's Audio (APE) metadata detection, parsing and artwork extraction. It also supports writing tags back to MP3 (ID3v2.3), FLAC (Vorbis Comment + Picture), APE (APEv2 footer), and WAV (RIFF LIST INFO); M4A/OGG writers are TODO and return ErrUnsupportedWrite for now.

Forked from upstream and extended with encoding detection improvements plus MP3 (ID3v2.3) / FLAC (Vorbis Comment + PICTURE) writers used by Songloft.

Reading

Detect and parse tag metadata from an io.ReadSeeker (i.e. an *os.File):

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 (see Metadata interface for more details).

Writing

Write tags to an existing audio file (atomic rewrite via a sibling temp file):

err := tag.WriteTag("song.mp3", tag.WriteOptions{
    Title:       "Sample Title",
    Artist:      "Sample Artist",
    AlbumArtist: "Sample Artist",
    Album:       "Sample Album",
    Year:        2024,
    Genre:       "Pop",
    Lyrics:      "[00:00.00]...",        // UTF-8
    Picture: &tag.Picture{
        MIMEType: "image/jpeg",
        Data:     coverBytes,
    },
})

Format dispatch is by file extension:

Extension Status Frames / blocks written
.mp3 ✅ ID3v2.3 TIT2 / TPE1 / TPE2 / TALB / TYER / TCON / USLT / APIC
.flac ✅ Vorbis Comment + PICTURE TITLE / ARTIST / ALBUMARTIST / ALBUM / DATE / GENRE / LYRICS + Picture(Front)
.ape ✅ APEv2 Title / Artist / Album / Year / Genre / Lyrics + Comment
.wav ✅ RIFF LIST INFO INAM / IART / IPRD / ICRD / IGNR / ICMT
.m4a / .mp4 / .m4b ⚠️ TODO Returns ErrUnsupportedWrite
.ogg / .oga ⚠️ TODO Returns ErrUnsupportedWrite

Other extensions return ErrUnsupportedWrite. Callers should treat tag-write failures as non-fatal (log + continue).

Parsed metadata is exported via a single interface (giving a consistent API for all supported metadata formats).

// Metadata is an interface which is used to describe metadata retrieved by this package.
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.
}

Audio Data Checksum (SHA1)

This package also provides a metadata-invariant checksum for audio files: only the audio data is used to construct the checksum.

https://pkg.go.dev/github.com/hanxi/tag#Sum

Tools

There are simple command-line tools which demonstrate basic tag extraction and summing:

$ go install github.com/hanxi/tag/cmd/tag@latest
$ cd $GOPATH/bin
$ ./tag sample.m4a
Metadata Format: MP4
Title: Sample Title
Album: Sample Album
Artist: Sample Artist
Year: 2024
Track: 1 of 10
Disc: 1 of 1
Picture: Picture{Ext: jpeg, MIMEType: image/jpeg, Type: , Description: , Data.Size: 12345}

$ ./sum sample.m4a
2ae208c5f00a1f21f5fac9b7f6e0b8e52c06da29

Documentation

Overview

Package tag provides MP3 (ID3: v1, 2.2, 2.3 and 2.4), MP4, FLAC and OGG metadata detection, parsing and artwork extraction.

Detect and parse tag metadata from an io.ReadSeeker (i.e. an *os.File):

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 (see Metadata interface for more details).

Index

Constants

This section is empty.

Variables

View Source
var DefaultUTF16WithBOMByteOrder binary.ByteOrder = binary.LittleEndian

DefaultUTF16WithBOMByteOrder is the byte order used when the "UTF16 with BOM" encoding is specified without a corresponding BOM in the data.

View Source
var ErrNoTagsFound = errors.New("no tags found")

ErrNoTagsFound is the error returned by ReadFrom when the metadata format cannot be identified.

View Source
var ErrNotID3v1 = errors.New("invalid ID3v1 header")

ErrNotID3v1 is an error which is returned when no ID3v1 header is found.

View Source
var ErrUnsupportedWrite = errors.New("tag write not supported for this format")

ErrUnsupportedWrite is returned when WriteTag is called for a file format that does not yet have a writer implementation.

Functions

func FixEncoding

func FixEncoding(b []byte) string

FixEncoding attempts to fix encoding issues in byte data (exported wrapper).

func Identify

func Identify(r io.ReadSeeker) (format Format, fileType FileType, err error)

Identify identifies the format and file type of the data in the ReadSeeker.

func MIMETypeFromExt

func MIMETypeFromExt(ext string) string

MIMETypeFromExt 返回常见图片扩展名对应的 MIME 类型,用于在调用方 没有显式设置 Picture.MIMEType 时做兜底。

func ReadID3v1Tags

func ReadID3v1Tags(r io.ReadSeeker) (metadataID3v1, error)

ReadID3v1Tags reads ID3v1 tags from the io.ReadSeeker. Returns ErrNotID3v1 if there are no ID3v1 tags, otherwise non-nil error if there was a problem.

func ReadID3v2Tags

func ReadID3v2Tags(r io.ReadSeeker) (*metadataID3v2, error)

ReadID3v2Tags parses ID3v2.{2,3,4} tags from the io.ReadSeeker into a Metadata, returning non-nil error on failure.

func Sum

func Sum(r io.ReadSeeker) (string, error)

Sum creates a checksum of the audio file data provided by the io.ReadSeeker which is metadata (ID3, MP4) invariant.

func SumAll

func SumAll(r io.ReadSeeker) (string, error)

SumAll returns a checksum of the content from the reader (until EOF).

func SumAtoms

func SumAtoms(r io.ReadSeeker) (string, error)

SumAtoms constructs a checksum of MP4 audio file data provided by the io.ReadSeeker which is metadata invariant.

func SumFLAC

func SumFLAC(r io.ReadSeeker) (string, error)

SumFLAC costructs a checksum of the FLAC audio file data provided by the io.ReadSeeker (ignores metadata fields).

func SumID3v1

func SumID3v1(r io.ReadSeeker) (string, error)

SumID3v1 constructs a checksum of MP3 audio file data (assumed to have ID3v1 tags) provided by the io.ReadSeeker which is metadata invariant.

func SumID3v2

func SumID3v2(r io.ReadSeeker) (string, error)

SumID3v2 constructs a checksum of MP3 audio file data (assumed to have ID3v2 tags) provided by the io.ReadSeeker which is metadata invariant.

func WriteAPE

func WriteAPE(filePath string, opts WriteOptions) error

WriteAPE writes APEv2 tags to a Monkey's Audio file.

The APEv2 tag sits at the end of the file. This function:

  1. Reads the entire file
  2. Strips any existing APETAGEX footer + items from the end
  3. Constructs new APEv2 items from WriteOptions
  4. Appends the new items + APETAGEX footer
  5. Writes atomically via temp file + rename

func WriteFLAC

func WriteFLAC(filePath string, opts WriteOptions) error

WriteFLAC 写入 FLAC 文件的 Vorbis Comment + Picture 元数据。

流程:

  1. 校验 "fLaC" 魔数
  2. 解析现有元数据块,保留 STREAMINFO + SEEKTABLE + CUESHEET + APPLICATION; 丢弃旧的 VORBIS_COMMENT / PICTURE / PADDING
  3. 用 opts 构造新的 VORBIS_COMMENT 块和 PICTURE 块
  4. 重新写文件:[fLaC][保留块][新 vc][新 picture][audio frames]

func WriteID3v2

func WriteID3v2(filePath string, opts WriteOptions) error

WriteID3v2 writes an ID3v2.3 tag at the start of an MP3 file.

流程:

  1. 打开原文件,检测是否存在旧 ID3v2 头;有则定位音频数据起始偏移
  2. 编码新 frames(TIT2/TPE1/TPE2/TALB/TYER/TCON/USLT/APIC)
  3. 写到临时文件:[ID3v2 header][frames][padding=0][原音频数据]
  4. 原子重命名覆盖原文件

若 opts 各字段全为空,函数等价于"重写 ID3v2 头为空 tag",但仍会消耗一次 I/O。 调用方可在写入前自行判断。

func WriteMP4

func WriteMP4(filePath string, opts WriteOptions) error

WriteMP4 writes iTunes-style metadata atoms into an M4A/MP4 file.

流程:

  1. 扫描顶层 atom 列表,定位 moov
  2. 解析 moov 内部,找到 udta > meta > ilst(不存在则创建)
  3. 用 opts 构建新 ilst
  4. 替换 moov 中的 ilst 区域,级联更新父容器 size
  5. 如果 moov 在 mdat 之前,更新 stco/co64 偏移
  6. 原子写入临时文件后 rename

func WriteOGG

func WriteOGG(filePath string, opts WriteOptions) error

WriteOGG writes Vorbis Comment metadata to an Ogg Vorbis/Opus file.

流程:

  1. 读取所有 OGG 页,按 serial 重组 packet
  2. 识别编解码器(Vorbis/Opus),定位 comment packet
  3. 用 opts 构建新 comment packet(复用 buildFLACVorbisComment)
  4. 重新分页 header packets,逐页复制音频数据(更新 sequence + CRC)
  5. 原子写入临时文件后 rename

func WriteTag

func WriteTag(filePath string, opts WriteOptions) error

WriteTag writes the supplied metadata into the music file at filePath.

The format is selected by file extension. Supported formats and their tag mappings:

Format          | Text fields              | Lyrics      | Picture
.mp3            | ID3v2.3 text frames      | USLT        | APIC
.flac           | Vorbis Comment           | LYRICS      | PICTURE block
.m4a/.mp4/.m4b  | iTunes atoms (©nam etc)  | ©lyr        | covr
.ogg/.oga       | Vorbis Comment           | LYRICS      | METADATA_BLOCK_PICTURE
.ape            | APEv2 items              | Lyrics      | Cover Art (Front) (binary)
.wav            | RIFF LIST INFO           | ICMT        | (not supported)

Returns ErrUnsupportedWrite for other extensions. The original file is rewritten atomically (write to a sibling temp file then rename).

func WriteWAV

func WriteWAV(filePath string, opts WriteOptions) error

WriteWAV writes RIFF LIST INFO metadata to a WAV file.

WAV files are RIFF containers. Metadata goes in a "LIST" chunk with subtype "INFO", containing sub-chunks like INAM (title), IART (artist), IPRD (album), ICRD (year), IGNR (genre), ICMT (lyrics).

This function:

  1. Validates the RIFF/WAVE header
  2. Scans existing chunks, keeping all non-tag chunks
  3. Builds a new LIST INFO chunk from WriteOptions
  4. Rewrites the file atomically via temp file + rename

Types

type Comm

type Comm struct {
	Language    string
	Description string
	Text        string
}

Comm is a type used in COMM, UFID, TXXX, WXXX and USLT tag. It's a text with a description and a specified language For WXXX, TXXX and UFID, we don't set a Language

func (Comm) String

func (t Comm) String() string

String returns a string representation of the underlying Comm instance.

type FileType

type FileType string

FileType is an enumeration of the audio file types supported by this package, in particular there are audio file types which share metadata formats, and this type is used to distinguish between them.

const (
	UnknownFileType FileType = ""     // Unknown FileType.
	MP3             FileType = "MP3"  // MP3 file
	M4A             FileType = "M4A"  // M4A file Apple iTunes (ACC) Audio
	M4B             FileType = "M4B"  // M4A file Apple iTunes (ACC) Audio Book
	M4P             FileType = "M4P"  // M4A file Apple iTunes (ACC) AES Protected Audio
	ALAC            FileType = "ALAC" // Apple Lossless file FIXME: actually detect this
	FLAC            FileType = "FLAC" // FLAC file
	OGG             FileType = "OGG"  // OGG file
	DSF             FileType = "DSF"  // DSF file DSD Sony format see https://dsd-guide.com/sites/default/files/white-papers/DSFFileFormatSpec_E.pdf
	WAV             FileType = "WAV"  // WAVE file
	APE             FileType = "APE"  // Monkey's Audio file
)

Supported file types.

type Format

type Format string

Format is an enumeration of metadata types supported by this package.

const (
	UnknownFormat Format = ""        // Unknown Format.
	ID3v1         Format = "ID3v1"   // ID3v1 tag format.
	ID3v2_2       Format = "ID3v2.2" // ID3v2.2 tag format.
	ID3v2_3       Format = "ID3v2.3" // ID3v2.3 tag format (most common).
	ID3v2_4       Format = "ID3v2.4" // ID3v2.4 tag format.
	MP4           Format = "MP4"     // MP4 tag (atom) format (see http://www.ftyps.com/ for a full file type list)
	VORBIS        Format = "VORBIS"  // Vorbis Comment tag format.
	APEv2         Format = "APEv2"   // APEv2 tag format (Monkey's Audio / WavPack / Musepack)
)

Supported tag formats.

type Metadata

type Metadata interface {
	// Format returns the metadata Format used to encode the data.
	Format() Format

	// FileType returns the file type of the audio file.
	FileType() FileType

	// Title returns the title of the track.
	Title() string

	// Album returns the album name of the track.
	Album() string

	// Artist returns the artist name of the track.
	Artist() string

	// AlbumArtist returns the album artist name of the track.
	AlbumArtist() string

	// Composer returns the composer of the track.
	Composer() string

	// Year returns the year of the track.
	Year() int

	// Genre returns the genre of the track.
	Genre() string

	// Track returns the track number and total tracks, or zero values if unavailable.
	Track() (int, int)

	// Disc returns the disc number and total discs, or zero values if unavailable.
	Disc() (int, int)

	// Picture returns a picture, or nil if not available.
	Picture() *Picture

	// Lyrics returns the lyrics, or an empty string if unavailable.
	Lyrics() string

	// Comment returns the comment, or an empty string if unavailable.
	Comment() string

	// Raw returns the raw mapping of retrieved tag names and associated values.
	// NB: tag/atom names are not standardised between formats.
	Raw() map[string]interface{}

	Duration() time.Duration

	// BitRate returns the average bitrate in kbps, or 0 if not available
	// from the container (e.g. ID3v1, generic MP4 without stsd parsing).
	BitRate() int

	// SampleRate returns the audio sampling rate in Hz, or 0 if not available.
	SampleRate() int
}

Metadata is an interface which is used to describe metadata retrieved by this package.

func ReadAPEMeta

func ReadAPEMeta(r io.ReadSeeker) (Metadata, error)

ReadAPEMeta reads Monkey's Audio metadata from the io.ReadSeeker.

APE files start with "MAC " magic at offset 0. For version >= 3.98 (3980) the file has a 52-byte APE_DESCRIPTOR followed by a separate APE_HEADER; older versions use a flat header. Text tags are stored in an APEv2 footer at the end of the file.

func ReadAtoms

func ReadAtoms(r io.ReadSeeker) (Metadata, error)

ReadAtoms reads MP4 metadata atoms from the io.ReadSeeker into a Metadata, returning non-nil error if there was a problem.

func ReadDSFMeta

func ReadDSFMeta(r io.ReadSeeker) (Metadata, error)

ReadDSFMeta reads DSF metadata from the io.ReadSeeker, returning the resulting metadata in a Metadata implementation, or non-nil error if there was a problem. samples: http://www.2l.no/hires/index.html

func ReadFLACMeta

func ReadFLACMeta(r io.ReadSeeker) (Metadata, error)

ReadFLACMeta reads FLAC metadata from the io.ReadSeeker, returning the resulting metadata in a Metadata implementation, or non-nil error if there was a problem.

func ReadFrom

func ReadFrom(r io.ReadSeeker) (Metadata, error)

ReadFrom detects and parses audio file metadata tags (currently supports ID3v1,2.{2,3,4}, MP4, FLAC/OGG). Returns non-nil error if the format of the given data could not be determined, or if there was a problem parsing the data.

func ReadOGGMeta

func ReadOGGMeta(r io.Reader) (Metadata, error)

ReadOGGMeta reads OGG metadata from the io.ReadSeeker, returning the resulting metadata in a Metadata implementation, or non-nil error if there was a problem. See http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html and http://www.xiph.org/ogg/doc/framing.html for details. For Opus see https://tools.ietf.org/html/rfc7845

func ReadV1MP3Meta

func ReadV1MP3Meta(r io.ReadSeeker, size int64) (Metadata, error)

func ReadV2MP3Meta

func ReadV2MP3Meta(r io.ReadSeeker, size int64) (Metadata, error)

func ReadWAVMeta

func ReadWAVMeta(r io.ReadSeeker) (Metadata, error)

ReadWAVMeta reads WAV metadata from the io.ReadSeeker, returning the resulting metadata in a Metadata implementation, or non-nil error if there was a problem.

type Picture

type Picture struct {
	Ext         string // Extension of the picture file.
	MIMEType    string // MIMEType of the picture.
	Type        string // Type of the picture (see pictureTypes).
	Description string // Description.
	Data        []byte // Raw picture data.
}

Picture is a type which represents an attached picture extracted from metadata.

func (Picture) String

func (p Picture) String() string

String returns a string representation of the underlying Picture instance.

type UFID

type UFID struct {
	Provider   string
	Identifier []byte
}

UFID is composed of a provider (frequently a URL and a binary identifier) The identifier can be a text (Musicbrainz use texts, but not necessary)

func (UFID) String

func (u UFID) String() string

type WriteOptions

type WriteOptions struct {
	Title       string
	Artist      string
	Album       string
	AlbumArtist string
	Year        int
	Genre       string
	Lyrics      string   // UTF-8 lyrics; embedded as USLT (MP3) / LYRICS or unsynced lyrics (others)
	Picture     *Picture // Cover art (MIMEType + Data required; Description optional)
}

WriteOptions describes the metadata fields that should be written to a music file. Empty string fields and a zero Year are skipped. A nil Picture means no embedded cover is written (an existing one in the file is left untouched only when the underlying format supports incremental updates; otherwise the picture frame may be cleared — see per-format docs).

Directories

Path Synopsis
cmd
check command
The check tool performs tag lookups on full music collections (iTunes or directory tree of files).
The check tool performs tag lookups on full music collections (iTunes or directory tree of files).
sum command
The sum tool constructs a checksum of a media file exluding any metadata (as recognised by the tag library).
The sum tool constructs a checksum of a media file exluding any metadata (as recognised by the tag library).
tag command
The tag tool reads metadata from media files (as supported by the tag library).
The tag tool reads metadata from media files (as supported by the tag library).
internal
Package mbz extracts MusicBrainz Picard-specific tags from general tag metadata.
Package mbz extracts MusicBrainz Picard-specific tags from general tag metadata.

Jump to

Keyboard shortcuts

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