🚨 TL;DR
Your fetch fails because:
urlEncode is broken for non-ASCII (Japanese) characters.
artist_name contains noisy metadata like CV: and feat. which hurts matching.
You are not using ISRC (which you actually have).
Fix:
Replace urlEncode with net/url.QueryEscape
Normalize artist name before request
Prefer ISRC search if available
🔴 Root Cause #1 — Your urlEncode() is wrong
This is the real bug.
default:
b.WriteString(fmt.Sprintf("%%%02X", r))
r is a Unicode rune, not a byte.
For:
#超絶かわいい
You are generating invalid percent encoding.
LRCLIB expects UTF-8 percent encoded bytes, not rune hex.
✅ FIX 1 — Replace urlEncode
Delete your entire function and use standard lib.
import "net/url"
Replace URI building with:
params := url.Values{}
params.Set("track_name", track.Title)
params.Set("artist_name", normalizeArtist(track.Artist))
params.Set("album_name", track.Album)
params.Set("duration", strconv.Itoa(duration))
uri := fmt.Sprintf("%s/api/get?%s", baseURL, params.Encode())
Delete urlEncode() completely.
🔴 Root Cause #2 — Artist Name Is Dirty
You are sending:
mona(CV:夏川椎菜) feat. HoneyWorks
LRCLIB likely stores:
mona
or
mona feat. HoneyWorks
The CV: part is poisoning the match.
✅ FIX 2 — Normalize Artist
Add this:
func normalizeArtist(s string) string {
s = strings.ReplaceAll(s, "CV:", "")
s = strings.ReplaceAll(s, "CV", "")
s = strings.ReplaceAll(s, "(", "(")
s = strings.ReplaceAll(s, ")", ")")
if i := strings.Index(s, "("); i != -1 {
s = s[:i]
}
if i := strings.Index(strings.ToLower(s), " feat."); i != -1 {
s = s[:i]
}
return strings.TrimSpace(s)
}
Then:
params.Set("artist_name", normalizeArtist(track.Artist))
🟢 Root Cause #3 — You Have ISRC (Use It!)
You have:
isrc: JPX402200177
LRCLIB supports lookup by ISRC.
This is far more reliable for Japanese tracks.
✅ FIX 3 — Prefer ISRC Lookup
Modify fetchLyrics:
GET /api/get?isrc=JPX402200177
You need to:
Extend jobInfo to store ISRC
Fetch it from Subsonic song tags
If ISRC exists → use it instead of title/artist
Example:
if track.ISRC != "" {
uri = fmt.Sprintf("%s/api/get?isrc=%s",
baseURL,
url.QueryEscape(track.ISRC),
)
}
🔥 Why Japanese Was Failing Specifically
Because:
Japanese = multi-byte UTF-8
Your encoder assumes 1 rune = 1 byte
That produces invalid percent sequences
LRCLIB rejects it → 404
ASCII tracks would work.
Japanese tracks fail.
✅ Minimal Required Fix
If you only do ONE thing:
Replace urlEncode() with url.QueryEscape.
That alone will fix most failures.
🧪 After Fix — Your Example Will Work
For:
Track: #超絶かわいい
Artist: mona(CV:夏川椎菜) feat. HoneyWorks
Proper request becomes:
...track_name=%23%E8%B6%85%E7%B5%B6%E3%81%8B%E3%82%8F%E3%81%84%E3%81%84
Correct UTF-8 percent encoding.
🚀 Recommended Final Improvements
Use url.Values
Normalize artist
Prefer ISRC lookup
Log final query string for debugging
🚨 TL;DR
Your fetch fails because:
urlEncode is broken for non-ASCII (Japanese) characters.
artist_name contains noisy metadata like CV: and feat. which hurts matching.
You are not using ISRC (which you actually have).
Fix:
Replace urlEncode with net/url.QueryEscape
Normalize artist name before request
Prefer ISRC search if available
🔴 Root Cause #1 — Your urlEncode() is wrong
This is the real bug.
default:
b.WriteString(fmt.Sprintf("%%%02X", r))
r is a Unicode rune, not a byte.
For:
#超絶かわいい
You are generating invalid percent encoding.
LRCLIB expects UTF-8 percent encoded bytes, not rune hex.
✅ FIX 1 — Replace urlEncode
Delete your entire function and use standard lib.
import "net/url"
Replace URI building with:
params := url.Values{}
params.Set("track_name", track.Title)
params.Set("artist_name", normalizeArtist(track.Artist))
params.Set("album_name", track.Album)
params.Set("duration", strconv.Itoa(duration))
uri := fmt.Sprintf("%s/api/get?%s", baseURL, params.Encode())
Delete urlEncode() completely.
🔴 Root Cause #2 — Artist Name Is Dirty
You are sending:
mona(CV:夏川椎菜) feat. HoneyWorks
LRCLIB likely stores:
mona
or
mona feat. HoneyWorks
The CV: part is poisoning the match.
✅ FIX 2 — Normalize Artist
Add this:
func normalizeArtist(s string) string {
s = strings.ReplaceAll(s, "CV:", "")
s = strings.ReplaceAll(s, "CV", "")
s = strings.ReplaceAll(s, "(", "(")
s = strings.ReplaceAll(s, ")", ")")
}
Then:
params.Set("artist_name", normalizeArtist(track.Artist))
🟢 Root Cause #3 — You Have ISRC (Use It!)
You have:
isrc: JPX402200177
LRCLIB supports lookup by ISRC.
This is far more reliable for Japanese tracks.
✅ FIX 3 — Prefer ISRC Lookup
Modify fetchLyrics:
GET /api/get?isrc=JPX402200177
You need to:
Extend jobInfo to store ISRC
Fetch it from Subsonic song tags
If ISRC exists → use it instead of title/artist
Example:
if track.ISRC != "" {
uri = fmt.Sprintf("%s/api/get?isrc=%s",
baseURL,
url.QueryEscape(track.ISRC),
)
}
🔥 Why Japanese Was Failing Specifically
Because:
Japanese = multi-byte UTF-8
Your encoder assumes 1 rune = 1 byte
That produces invalid percent sequences
LRCLIB rejects it → 404
ASCII tracks would work.
Japanese tracks fail.
✅ Minimal Required Fix
If you only do ONE thing:
Replace urlEncode() with url.QueryEscape.
That alone will fix most failures.
🧪 After Fix — Your Example Will Work
For:
Track: #超絶かわいい
Artist: mona(CV:夏川椎菜) feat. HoneyWorks
Proper request becomes:
...track_name=%23%E8%B6%85%E7%B5%B6%E3%81%8B%E3%82%8F%E3%81%84%E3%81%84
Correct UTF-8 percent encoding.
🚀 Recommended Final Improvements
Use url.Values
Normalize artist
Prefer ISRC lookup
Log final query string for debugging