Show lyric source and link

This commit is contained in:
iamdoubz committed 2026-07-30 14:49:31 -05:00
1 parent da525948ce
commit e02752ab30
4 files changed
+29 -8

No files matched your search

+10 -8
View File
@@ -11,14 +11,16 @@
* "found": true|false,
* "lyrics": "plain text\nwith newlines",
* "synced": [{ "time": 12.34, "text": "…" }, …], // [] when unavailable
* "url": "…"
* "url": "…",
* "source": "lrclib" | "dumb" | "genius"
* }
*
* Lyrics are returned as plain text (tags/timestamps stripped) so the
* front-end can render them with textContent — no HTML injection from a
* third-party page. `synced` (line-level LRC timestamps, seconds) is only
* populated when LRCLIB has synced lyrics; the Genius fallback has no timing
* data so it's always [] there.
* data so it's always [] there. `url` is '' for LRCLIB (the front-end only
* shows a "source" link for dumb/genius).
*
* Note: the Genius fallback scrapes HTML, which can change at any time. If
* Genius restructures their page the extraction may need updating.
@@ -79,7 +81,7 @@ function lrclib_lyrics($artist, $title, $timeout) {
$lrc = lrclib_lyrics($artist, $title, $timeout);
if ($lrc !== null) {
json_out(['found' => true, 'lyrics' => $lrc['lyrics'], 'synced' => $lrc['synced'], 'url' => '']);
json_out(['found' => true, 'lyrics' => $lrc['lyrics'], 'synced' => $lrc['synced'], 'url' => '', 'source' => 'lrclib']);
}
/* -- dumb (Genius-API-free fallback) ----------------------------------------- */
@@ -89,9 +91,9 @@ if (cfg('dumb.enabled')) {
$song = dumb_song($path, $timeout);
$url = cfg('dumb.url') . $path;
if ($song === null || $song['lyrics'] === '') {
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $url]);
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $url, 'source' => 'dumb']);
}
json_out(['found' => true, 'lyrics' => $song['lyrics'], 'synced' => [], 'url' => $url]);
json_out(['found' => true, 'lyrics' => $song['lyrics'], 'synced' => [], 'url' => $url, 'source' => 'dumb']);
}
/* -- Genius (fallback) ------------------------------------------------------- */
@@ -131,7 +133,7 @@ if ($pageUrl === '') json_out($empty);
/* -- Scrape the lyric containers ------------------------------------------- */
$page = http_get($pageUrl, $timeout);
if ($page === null) {
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $pageUrl]);
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $pageUrl, 'source' => 'genius']);
}
$marker = 'data-lyrics-container="true"';
@@ -153,7 +155,7 @@ $lyrics = implode("\n", array_map('trim', explode("\n", $lyrics)));
$lyrics = preg_replace("/\n{3,}/", "\n\n", $lyrics);
if ($lyrics === '') {
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $pageUrl]);
json_out(['found' => false, 'lyrics' => '', 'synced' => [], 'url' => $pageUrl, 'source' => 'genius']);
}
json_out(['found' => true, 'lyrics' => $lyrics, 'synced' => [], 'url' => $pageUrl]);
json_out(['found' => true, 'lyrics' => $lyrics, 'synced' => [], 'url' => $pageUrl, 'source' => 'genius']);
+7
View File
@@ -227,6 +227,13 @@ audio[controls] { width: 100%; outline: 0; }
.lyrics-line:hover, .lyrics-line:focus-visible { opacity: .85; outline: 0; }
.lyrics-line.current { opacity: 1; font-weight: 700; }
.lyrics-source {
display: block; margin-top: 14px;
font-size: 0.75rem; opacity: .6; color: inherit;
}
.lyrics-source:hover, .lyrics-source:focus-visible { opacity: 1; text-decoration: underline; }
.lyrics-source[hidden] { display: none; }
.lyrics-sync {
position: absolute; top: 48px; right: 10px; z-index: 2;
display: flex; align-items: center; gap: 6px;
+11
View File
@@ -37,6 +37,7 @@
lyricsToggle: $('lyrics-toggle'),
lyrics: $('lyrics'),
lyricsLines: $('lyrics-lines'),
lyricsSource: $('lyrics-source'),
lyricsSync: $('lyrics-sync'),
lyricsOffset: $('lyrics-offset'),
historyBody: $('history-body'),
@@ -719,6 +720,9 @@
if (el.lyrics) el.lyrics.hidden = true;
if (el.lyricsLines) el.lyricsLines.textContent = '';
if (el.lyricsSync) el.lyricsSync.hidden = true;
if (el.lyricsSource) el.lyricsSource.hidden = true;
var SOURCE_LABEL = { genius: 'Genius', dumb: 'dumb' };
var body = new URLSearchParams();
body.set('artist', track.artist || '');
@@ -741,6 +745,13 @@
} else {
el.lyricsLines.textContent = res.lyrics;
}
// No link for LRCLIB (its url is always ''); Genius/dumb link to the
// page the lyrics were scraped from.
if (el.lyricsSource && res.url && SOURCE_LABEL[res.source]) {
el.lyricsSource.href = res.url;
el.lyricsSource.textContent = 'Lyrics via ' + SOURCE_LABEL[res.source];
el.lyricsSource.hidden = false;
}
el.lyricsToggle.hidden = false;
})
.catch(function () {});
+1
View File
@@ -41,6 +41,7 @@ $glassFx = $liquidGlass ? '<span class="glass-fx" aria-hidden="true"></spa
</div>
<div id="lyrics" class="lyrics" hidden>
<div id="lyrics-lines" class="lyrics-lines"></div>
<a id="lyrics-source" class="lyrics-source" href="" target="_blank" rel="noopener" hidden></a>
</div>
<?php endif; ?>
</div>