spotDL/spotify-downloader

MusixMatch lyrics provider broken: all requests blocked with HTTP 403 (TLS fingerprint bot detection)

Aberta

#2.741 aberto em 18 de jul. de 2026

 (3 comentários) (0 reação) (0 responsável)Python (1.418 forks)batch import
Good First IssueLyrics Provider

Métricas do repositório

Stars
 (14.703 estrelas)
Métricas de merge de PR
 (Mesclagem média 38d 15h) (1 fundiu PR em 30d)

Description

System OS

Windows

Python Version

3.13 (CPython)

Install Source

GitHub

Install version / commit hash

v4.5.0 (also reproduced on latest master)

Expected Behavior vs Actual Behavior

Expected: The MusixMatch lyrics provider returns lyrics for songs that exist on musixmatch.com.

Actual: MusixMatch returns HTTP 403 for every request made by spotdl, so the provider never returns any lyrics. On current master this failure is completely silent — get_results() has no status-code check, so the 403 error page is parsed as HTML, no /lyrics/ links are found, and the provider quietly falls through to returning no results. (#2697 adds a status check that at least surfaces the error in debug logs.)

Steps to reproduce - Ensure to include actual links!

  1. spotdl download https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT --lyrics musixmatch
  2. Observe no lyrics are embedded, with no error reported.

Or reproduce the raw failure directly:

import requests
from spotdl.providers.lyrics.base import LyricsProvider

resp = requests.get(
    "https://www.musixmatch.com/search/test",
    headers=LyricsProvider().headers,
    timeout=10,
)
print(resp.status_code)  # 403

Traceback

(With the status-code check from #2697 applied; on master the failure is silent)

DEBUG    spotdl.providers.lyrics.base: MusixMatch: Failed to get results for Never Gonna Give You Up - Rick Astley: Received HTTP 403 from https://www.musixmatch.com/search/Never%20Gonna%20Give%20You%20Up%20-%20Rick%20Astley

Other details

I dug into why the 403 happens. MusixMatch has deployed bot detection at their edge, and it classifies clients by more than headers:

Client Result Served by
python-requests + Chrome User-Agent (what spotdl sends) 403 Forbidden awselb/2.0 (AWS WAF/ELB)
python-requests + default python-requests/x.y UA 404 "Not Allowed" on every path, incl. homepage Varnish
curl (either UA) 403 edge
Real browsers work

Key observations:

  • Headers don't matter. Sending a complete modern browser header set (Chrome 126 UA, Accept, Accept-Language, sec-ch-ua client hints) still gets 403.
  • It appears to be TLS fingerprinting (JA3). spotdl's requests claim to be Chrome in the UA, but Python's OpenSSL handshake looks nothing like Chrome's BoringSSL handshake (cipher ordering, extensions, no GREASE, HTTP/1.1 instead of h2). A "Chrome" UA paired with a non-Chrome TLS fingerprint is a classic bot signal, and the request is rejected at the WAF before reaching the app.
  • It is not IP-based — different clients from the same IP get different responses.
  • The 403 response even sets a mxm_bab=AA cookie with a ~10-year expiry (a bot flag).

Suggested fix: switch the MusixMatch provider (or all LyricsProvider HTTP calls) from requests to curl_cffi, which impersonates real browser TLS/JA3 + HTTP/2 fingerprints (from curl_cffi import requests; requests.get(url, impersonate="chrome")). Its requests-compatible API would keep the change small. The trade-offs are a new binary dependency and the usual arms race with a site that is actively blocking scrapers — the alternative is the official (paid) MusixMatch API, or retiring the provider.

Guia do colaborador