Skip to main content

Overview

The LyricsFetcher class provides an interface to search and retrieve song lyrics from the LRCLIB API. It supports both synced (timestamped) and plain text lyrics.

Constructor

Instantiate the fetcher before making requests:
from tagqt.core.lyric import LyricsFetcher

fetcher = LyricsFetcher()

Methods

search_lyrics()

Searches for lyrics matching the given artist and track title.
artist
str
required
Artist name to search for
title
str
required
Track title to search for
album
str
default:"None"
Album name (currently not used in search but available for future filtering)
from tagqt.core.lyric import LyricsFetcher

fetcher = LyricsFetcher()
results = fetcher.search_lyrics(
    artist="Radiohead",
    title="Paranoid Android"
)

if results:
    for result in results:
        print(f"Track: {result['trackName']}")
        print(f"Artist: {result['artistName']}")
        print(f"Album: {result['albumName']}")
        print(f"Synced: {result['isSynced']}")
        print()
return
list[dict]
List of lyric results. Returns empty list on error or no results found.Each result dictionary contains:
  • id (int): LRCLIB lyric ID
  • trackName (str): Track title
  • artistName (str): Artist name
  • albumName (str): Album name
  • duration (float): Track duration in seconds
  • syncedLyrics (str | None): Time-synced LRC format lyrics
  • plainLyrics (str | None): Plain text lyrics without timestamps
  • isSynced (bool): Whether synced lyrics are available

Response Format

Synced Lyrics (LRC Format)

Time-synced lyrics use the LRC format with timestamps:
[00:00.00]Please could you stop the noise
[00:03.50]I'm trying to get some rest
[00:42.50]From all the unborn chicken voices
[00:46.00]In my head

Plain Lyrics

Plain text lyrics without timestamps:
Please could you stop the noise
I'm trying to get some rest
From all the unborn chicken voices
In my head

Complete Example

from tagqt.core.lyric import LyricsFetcher
from tagqt.core.tags import MetadataHandler

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

# Search for lyrics
fetcher = LyricsFetcher()
results = fetcher.search_lyrics(
    artist=handler.artist,
    title=handler.title,
    album=handler.album
)

if not results:
    print("No lyrics found")
else:
    # Use first result
    lyrics_data = results[0]
    
    print(f"Found lyrics for: {lyrics_data['trackName']} by {lyrics_data['artistName']}")
    print(f"Duration: {lyrics_data['duration']}s")
    
    # Prefer synced lyrics if available
    if lyrics_data['syncedLyrics']:
        print("Using synced lyrics (LRC format)")
        handler.lyrics = lyrics_data['syncedLyrics']
    elif lyrics_data['plainLyrics']:
        print("Using plain text lyrics")
        handler.lyrics = lyrics_data['plainLyrics']
    
    # Save lyrics to file and metadata
    handler.save()
    print("Lyrics saved!")

Filtering Results

When multiple results are returned, you may want to filter them:
results = fetcher.search_lyrics(
    artist="The Beatles",
    title="Yesterday"
)

# Filter for synced lyrics only
synced_results = [r for r in results if r['isSynced']]

# Filter by album
album_results = [
    r for r in results 
    if r['albumName'] and 'Help!' in r['albumName']
]

# Filter by duration (within 5 seconds of expected)
expected_duration = 125  # 2:05
close_duration = [
    r for r in results
    if abs(r['duration'] - expected_duration) < 5
]

Integration with MetadataHandler

The LyricsFetcher works seamlessly with MetadataHandler:
from tagqt.core.lyric import LyricsFetcher
from tagqt.core.tags import MetadataHandler

def fetch_and_save_lyrics(filepath):
    handler = MetadataHandler(filepath)
    fetcher = LyricsFetcher()
    
    # Search for lyrics
    results = fetcher.search_lyrics(
        artist=handler.artist,
        title=handler.title
    )
    
    if results:
        # Use synced lyrics if available, otherwise plain
        lyrics = results[0]['syncedLyrics'] or results[0]['plainLyrics']
        
        if lyrics:
            handler.lyrics = lyrics
            handler.save()  # Saves to tags and .lrc file
            return True
    
    return False

# Use the function
if fetch_and_save_lyrics("/music/song.mp3"):
    print("Lyrics fetched and saved successfully!")
else:
    print("No lyrics found")

Error Handling

The method handles network errors gracefully:
results = fetcher.search_lyrics(
    artist="Artist Name",
    title="Track Title"
)

if not results:
    print("No lyrics found or network error occurred")
else:
    print(f"Found {len(results)} result(s)")
Common scenarios:
  • Network timeout (10 second timeout)
  • Invalid response from API
  • No matching lyrics in database
All errors are caught and an empty list is returned.

API Details

  • Base URL: https://lrclib.net/api/search
  • Request timeout: 10 seconds
  • Rate limiting: No explicit rate limit enforced by client (respect LRCLIB’s fair use policy)
  • Search method: Combined artist + title search query

Dependencies

Requires the requests Python package:
pip install requests

Best Practices

  1. Verify results: Always check if results list is non-empty before accessing
  2. Prefer synced lyrics: Check isSynced flag for better user experience
  3. Handle multiple results: The API may return several matches; filter or present choices to user
  4. Metadata quality: Ensure artist and title metadata are accurate for better search results
  5. LRC file format: When using synced lyrics, they’re automatically saved as .lrc files by MetadataHandler.save()

Build docs developers (and LLMs) love