or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-tinytag

Read audio file metadata

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/tinytag@2.1.x

To install, run

npx @tessl/cli install tessl/pypi-tinytag@2.1.0

index.mddocs/

TinyTag

TinyTag is a pure Python library for reading metadata from various audio file formats including MP3, M4A, WAVE, OGG, FLAC, WMA, and AIFF. It provides a unified API across all supported formats, allowing developers to extract essential metadata such as title, artist, album, track numbers, duration, bitrate, and embedded images without requiring external dependencies.

Package Information

  • Package Name: tinytag
  • Language: Python
  • Installation: pip install tinytag
  • Python Version: 3.7+
  • License: MIT

Core Imports

from tinytag import TinyTag

Complete imports for all functionality:

from tinytag import (
    TinyTag, Image, Images, OtherFields, OtherImages,
    TinyTagException, ParseError, UnsupportedFormatError,
    __version__
)

For type annotations (when needed):

from typing import BinaryIO, Any
from os import PathLike

Basic Usage

from tinytag import TinyTag

# Read basic metadata
tag = TinyTag.get('/path/to/audio/file.mp3')

print(f'Title: {tag.title}')
print(f'Artist: {tag.artist}')
print(f'Album: {tag.album}')
print(f'Duration: {tag.duration:.2f} seconds')
print(f'Bitrate: {tag.bitrate} kbps')

# Read metadata with images
tag = TinyTag.get('/path/to/audio/file.mp3', image=True)
if tag.images.front_cover:
    cover_data = tag.images.front_cover.data
    with open('cover.jpg', 'wb') as f:
        f.write(cover_data)

# Check if file is supported
if TinyTag.is_supported('/path/to/file.mp3'):
    tag = TinyTag.get('/path/to/file.mp3')

Capabilities

Audio File Metadata Reading

Parse audio files and extract metadata using a unified API across all supported formats.

class TinyTag:
    @classmethod
    def get(cls,
            filename: bytes | str | PathLike[Any] | None = None,
            file_obj: BinaryIO | None = None,
            tags: bool = True,
            duration: bool = True,
            image: bool = False,
            encoding: str | None = None,
            ignore_errors: bool | None = None) -> TinyTag:
        """
        Return a TinyTag instance for an audio file.
        
        Args:
            filename: Path to audio file
            file_obj: Binary file object (alternative to filename)
            tags: Whether to parse metadata tags
            duration: Whether to calculate audio duration
            image: Whether to load embedded images
            encoding: Text encoding override for some formats
            ignore_errors: Deprecated parameter
            
        Returns:
            TinyTag instance with parsed metadata
            
        Raises:
            ParseError: If parsing fails
            ValueError: If neither filename nor file_obj provided
        """
    
    @classmethod
    def is_supported(cls, filename: bytes | str | PathLike[Any]) -> bool:
        """
        Check if a file is supported based on its extension.
        
        Args:
            filename: Path to file to check
            
        Returns:
            True if file extension is supported
        """
    
    SUPPORTED_FILE_EXTENSIONS: tuple[str, ...] = (
        '.mp1', '.mp2', '.mp3',
        '.oga', '.ogg', '.opus', '.spx',
        '.wav', '.flac', '.wma',
        '.m4b', '.m4a', '.m4r', '.m4v', '.mp4', '.aax', '.aaxc',
        '.aiff', '.aifc', '.aif', '.afc'
    )

Metadata Access

Access standard metadata fields and file properties through instance attributes.

# Audio Properties
filename: str | None          # Original filename
filesize: int                 # File size in bytes
duration: float | None        # Duration in seconds
channels: int | None          # Number of audio channels
bitrate: float | None         # Bitrate in kBits/s
bitdepth: int | None          # Bit depth (for lossless)
samplerate: int | None        # Sample rate in Hz

# Metadata Fields
artist: str | None            # Primary artist
albumartist: str | None       # Album artist
composer: str | None          # Composer
album: str | None             # Album title
disc: int | None              # Disc number
disc_total: int | None        # Total discs
title: str | None             # Track title
track: int | None             # Track number
track_total: int | None       # Total tracks
genre: str | None             # Genre
year: str | None              # Year or date
comment: str | None           # Comment field

# Additional Data
images: Images                # Embedded images
other: OtherFields           # Additional metadata

Dictionary Export

Convert metadata to dictionary format for serialization or processing.

def as_dict(self) -> dict[str, str | float | list[str]]:
    """
    Return flat dictionary representation of metadata.
    
    Returns:
        Dictionary with metadata fields, lists for multiple values
    """

# Deprecated Methods (will be removed in future versions)
def get_image(self) -> bytes | None:
    """
    DEPRECATED: Use images.any instead.
    Return bytes of any embedded image.
    
    Returns:
        Image data bytes or None if no image available
    """

@property
def extra(self) -> dict[str, str]:
    """
    DEPRECATED: Use 'other' attribute instead.
    Legacy access to additional metadata fields.
    
    Returns:
        Dictionary of extra metadata fields
    """

@property
def audio_offset(self) -> None:
    """
    OBSOLETE: Always returns None.
    This property is no longer used and will be removed.
    
    Returns:
        None
    """

Image Handling

Access embedded images like album artwork with full metadata support.

class Images:
    """Container for embedded images in audio files."""
    
    front_cover: Image | None    # Front cover image
    back_cover: Image | None     # Back cover image  
    media: Image | None          # Media/CD label image
    other: OtherImages          # Additional images
    
    @property
    def any(self) -> Image | None:
        """
        Return any available image, prioritizing front cover.
        
        Returns:
            First available image or None
        """
    
    def as_dict(self) -> dict[str, list[Image]]:
        """
        Return flat dictionary of all images.
        
        Returns:
            Dictionary mapping image types to lists of Image objects
        """

class Image:
    """Represents an embedded image in an audio file."""
    
    def __init__(self, name: str, data: bytes, mime_type: str | None = None) -> None:
        """
        Create Image instance.
        
        Args:
            name: Image type/name
            data: Binary image data
            mime_type: MIME type (e.g., 'image/jpeg')
        """
    
    name: str                    # Image type/name
    data: bytes                  # Binary image data
    mime_type: str | None        # MIME type
    description: str | None      # Image description

Additional Metadata

Access format-specific and extended metadata through standardized field names.

class OtherFields(dict[str, list[str]]):
    """Dictionary containing additional metadata fields."""
    
    # Standardized field names (when available):
    # barcode, bpm, catalog_number, conductor, copyright, director
    # encoded_by, encoder_settings, initial_key, isrc, language, license
    # lyricist, lyrics, media, publisher, set_subtitle, url

class OtherImages(dict[str, list[Image]]):
    """Dictionary containing additional embedded images."""
    
    # Standardized image types (when available):
    # generic, icon, alt_icon, front_cover, back_cover, media, leaflet
    # lead_artist, artist, conductor, band, composer, lyricist
    # recording_location, during_recording, during_performance, screen_capture
    # bright_colored_fish, illustration, band_logo, publisher_logo, unknown

Exception Handling

Handle errors during audio file parsing with specific exception types.

class TinyTagException(Exception):
    """Base exception for all TinyTag errors."""

class ParseError(TinyTagException):
    """Raised when parsing an audio file fails."""

class UnsupportedFormatError(TinyTagException):
    """Raised when file format is not supported."""

Version Information

Access the library version for compatibility checks.

__version__: str  # Current library version (e.g., "2.1.2")

Command Line Interface

Use tinytag from the command line to extract metadata and save images.

# Basic usage
python -m tinytag /path/to/audio.mp3

# Save cover image  
python -m tinytag -i cover.jpg /path/to/audio.mp3

# Different output formats
python -m tinytag -f csv /path/to/audio.mp3
python -m tinytag -f json /path/to/audio.mp3

# Skip unsupported files
python -m tinytag -s /path/to/files/*
# Command line options:
# -h, --help                    Display help
# -i, --save-image <path>       Save cover art to file  
# -f, --format json|csv|tsv|tabularcsv  Output format
# -s, --skip-unsupported        Skip unsupported files

Usage Examples

Basic Metadata Extraction

from tinytag import TinyTag

# Parse audio file
tag = TinyTag.get('music.mp3')

# Access common metadata
print(f'Artist: {tag.artist}')
print(f'Title: {tag.title}')
print(f'Album: {tag.album}')
print(f'Duration: {tag.duration:.1f}s')
print(f'Bitrate: {tag.bitrate}kbps')

# Check audio properties
if tag.channels:
    print(f'Channels: {tag.channels}')
if tag.samplerate:
    print(f'Sample rate: {tag.samplerate}Hz')

Working with Images

from tinytag import TinyTag, Image

# Load file with images
tag = TinyTag.get('album.flac', image=True)

# Access front cover
if tag.images.front_cover:
    cover = tag.images.front_cover
    print(f'Cover: {cover.name} ({cover.mime_type})')
    print(f'Size: {len(cover.data)} bytes')
    
    # Save cover image
    with open('cover.jpg', 'wb') as f:
        f.write(cover.data)

# Get any available image
any_image = tag.images.any
if any_image:
    print(f'Found image: {any_image.name}')

# Legacy approach (deprecated - use images.any instead)
# image_data = tag.get_image()  # DEPRECATED
# if image_data:
#     with open('cover_legacy.jpg', 'wb') as f:
#         f.write(image_data)

# Access all images
all_images = tag.images.as_dict()
for image_type, images in all_images.items():
    print(f'{image_type}: {len(images)} images')

Additional Metadata

from tinytag import TinyTag

tag = TinyTag.get('detailed.mp3')

# Access additional fields
bpm_values = tag.other.get('bpm')
if bpm_values:
    print(f'BPM: {bpm_values[0]}')

lyrics = tag.other.get('lyrics')
if lyrics:
    print(f'Lyrics: {lyrics[0][:100]}...')

# Handle multiple artists
primary_artist = tag.artist
additional_artists = tag.other.get('artist', [])
all_artists = [primary_artist] + additional_artists if primary_artist else additional_artists
print(f'All artists: {", ".join(all_artists)}')

# Legacy metadata access (deprecated - use 'other' instead)
# extra_data = tag.extra  # DEPRECATED: returns dict[str, str]
# Use tag.other instead which returns dict[str, list[str]]

# Export all metadata
metadata = tag.as_dict()
for field, value in metadata.items():
    print(f'{field}: {value}')

Error Handling

from tinytag import TinyTag, ParseError, UnsupportedFormatError

try:
    # Check support first
    if not TinyTag.is_supported('file.unknown'):
        print('File format not supported')
        exit(1)
    
    # Parse file
    tag = TinyTag.get('file.mp3')
    print(f'Successfully parsed: {tag.title}')
    
except ParseError as e:
    print(f'Failed to parse file: {e}')
except UnsupportedFormatError as e:
    print(f'Unsupported format: {e}')
except Exception as e:
    print(f'Unexpected error: {e}')

File Object Usage

from tinytag import TinyTag
from io import BytesIO

# Using file object instead of filename
with open('audio.mp3', 'rb') as f:
    tag = TinyTag.get(file_obj=f)
    print(f'Title: {tag.title}')

# Using BytesIO
with open('audio.mp3', 'rb') as f:
    data = f.read()
    
file_obj = BytesIO(data)
tag = TinyTag.get(file_obj=file_obj)
print(f'Duration: {tag.duration}')

Version Information

from tinytag import __version__

# Check library version
print(f'TinyTag version: {__version__}')

# Version-dependent behavior
from packaging import version
if version.parse(__version__) >= version.parse('2.0.0'):
    # Use v2.x API features
    tag = TinyTag.get('file.mp3')
    if tag.track is not None:  # v2.x: integers
        print(f'Track: {tag.track}')
else:
    # Handle v1.x compatibility
    pass

Supported Formats

TinyTag supports the following audio formats:

  • MP3/MP2/MP1: ID3 v1, v1.1, v2.2, v2.3+
  • M4A: AAC and ALAC encoding
  • WAVE/WAV: Standard PCM and compressed
  • OGG: FLAC, Opus, Speex, Vorbis
  • FLAC: Free Lossless Audio Codec
  • WMA: Windows Media Audio
  • AIFF/AIFF-C: Audio Interchange File Format

All formats use the same unified API, ensuring consistent behavior across different audio file types.