aboutsummaryrefslogtreecommitdiffstats
path: root/api/lastfm.php
diff options
context:
space:
mode:
authorsillylaird <sillyfanboy@gmail.com>2026-09-03 00:33:59 +0000
committersillylaird <sillyfanboy@gmail.com>2026-09-03 00:33:59 +0000
commit898b52edcb47bcb3e9d6106e74ca73e74ea01e70 (patch)
tree85c6ee5ad58b860144551184d4cf86b560c62b91 /api/lastfm.php
downloadwww-main.tar.gz
www-main.zip
import live www.sillylaird.ca webrootHEADmain
Diffstat (limited to 'api/lastfm.php')
-rw-r--r--api/lastfm.php110
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(),
+ ]);
+}