Skip to main content

A synced lyric fetcher and embedder for music files

Project description

lrxy - Lyric Embedding Library

PyPI - Version Python Version from PEP 621 TOML

Embed lyrics directly into your audio files with a simple, consistent interface across multiple audio formats.

Features

  • Support multiple providers: Ablity to choose between different providers. Currently supported providers:
Provider Details
LRCLib Simple and reliable LRC provider
Apple Music Supports word-by-word lyrics
MusixMatch Large lyrics database used by most streaming services
  • Batch processing: Process multiple files efficiently
  • Support multiple formats: Support a wide range of audio formats and most used lyric formats including:
Format Details
LRC Extended LyRiC is a rich LRC format with word-by-word support and other features
TTML Timed Text Markup Language standard by Apple
SRT Popular line-by-line media subtitle format

Installation

Using pip:

pip install lrxy

Using uv:

uv tool install lrxy  # as a cli tool
uv pip install lrxy   # as a python module

Command Line

lrxy

A synced lyric fetcher and embedder for music files

usage: lrxy [-h] [-n | --embed FILE] [-f {ttml,lrc,srt,json}]
            [-p {lrclib,musixmatch,applemusic}] [--no-overwrite]
            [--shell-completion {bash,zsh,fish}]
            [--log-level {error,warning,info,debug}] [-v]
            MUSIC_FILE [MUSIC_FILE ...]

positional arguments:
  MUSIC_FILE            path of music file to process

options:
  -h, --help            show this help message and exit
  -n, --no-embed        write lyrics to separate text files
  --embed FILE          embed existing lyric file into music
  -f {ttml,lrc,srt,json}, --format {ttml,lrc,srt,json}
                        output lyrics format
  -p {lrclib,musixmatch,applemusic}, --provider {lrclib,musixmatch,applemusic}
                        provider to fetch lyrics
  --no-overwrite        do not overwrite existing lyrics
  --shell-completion {bash,zsh,fish}
                        provide shell completion
  --log-level {error,warning,info,debug}
                        command line verbosity
  -v, --version         show current lrxy version and exit

Provider is going to be lrclib by default

lrxy-convert

A tool from lrxy to convert between different lyric formats

usage: lrxy-convert [-h] [-i {ttml,lrc,srt,json}]
                    [-o {ttml,lrc,srt,json}]
                    [--shell-completion {bash,zsh,fish}]
                    [--log-level {error,warning,info,debug}]
                    INPUT OUTPUT

positional arguments:
  INPUT                 path of the input file to convert from
  OUTPUT                path of the output file to convert to

options:
  -h, --help            show this help message and exit
  -i {ttml,lrc,srt,json}, --input-format {ttml,lrc,srt,json}
                        input lyric file format
  -o {ttml,lrc,srt,json}, --output-format {ttml,lrc,srt,json}
                        output lyric file format
  --shell-completion {bash,zsh,fish}
                        provide shell completion
  --log-level {error,warning,info,debug}
                        command line verbosity

The default output is a json structed data

Example

Easy to use automatic batch lyric fetch and embed:

lrxy song1.mp3 song2.flac

Get lyric for songs as a separate ttml file from Apple Music:

lrxy -p applemusic -n song.opus

Embed a lyric file to a music without any further steps:

lrxy --embed lyric.lrc song.m4a

Convert a ttml file to an elrc type format:

lrxy-convert lyric.ttml lyric.lrc

You can also pipe with specifying the format manually:

lrxy-convert lyric.srt -o ttml - | cat

Quick Start

from lrxy.utils import load_audio, iter_files
from lrxy.providers import lrclib_api

# Load any audio file (MP3, FLAC, M4A, etc.)
for result in iter_files("song1.mp3", "song2.flac", provider=lrclib_api):
    audio = result["music_obj"]
    lyric = result["data"]["lyric"]
    if lyric:
        audio.embed_lyric(lyric)

Usage

Basic Lyric Embedding

from lrxy.utils import load_audio

# Load audio file (format detected automatically)
audio = load_audio("path/to/song.mp3")

# Check required metadata
print(f"Artist: {audio.artist}")
print(f"Title: {audio.title}")
print(f"Album: {audio.album}")
print(f"Duration: {audio.duration} seconds")

# Embed lyrics
audio.embed_lyric("Verse 1\nThis is a line\n\nChorus\nThis is the chorus")

Lyric Converting

from lrxy.converter import ttml, lrc

with open("path/to/lyric.ttml", "r") as f:
  ttml_lyric = f.read()

# parse the contents of the ttml file into a structed json data
data = ttml.parse(ttml_lyric)

# generate lrc format lyric from the structed data
lrc_lyric = lrc.generate(data)

with open("path/to/output/lyric.lrc", "w") as f:
  f.write(lrc_lyric)

Batch Processing

from lrxy.utils import iter_files

# Process multiple files with automatic lyric fetching
for result in iter_files("song1.mp3", "song2.flac", "song3.m4a"):
    if not result['success']:
        print(f"❌ {result['path'].name}: {result['error']}")
    elif not result['data']['syncedLyrics']:
        print(f"⚠️  {result['music_obj'].track_name}: No lyrics found")
    else:
        result['music_obj'].embed_lyric(result['syncedLyrics'])
        print(f"✅ {result['music_obj'].track_name}")

Embed Lyrics from File

from lrxy.utils import load_audio

audio = load_audio("song.mp3")
audio.embed_from_file("song.lrc")

Supported Audio Formats

lrxy supports the most common audio formats with consistent API access:

Format File Extensions Tag Standard Notes
MP3 .mp3 ID3 Supports both ID3v2.3 and ID3v2.4 and uses USLT tag to store lyric
FLAC, Opus .flac, .opus Vorbis Comments Stores lyrics in standard lyrics field
Ogg Vorbis .ogg, .oga Vorbis Comments Same as FLAC format handling
M4A/MP4 .m4a, .mp4, .aac MP4 atoms Uses Apple's ©lyr field

Format-Specific Details

MP3 (ID3 Tags)

  • Required metadata: Artist (TPE1), Title (TIT2), Album (TALB)
  • Lyrics storage: USLT frame (unsynchronized lyrics)

FLAC/Ogg (Vorbis Comments)

  • Required metadata: Artist (artist), Title (title), Album (album)
  • Lyrics storage: Standard lyrics field
  • Special handling: Preserves all existing metadata while updating lyrics

M4A/MP4 (MP4 Atoms)

  • Required metadata: Artist (©ART), Title (©nam), Album (©alb)
  • Lyrics storage: Apple's ©lyr field
  • Special handling: Compatible with iTunes, Apple Music, and modern players

Error Handling

lrxy provides consistent error reporting through a standardized result structure:

from lrxy.utils import iter_files

for result in iter_files("song1.mp3", "invalid_file.xyz"):
    if not result['success']:
        # All errors have the same structure
        print(f"Error processing {result['path'].name}:")
        print(f"- Type: {result['error']}")
        print(f"- Message: {result['message']}")
    else:
        # Successful results have consistent structure
        print(f"Processed {result['music_obj'].track_name}")

Common Error Types

Error Type Description Likely Cause
notfound Lyrics not found Incorrect metadata or unavailable lyrics
network Network/connection issue Internet problems or API downtime
api API response error Invalid response format from lyric provider
format Unsupported audio format File extension not recognized
tag Missing required metadata Artist/title/album not present in file

Advanced Usage

Custom Lyric Provider

from lrxy.utils import iter_files
from lrxy.providers import lrclib_api

# Create custom provider function
def my_provider(tags):
    # Your custom implementation
    return lrclib_api(tags)  # Or your own API client

# Use with iter_files
for result in iter_files("song.mp3", provider=my_provider):
    # Process results...

Skip Files with Existing Lyrics

from lrxy.utils import iter_files

# Only process files without existing lyrics
for result in iter_files("Music/*.mp3"):
    audio = result['music_obj']
    if result['success']:
        lyric = result['data']['syncedLyrics']:
        if not audio.has_lyric:
            audio.embed_lyric(lyric, overwrite=False)

Requirements

  • Python 3.10+
  • Mutagen (installed automatically as dependency)

Acknowledgments

  • Paxsenix API: For Apple Music and MusixMatch providers
  • LRCLib: For their great lyric platform

License

Distributed under the GPLv2 License. See LICENSE for more information.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lrxy-1.1.3.tar.gz (61.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lrxy-1.1.3-py3-none-any.whl (56.2 kB view details)

Uploaded Python 3

File details

Details for the file lrxy-1.1.3.tar.gz.

File metadata

  • Download URL: lrxy-1.1.3.tar.gz
  • Upload date:
  • Size: 61.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for lrxy-1.1.3.tar.gz
Algorithm Hash digest
SHA256 876fe2ecb6ef6d7d7c86601953e7756921d464e285c1d482bf462466355d2955
MD5 b33ca665968b210ebf2a331ac7c62ca0
BLAKE2b-256 27650b15d42198d4302b312735c1a84e427a5e9758d55293caa82eb4ba4d4f81

See more details on using hashes here.

File details

Details for the file lrxy-1.1.3-py3-none-any.whl.

File metadata

  • Download URL: lrxy-1.1.3-py3-none-any.whl
  • Upload date:
  • Size: 56.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for lrxy-1.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 01f0dceba1badef68d9c084d0da6ccad599bc486b227859e9af2c6970f0a727d
MD5 d2a696a42f270f1013c2db1a2b973aac
BLAKE2b-256 57ca0dee2149aadfc9f5c4ecebf514bbb446b242acc1e0b7e6e3d790cc78d529

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page