false, 'lyrics' => '', 'url' => ''];
if (!cfg('lyrics.enabled') || cfg('genius.token') === '') {
json_out($empty);
}
[$artist, $title] = request_track();
if ($artist === '' && $title === '') {
json_out($empty);
}
$token = cfg('genius.token');
$timeout = 5;
$headers = ['Authorization: Bearer ' . $token];
/**
* Return the inner HTML of a balanced
whose opening tag starts at $lt.
* Correctly handles nested
elements.
*/
function inner_balanced_div($html, $lt) {
$open = strpos($html, '>', $lt);
if ($open === false) return '';
$i = $open + 1;
$start = $i;
$len = strlen($html);
$depth = 1;
while ($i < $len && $depth > 0) {
$next = strpos($html, '<', $i);
if ($next === false) break;
if (strncasecmp(substr($html, $next, 5), '
newlines before stripping tags.
$fragment = preg_replace('#
#i', "\n", $fragment);
// Drop any stray script/style.
$fragment = preg_replace('#<(script|style)\b[^>]*>.*?\1>#is', '', $fragment);
// Block-level tags imply a line break.
$fragment = preg_replace('#(p|div)>#i', "\n", $fragment);
$text = strip_tags($fragment);
$text = html_entity_decode($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
return $text;
}
/* -- Find the song on Genius ----------------------------------------------- */
$query = rawurlencode(trim($artist . ' - ' . $title, ' -'));
$search = http_get('https://api.genius.com/search?q=' . $query, $timeout, $headers);
if ($search === null) json_out($empty);
$json = json_decode($search, true);
$hits = dot_get($json, 'response.hits', []);
if (!is_array($hits) || count($hits) === 0) json_out($empty);
$pageUrl = (string) dot_get($hits, '0.result.url', '');
// Optionally prefer the first English-language match (a few extra API calls).
if (cfg('lyrics.prefer_english')) {
$checked = 0;
foreach ($hits as $h) {
if ($checked++ >= 5) break;
$id = dot_get($h, 'result.id', null);
if (!$id) continue;
$songRaw = http_get('https://api.genius.com/songs/' . rawurlencode((string) $id), $timeout, $headers);
if ($songRaw === null) continue;
if (dot_get(json_decode($songRaw, true), 'response.song.language', '') === 'en') {
$pageUrl = (string) dot_get($h, 'result.url', $pageUrl);
break;
}
}
}
if ($pageUrl === '') json_out($empty);
/* -- Scrape the lyric containers ------------------------------------------- */
$page = http_get($pageUrl, $timeout);
if ($page === null) {
json_out(['found' => false, 'lyrics' => '', 'url' => $pageUrl]);
}
$marker = 'data-lyrics-container="true"';
$pieces = [];
$offset = 0;
while (($mpos = strpos($page, $marker, $offset)) !== false) {
// Backtrack to the start of this opening
tag.
$lt = strrpos(substr($page, 0, $mpos), '
false, 'lyrics' => '', 'url' => $pageUrl]);
}
json_out(['found' => true, 'lyrics' => $lyrics, 'url' => $pageUrl]);