How Folia Major's Lyrics Auto-Matching Algorithm Works: Word-by-Word Lyric Selection Explained

Folia Major's lyrics auto-matching algorithm queries multiple online providers in priority order, scores candidates using metadata matching heuristics, and selects the highest-scoring word-by-word lyric that exceeds a minimum reliability threshold of 75 points.

Folia Major implements a sophisticated multi-provider search strategy in src/utils/lyrics/autoMatchBestLyric.ts to automatically identify the best word-by-word lyrics for any given track. The algorithm normalizes track metadata, enforces strict timeout constraints, and cascades through NetEase, AMLLDB, QQ Music, and Kugou until it finds a perfect match or exhausts all options.

Core Workflow and Architecture

The autoMatchBestLyric function orchestrates the entire matching process through a series of discrete steps that ensure both accuracy and responsiveness.

Building the Search Query and Target Profile

The algorithm begins by constructing a normalized search profile. The buildLyricSearchQuery function creates a search string from the track's title, artist, and optional album metadata. Simultaneously, normalizeLyricMatchDurationMs rounds the track duration to the nearest second to avoid micro-mismatch errors.

A targetSong object is then assembled containing the normalized {title, artist, album?, durationMs} values. This object serves as the reference against which all provider candidates are scored.

Provider Selection Strategy

Folia Major queries providers in a specific priority order: NetEase → AMLLDB → QQ Music → Kugou. This ordering maximizes the probability of obtaining word-by-word lyrics with accurate chorus timing data. Users can optionally force a specific preferredSource to override this default sequence.

Each provider query is wrapped in withTimeout guards—3.5 seconds for search operations and 5 seconds for lyric fetching—to prevent any single slow provider from stalling the UI.

Scoring and Candidate Validation

For each provider, the algorithm retrieves the top AUTO_MATCH_SEARCH_LIMIT (10) results and evaluates them using calculateMatchScoreDetails from src/utils/lyrics/matchScore.ts. The scoring function assesses:

  • Title match: Exact comparison ignoring punctuation
  • Artist match: At least one artist name must correspond
  • Album match: Optional validation when album data is available
  • Duration match: Accepted if the absolute difference is ≤ 3 seconds

A candidate must satisfy the reliable match criteria (titleMatched && (artistMatched || albumMatched)) and achieve a score ≥ AUTO_MATCH_MIN_SCORE (75) to be considered valid. The selectBestCandidate function implements this filtering logic in src/utils/lyrics/autoMatchBestLyric.ts lines 53-81.

Provider-Specific Processing Logic

Each lyric source requires specialized handling to normalize the returned data into the standard LyricData format.

NetEase Primary Pipeline

As the preferred provider, NetEase receives priority processing. When the getNeteaseProcessed function identifies a valid candidate, it calls neteaseApi.getLyric and transforms the raw response using processNeteaseLyrics from src/utils/lyrics/neteaseProcessing.ts.

If the processed result indicates a pure-music track (processed.isPureMusic), the algorithm returns early with {isPureMusic:true}, avoiding unnecessary downstream processing. For standard tracks, when NetEase lyrics lack built-in chorus markers, the system fetches chorus ranges via fetchNeteaseChorusRanges and applies them using applyNeteaseChorusByTime from src/utils/lyrics/chorusEffects.ts.

AMLLDB Fallback Integration

If NetEase fails to deliver word-by-word lyrics, the algorithm attempts to retrieve TTML-formatted lyrics from the AMLLDB data store using fetchAmllDbLyrics. The tryAmllDbCandidate function (lines 102-130) accepts the result only if it contains word-by-word timing data, maintaining the quality standard.

QQ Music and Kugou Fallbacks

When NetEase and AMLLDB both fail, the system queries QQ Music via searchQQLyrics and fetchQQLyrics. QQ lyrics benefit from NetEase chorus range decoration when available. Finally, Kugou Music serves as the last resort through searchKugouLyrics and fetchKugouLyrics implementations in src/utils/lyrics/providers/kugouLyricProvider.ts.

Implementation Example

The following pattern demonstrates how to integrate the auto-matcher into a playback controller, as implemented in src/hooks/useLibraryPlaybackController.ts:

import { autoMatchBestLyric } from '@/utils/lyrics/autoMatchBestLyric';
import { useLibraryPlaybackController } from '@/hooks/useLibraryPlaybackController';

export function useAutoLyricMatcher(song) {
  const { setCurrentLyrics } = useLibraryPlaybackController();

  useEffect(() => {
    let cancelled = false;
    async function match() {
      const match = await autoMatchBestLyric(
        song.name,
        song.artist,
        song.duration || 0,
        { album: song.album }
      );
      if (!cancelled && match && !('isPureMusic' in match)) {
        setCurrentLyrics(match.lyrics);
      }
    }
    match();
    return () => { cancelled = true; };
  }, [song]);
}

For direct API usage, you can invoke the matcher with optional source preferences:

import { autoMatchBestLyric } from '@/utils/lyrics/autoMatchBestLyric';

async function getLyricsForTrack(title: string, artist: string, durationMs: number) {
  const result = await autoMatchBestLyric(title, artist, durationMs, {
    // optional: force QQ as the first source
    // preferredSource: 'qq',
  });

  if (result?.isPureMusic) {
    console.log('Track is pure instrumental – no lyrics needed.');
    return null;
  }

  if (!result) {
    console.warn('No suitable word‑by‑word lyric was found.');
    return null;
  }

  console.log(`Matched ${result.source} lyrics (ID: ${result.id})`);
  return result.lyrics; // LyricData ready for visualizer
}

Summary

  • Folia Major's lyrics auto-matching algorithm is implemented in src/utils/lyrics/autoMatchBestLyric.ts and uses a cascading provider strategy to find word-by-word lyrics.
  • The system queries NetEase → AMLLDB → QQ → Kugou in sequence, with strict timeout guards (3.5s for search, 5s for fetch) to maintain UI responsiveness.
  • Candidates are scored using calculateMatchScoreDetails and must achieve a minimum score of 75 while passing reliability checks (titleMatched && (artistMatched || albumMatched)).
  • NetEase is the primary source due to its chorus timing support, with fallback processing through AMLLDB for TTML lyrics and QQ/Kugou for standard formats.
  • Pure-music tracks are detected early to prevent unnecessary network requests, and chorus timing is applied across providers when available.

Frequently Asked Questions

What is the minimum match score required for Folia Major to accept a lyric candidate?

Folia Major requires a minimum score of 75 points (AUTO_MATCH_MIN_SCORE) for any candidate to be considered valid. This threshold ensures that only highly accurate matches—where title, artist, album, and duration metadata align closely with the target track—are accepted, preventing false positives from low-quality sources.

How does Folia Major handle cases where multiple lyric providers return results?

The algorithm processes providers in a strict priority order: NetEase first, followed by AMLLDB, QQ Music, and finally Kugou. For each provider, it retrieves up to 10 candidates (AUTO_MATCH_SEARCH_LIMIT), scores them all, and selects the best valid candidate from that provider before moving to the next. This ensures NetEase's superior word-by-word timing and chorus data is preferred when available, while maintaining robust fallback options.

What happens if a song is instrumental or pure music?

When processing NetEase results, the algorithm detects pure-music tracks through the isPureMusic flag in processNeteaseLyrics. If detected, the function returns immediately with {isPureMusic:true}, preventing unnecessary queries to downstream providers. This optimization saves bandwidth and processing time for instrumental tracks that lack lyrics.

Can users force a specific lyric provider instead of using the automatic selection?

Yes. The autoMatchBestLyric function accepts an optional preferredSource parameter in its options object. By setting this to 'qq', 'netease', 'kugou', or 'amlldb', users can override the default search order and force the algorithm to query only that specific provider first. If the preferred source fails to return a valid match, the system still falls back to the standard priority queue.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →