104 lines
3.2 KiB
PHP
104 lines
3.2 KiB
PHP
<?php
|
|
/**
|
|
* api/_bootstrap.php
|
|
* ------------------
|
|
* Shared setup for every endpoint under /api: loads config, applies error
|
|
* settings, and provides small HTTP / JSON helpers.
|
|
*/
|
|
|
|
require_once __DIR__ . '/../config.php';
|
|
|
|
if (cfg('runtime.show_errors')) {
|
|
ini_set('display_errors', '1');
|
|
ini_set('display_startup_errors', '1');
|
|
error_reporting(E_ALL);
|
|
} else {
|
|
error_reporting(0);
|
|
}
|
|
|
|
/** Send a JSON response and stop. */
|
|
function json_out($data, $status = 200) {
|
|
http_response_code($status);
|
|
header('Content-Type: application/json; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Cache-Control: no-cache, must-revalidate, max-age=0');
|
|
echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
exit;
|
|
}
|
|
|
|
/** Plain-text response and stop (used by the lyrics endpoint). */
|
|
function text_out($text, $status = 200) {
|
|
http_response_code($status);
|
|
header('Content-Type: text/plain; charset=utf-8');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Cache-Control: no-cache, must-revalidate, max-age=0');
|
|
echo $text;
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Perform an HTTP GET and return the body (or null on failure).
|
|
* Falls back to file_get_contents when cURL is unavailable.
|
|
*/
|
|
function http_get($url, $timeout = 5, $headers = []) {
|
|
if ($url === '') return null;
|
|
|
|
if (function_exists('curl_init')) {
|
|
$ch = curl_init($url);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_CONNECTTIMEOUT => (int) $timeout,
|
|
CURLOPT_TIMEOUT => (int) $timeout,
|
|
CURLOPT_FOLLOWLOCATION => true,
|
|
CURLOPT_MAXREDIRS => 3,
|
|
CURLOPT_USERAGENT => 'radio-site/1.0 (+https://github.com)',
|
|
]);
|
|
if (!empty($headers)) {
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
|
}
|
|
$body = curl_exec($ch);
|
|
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
|
curl_close($ch);
|
|
if ($body === false || $code >= 400) return null;
|
|
return $body;
|
|
}
|
|
|
|
// Fallback without cURL.
|
|
$ctx = stream_context_create([
|
|
'http' => [
|
|
'timeout' => (int) $timeout,
|
|
'header' => implode("\r\n", $headers),
|
|
'ignore_errors' => true,
|
|
],
|
|
'ssl' => ['verify_peer' => true, 'verify_peer_name' => true],
|
|
]);
|
|
$body = @file_get_contents($url, false, $ctx);
|
|
return ($body === false) ? null : $body;
|
|
}
|
|
|
|
/**
|
|
* Read a value out of a decoded-JSON structure using dot notation.
|
|
* Supports array indexes: "a.b.0.c".
|
|
*/
|
|
function dot_get($data, $path, $default = null) {
|
|
if ($path === '' || $path === null) return $default;
|
|
$node = $data;
|
|
foreach (explode('.', $path) as $key) {
|
|
if (is_array($node) && array_key_exists($key, $node)) {
|
|
$node = $node[$key];
|
|
} elseif (is_object($node) && isset($node->$key)) {
|
|
$node = $node->$key;
|
|
} else {
|
|
return $default;
|
|
}
|
|
}
|
|
return $node;
|
|
}
|
|
|
|
/** Read the artist/title the browser sends to artwork/lyrics endpoints. */
|
|
function request_track() {
|
|
$artist = $_POST['artist'] ?? $_GET['artist'] ?? '';
|
|
$title = $_POST['title'] ?? $_GET['title'] ?? '';
|
|
return [trim((string) $artist), trim((string) $title)];
|
|
}
|