Skip to main content

Overview

The MetadataHandler class provides a comprehensive interface for managing audio metadata across multiple formats. It supports reading and writing tags, cover art, lyrics, and audio file properties.

Supported Audio Formats

  • MP3 (ID3v2 tags)
  • FLAC (Vorbis Comments)
  • OGG Vorbis (Vorbis Comments)
  • MP4/M4A (iTunes-style tags)

Constructor

filepath
str
required
Absolute or relative path to the audio file to load
from tagqt.core.tags import MetadataHandler

handler = MetadataHandler("/path/to/song.mp3")

Methods

load_file()

Loads the audio file using mutagen. Called automatically by the constructor.
handler.load_file()
return
None
No return value. Sets self.audio to the loaded mutagen file object.

get_tag()

Retrieves a tag value from the audio file.
tag
str
required
Tag name (e.g., ‘title’, ‘artist’, ‘album’)
title = handler.get_tag('title')
artist = handler.get_tag('artist')
return
str
Tag value as a string, or empty string if tag doesn’t exist

set_tag()

Sets a tag value in the audio file metadata.
tag
str
required
Tag name to set
value
str | list
required
Value to set. If a list is provided, duplicates are automatically removed while preserving order.
handler.set_tag('title', 'New Song Title')
handler.set_tag('genre', ['Rock', 'Alternative'])
return
None
No return value. Modifies metadata in memory (call save() to persist changes).

save()

Saves all metadata changes to the audio file. Also auto-saves lyrics to .lrc file if present.
handler.title = "New Title"
handler.artist = "New Artist"
handler.save()
return
None
Writes changes to disk

save_lyrics_file()

Saves lyrics to a .lrc file with the same name as the audio file.
handler.lyrics = "[00:00.00] First line\n[00:05.00] Second line"
handler.save_lyrics_file()
return
None
Creates/overwrites a .lrc file in the same directory as the audio file

save_cover_file()

Saves cover art to cover.jpg in the same directory as the audio file.
data
bytes
default:"None"
Image data to save. If None, extracts from existing tags.
overwrite
bool
default:"True"
Whether to overwrite existing cover.jpg file
# Save embedded cover art to file
handler.save_cover_file()

# Save specific image data
with open('new_cover.jpg', 'rb') as f:
    image_data = f.read()
handler.save_cover_file(data=image_data)

# Don't overwrite if cover.jpg already exists
handler.save_cover_file(overwrite=False)
return
None
Creates/overwrites cover.jpg file

get_cover()

Extracts cover art from the audio file’s embedded metadata.
cover_data = handler.get_cover()
if cover_data:
    with open('extracted_cover.jpg', 'wb') as f:
        f.write(cover_data)
return
bytes | None
Raw image data (JPEG or PNG), or None if no cover art is embedded

set_cover()

Embeds cover art into the audio file with optional automatic resizing.
data
bytes
required
Raw image data (JPEG, PNG, or other PIL-supported format)
max_size
int
default:"500"
Maximum width/height in pixels. Images larger than this are automatically resized while maintaining aspect ratio. Set to 0 or None to disable resizing.
# Load and embed cover art
with open('cover.jpg', 'rb') as f:
    cover_data = f.read()

handler.set_cover(cover_data)  # Auto-resize to 500x500
handler.set_cover(cover_data, max_size=1000)  # Resize to 1000x1000
handler.set_cover(cover_data, max_size=None)  # No resizing
handler.save()
return
None
Embeds image into metadata (call save() to persist)

Properties

All properties support both reading and writing. Changes are not persisted until save() is called.

Metadata Properties

title
str
Track title
artist
str
Track artist(s)
album
str
Album name
album_artist
str
Album artist (for compilations)
year
str
Release year or full date (maps to ‘date’ tag)
genre
str
Music genre
comment
str
Track comment/description
handler.title = "Song Title"
handler.artist = "Artist Name"
handler.album = "Album Name"
handler.year = "2024"
handler.genre = "Rock"
handler.save()

Track Numbering Properties

track_number
str
Track number (e.g., “1” or “1/12”)
track_total
str
Total tracks on disc (FLAC/OGG only). Stored as separate TRACKTOTAL tag.
disc_number
str
Disc number (e.g., “1” or “1/2”). For FLAC/OGG, automatically combines with DISCTOTAL if available.
# Simple track number
handler.track_number = "5"

# FLAC/OGG with separate total
handler.track_number = "5"
handler.track_total = "12"

# Disc number with total (FLAC/OGG)
handler.disc_number = "1/2"  # Auto-splits into discnumber and DISCTOTAL

Advanced Metadata Properties

bpm
str
Tempo in beats per minute
initial_key
str
Musical key (e.g., “Am”, “C#m”)
isrc
str
International Standard Recording Code
publisher
str
Record label/publisher (maps to ‘organization’ tag)
handler.bpm = "128"
handler.initial_key = "Am"
handler.isrc = "USRC17607839"
handler.publisher = "Example Records"

Lyrics Property

lyrics
str
Song lyrics. Supports format-specific storage:
  • MP3: USLT (Unsynchronized Lyrics) ID3 frame
  • FLAC/OGG: LYRICS Vorbis comment
  • MP4: ©lyr atom
# Set plain text lyrics
handler.lyrics = """Verse 1
First line
Second line
"""

# Set synced LRC lyrics
handler.lyrics = """[00:12.00]Line 1
[00:17.20]Line 2
"""

handler.save()

Read-Only Audio Properties

These properties extract technical information from the audio file and cannot be modified.
duration
int
Track duration in seconds
bitrate
int
Audio bitrate in kbps (kilobits per second)
sample_rate
int
Sample rate in kHz (kilohertz)
filesize
float
File size in MB (megabytes), rounded to 2 decimal places
print(f"Duration: {handler.duration}s")
print(f"Bitrate: {handler.bitrate} kbps")
print(f"Sample Rate: {handler.sample_rate} kHz")
print(f"File Size: {handler.filesize} MB")

Complete Example

from tagqt.core.tags import MetadataHandler

# Load an audio file
handler = MetadataHandler("/music/song.mp3")

# Read existing metadata
print(f"Title: {handler.title}")
print(f"Artist: {handler.artist}")
print(f"Duration: {handler.duration}s")
print(f"Bitrate: {handler.bitrate} kbps")

# Update metadata
handler.title = "New Song Title"
handler.artist = "New Artist"
handler.album = "New Album"
handler.year = "2024"
handler.track_number = "3"
handler.genre = "Electronic"

# Add lyrics
handler.lyrics = """[00:00.00]First line
[00:05.00]Second line
"""

# Embed cover art (auto-resized to 500x500)
with open('cover.jpg', 'rb') as f:
    handler.set_cover(f.read())

# Save all changes
handler.save()
print("Metadata updated successfully!")

# Extract cover art to file
handler.save_cover_file()
print("Cover saved to cover.jpg")

Format-Specific Notes

MP3 (ID3)

  • Uses EasyID3 for standard tags
  • Lyrics stored in USLT frames
  • Cover art stored in APIC frames (always converted to JPEG)
  • UTF-8 encoding (ID3v2.4)

FLAC

  • Uses Vorbis Comments
  • Supports TRACKTOTAL and DISCTOTAL separate tags
  • Cover art stored as Picture blocks
  • Lossless metadata storage

OGG Vorbis

  • Uses Vorbis Comments (same as FLAC)
  • Supports TRACKTOTAL and DISCTOTAL
  • Cover art stored as Picture blocks

MP4/M4A

  • Uses iTunes-style atoms
  • Lyrics stored in ©lyr atom
  • Cover art stored in ‘covr’ atom
  • Automatically converts images to JPEG format

Build docs developers (and LLMs) love