diff options
| author | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
|---|---|---|
| committer | sillylaird <sillyfanboy@gmail.com> | 2026-09-03 00:33:59 +0000 |
| commit | 898b52edcb47bcb3e9d6106e74ca73e74ea01e70 (patch) | |
| tree | 85c6ee5ad58b860144551184d4cf86b560c62b91 /api/lastfm.php | |
| download | www-main.tar.gz www-main.zip | |
Diffstat (limited to 'api/lastfm.php')
| -rw-r--r-- | api/lastfm.php | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/api/lastfm.php b/api/lastfm.php new file mode 100644 index 0000000..5ec583b --- /dev/null +++ b/api/lastfm.php @@ -0,0 +1,110 @@ +<?php +require_once __DIR__ . '/../partials/proxy_helpers.php'; + +if (!headers_sent()) { + header('Content-Type: application/json'); + header('Cache-Control: no-cache, must-revalidate'); +} +ob_start(); + +$cacheDir = sys_get_temp_dir() . '/sillylaird_lastfm'; +if (!is_dir($cacheDir)) @mkdir($cacheDir, 0700, true); +$cacheFile = $cacheDir . '/recent.json'; +$freshTtl = 10; // serve cache without hitting upstream +$staleTtl = PHP_INT_MAX; // on upstream failure, always fall back to cache + +$serveCache = function (string $file) { + $body = @file_get_contents($file); + if ($body === false) return false; + ob_end_clean(); + echo $body; + return true; +}; + +if (is_file($cacheFile) && (time() - filemtime($cacheFile)) < $freshTtl) { + if ($serveCache($cacheFile)) exit; +} + +if (!proxy_rate_limit('lastfm_api', 60, 60)) { + if (is_file($cacheFile) && (time() - filemtime($cacheFile)) < $staleTtl) { + if ($serveCache($cacheFile)) exit; + } + ob_end_clean(); + http_response_code(429); + echo json_encode(['error' => true, 'message' => 'rate limited']); + exit; +} + +$apiKey = lastfm_api_key(); +$user = 'SillyLaird'; +$limit = 5; + +$url = "https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=$user&api_key=$apiKey&format=json&limit=$limit"; + +$ch = curl_init(); +curl_setopt($ch, CURLOPT_URL, $url); +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); +curl_setopt($ch, CURLOPT_TIMEOUT, 5); +curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); +curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); +curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); + +$response = curl_exec($ch); +$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); +$error = curl_error($ch); +curl_close($ch); + +try { + if ($response === false) { + throw new Exception("cURL Error: " . $error); + } + + if ($httpCode !== 200) { + throw new Exception("Last.fm API returned HTTP $httpCode"); + } + + $data = json_decode($response, true); + + if (isset($data['error'])) { + throw new Exception("Last.fm Error: " . $data['message']); + } + + if (!isset($data['recenttracks']['track'])) { + throw new Exception("No tracks found."); + } + + $tracks = $data['recenttracks']['track']; + if (isset($tracks['name'])) { + $tracks = [$tracks]; + } + + $results = []; + foreach ($tracks as $track) { + $results[] = [ + 'name' => $track['name'], + 'artist' => $track['artist']['#text'], + 'url' => $track['url'], + 'image' => isset($track['image'][2]['#text']) ? $track['image'][2]['#text'] : '', + 'nowplaying' => isset($track['@attr']['nowplaying']) && $track['@attr']['nowplaying'] === 'true', + ]; + } + + $json = json_encode($results); + $tmp = $cacheFile . '.tmp'; + if (@file_put_contents($tmp, $json, LOCK_EX) !== false) { + @rename($tmp, $cacheFile); + } + ob_end_clean(); + echo $json; + +} catch (Exception $e) { + if (is_file($cacheFile) && (time() - filemtime($cacheFile)) < $staleTtl) { + if ($serveCache($cacheFile)) exit; + } + ob_end_clean(); + http_response_code(500); + echo json_encode([ + 'error' => true, + 'message' => $e->getMessage(), + ]); +} |
