false, 'artist' => '', 'title' => '', 'album' => '', 'art' => '', 'listeners' => null, 'listeners_peak' => null, ]; /** Remove configured junk (e.g. " (Remastered)", ".mp3") from a string. */ function clean_str($s) { $patterns = cfg('nowplaying.cleanup'); if (empty($patterns)) return trim($s); $isRegex = cfg('nowplaying.cleanup_is_regex'); foreach ($patterns as $p) { if ($p === '') continue; if ($isRegex) { $out = @preg_replace('/' . str_replace('/', '\\/', $p) . '/i', '', $s); if ($out !== null) $s = $out; // ignore invalid patterns } else { $s = str_ireplace($p, '', $s); } } return trim($s); } /** Split "Artist Title" into [artist, title]. */ function split_title($combined, $delim) { $combined = trim((string) $combined); if ($combined === '') return ['', '']; if ($delim !== '' && strpos($combined, $delim) !== false) { $parts = explode($delim, $combined, 2); return [trim($parts[0]), trim($parts[1])]; } // No delimiter found — treat the whole thing as the title. return ['', $combined]; } $raw = http_get($url, $timeout); if ($raw === null) { json_out($out); // backend unreachable -> offline } $data = json_decode($raw, true); if (!is_array($data)) { json_out($out); } switch ($provider) { /* --------------------------------------------------------------- */ case 'azuracast': $np = $data['now_playing'] ?? []; $song = $np['song'] ?? []; $out['artist'] = (string) ($song['artist'] ?? ''); $out['title'] = (string) ($song['title'] ?? ''); $out['album'] = (string) ($song['album'] ?? ''); $out['art'] = (string) ($song['art'] ?? ''); if ($out['artist'] === '' && $out['title'] === '' && !empty($song['text'])) { [$out['artist'], $out['title']] = split_title($song['text'], $delim); } $out['listeners'] = isset($data['listeners']['current']) ? (int) $data['listeners']['current'] : null; $out['listeners_peak'] = isset($data['listeners']['total']) ? (int) $data['listeners']['total'] : null; $out['online'] = !empty($data['is_online']) && ($out['title'] !== '' || $out['artist'] !== ''); break; /* --------------------------------------------------------------- */ case 'shoutcast': $combined = $data['streamtitle'] ?? $data['songtitle'] ?? ''; [$out['artist'], $out['title']] = split_title($combined, $delim); $out['listeners'] = isset($data['currentlisteners']) ? (int) $data['currentlisteners'] : null; $out['listeners_peak'] = isset($data['peaklisteners']) ? (int) $data['peaklisteners'] : null; $out['online'] = ($out['title'] !== '' || $out['artist'] !== ''); break; /* --------------------------------------------------------------- */ case 'custom': $c = cfg('nowplaying.custom'); if (!empty($c['title_combined'])) { [$out['artist'], $out['title']] = split_title(dot_get($data, $c['title_combined'], ''), $delim); } else { $out['artist'] = (string) dot_get($data, $c['artist'], ''); $out['title'] = (string) dot_get($data, $c['title'], ''); } $out['album'] = (string) dot_get($data, $c['album'], ''); $out['art'] = (string) dot_get($data, $c['art'], ''); $listeners = dot_get($data, $c['listeners'], null); $out['listeners'] = ($listeners === null) ? null : (int) $listeners; $out['online'] = ($out['title'] !== '' || $out['artist'] !== ''); break; /* --------------------------------------------------------------- */ case 'icecast': default: $ice = $data['icestats'] ?? []; $source = $ice['source'] ?? null; if ($source === null) break; // "source" can be a single object or a list of mounts. $sources = isset($source[0]) ? $source : [$source]; $mount = cfg('nowplaying.mount'); $chosen = null; if ($mount !== '') { foreach ($sources as $s) { $listenurl = (string) ($s['listenurl'] ?? ''); if ($listenurl !== '' && substr($listenurl, -strlen($mount)) === $mount) { $chosen = $s; break; } } } if ($chosen === null) { // First source that actually has a title, else the first one. foreach ($sources as $s) { if (!empty($s['title']) || !empty($s['artist'])) { $chosen = $s; break; } } if ($chosen === null) $chosen = $sources[0]; } // Liquidsoap can emit artist/title separately; prefer that. if (!empty($chosen['artist']) || !empty($chosen['title'])) { $maybeArtist = (string) ($chosen['artist'] ?? ''); $maybeTitle = (string) ($chosen['title'] ?? ''); if ($maybeArtist !== '' && $maybeTitle !== '') { $out['artist'] = trim($maybeArtist); $out['title'] = trim($maybeTitle); } else { [$out['artist'], $out['title']] = split_title($maybeTitle !== '' ? $maybeTitle : $maybeArtist, $delim); } } $out['listeners'] = isset($chosen['listeners']) ? (int) $chosen['listeners'] : null; $out['listeners_peak'] = isset($chosen['listener_peak']) ? (int) $chosen['listener_peak'] : null; $out['online'] = ($out['title'] !== '' || $out['artist'] !== ''); break; } // Strip configured junk from the metadata before returning it. $out['artist'] = clean_str($out['artist']); $out['title'] = clean_str($out['title']); json_out($out);