feat(*): refactor dynamic vs. static structure and distinctions; make additional elements dynamic
This commit is contained in:
parent
7a0b808f24
commit
13d17e2e51
128 changed files with 982 additions and 959 deletions
|
@ -2,9 +2,6 @@
|
|||
|
||||
namespace App\Classes;
|
||||
|
||||
require __DIR__ . "/BaseHandler.php";
|
||||
require __DIR__ . '/../../server/utils/init.php';
|
||||
|
||||
abstract class ApiHandler extends BaseHandler
|
||||
{
|
||||
protected function ensureCliAccess(): void
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Classes;
|
||||
|
||||
require __DIR__ . "/../../vendor/autoload.php";
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
|
|
69
api/Classes/LatestListenHandler.php
Normal file
69
api/Classes/LatestListenHandler.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
namespace App\Classes;
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
|
||||
class LatestListenHandler extends BaseHandler
|
||||
{
|
||||
protected int $cacheTTL = 60;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->initializeCache();
|
||||
}
|
||||
|
||||
public function handleRequest(): void
|
||||
{
|
||||
$data = $this->getLatestListen();
|
||||
|
||||
if (!$data) {
|
||||
$this->sendResponse(["message" => "No recent tracks found"], 404);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->sendResponse($data);
|
||||
}
|
||||
|
||||
public function getLatestListen(): ?array
|
||||
{
|
||||
try {
|
||||
$cachedData = $this->cache ? $this->cache->get("latest_listen") : null;
|
||||
|
||||
if ($cachedData) return json_decode($cachedData, true);
|
||||
|
||||
$data = $this->makeRequest("GET", "optimized_latest_listen?select=*");
|
||||
|
||||
if (!is_array($data) || empty($data[0])) return null;
|
||||
|
||||
$latestListen = $this->formatLatestListen($data[0]);
|
||||
|
||||
if ($this->cache) $this->cache->set("latest_listen", json_encode($latestListen), $this->cacheTTL);
|
||||
|
||||
return $latestListen;
|
||||
} catch (\Exception $e) {
|
||||
error_log("LatestListenHandler::getLatestListen error: " . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private function formatLatestListen(array $latestListen): array
|
||||
{
|
||||
$emoji = $latestListen["artist_emoji"] ?? ($latestListen["genre_emoji"] ?? "🎧");
|
||||
$trackName = htmlspecialchars($latestListen["track_name"] ?? "Unknown Track", ENT_QUOTES, "UTF-8");
|
||||
$artistName = htmlspecialchars($latestListen["artist_name"] ?? "Unknown Artist", ENT_QUOTES, "UTF-8");
|
||||
$url = htmlspecialchars($latestListen["url"] ?? "/", ENT_QUOTES, "UTF-8");
|
||||
|
||||
return [
|
||||
"content" => sprintf(
|
||||
'%s %s by <a href="%s">%s</a>',
|
||||
$emoji,
|
||||
$trackName,
|
||||
$url,
|
||||
$artistName
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
26
api/Classes/MusicDataHandler.php
Normal file
26
api/Classes/MusicDataHandler.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
namespace App\Classes;
|
||||
|
||||
class MusicDataHandler extends BaseHandler
|
||||
{
|
||||
protected int $cacheTTL = 300;
|
||||
|
||||
public function getThisWeekData(): array
|
||||
{
|
||||
$cacheKey = 'music_week_data';
|
||||
$cached = $this->cache ? $this->cache->get($cacheKey) : null;
|
||||
|
||||
if ($cached) return json_decode($cached, true);
|
||||
|
||||
$response = $this->makeRequest('GET', 'optimized_week_music?select=*');
|
||||
$music = $response[0]['week_music'] ?? [];
|
||||
$music['total_tracks'] = $music['week_summary']['total_tracks'] ?? 0;
|
||||
$music['total_artists'] = $music['week_summary']['total_artists'] ?? 0;
|
||||
$music['total_albums'] = $music['week_summary']['total_albums'] ?? 0;
|
||||
|
||||
if ($this->cache) $this->cache->set($cacheKey, json_encode($music), $this->cacheTTL);
|
||||
|
||||
return $music;
|
||||
}
|
||||
}
|
|
@ -11,21 +11,18 @@ abstract class PageFetcher extends BaseHandler
|
|||
|
||||
protected function cacheGet(string $key): mixed
|
||||
{
|
||||
return $this->cache && $this->cache->exists($key)
|
||||
? json_decode($this->cache->get($key), true)
|
||||
: null;
|
||||
return $this->cache && $this->cache->exists($key) ? json_decode($this->cache->get($key), true) : null;
|
||||
}
|
||||
|
||||
protected function cacheSet(string $key, mixed $value, int $ttl = 3600): void
|
||||
protected function cacheSet(string $key, mixed $value, int $ttl = 300): void
|
||||
{
|
||||
if ($this->cache) {
|
||||
$this->cache->setex($key, $ttl, json_encode($value));
|
||||
}
|
||||
if ($this->cache) $this->cache->setex($key, $ttl, json_encode($value));
|
||||
}
|
||||
|
||||
protected function fetchSingleFromApi(string $endpoint, string $url): ?array
|
||||
{
|
||||
$data = $this->fetchFromApi($endpoint, "url=eq./{$url}");
|
||||
|
||||
return $data[0] ?? null;
|
||||
}
|
||||
|
||||
|
@ -39,6 +36,7 @@ abstract class PageFetcher extends BaseHandler
|
|||
if ($this->globals !== null) return $this->globals;
|
||||
|
||||
$fetcher = new GlobalsFetcher();
|
||||
|
||||
$this->globals = $fetcher->fetch();
|
||||
|
||||
return $this->globals;
|
||||
|
|
36
api/Classes/RecentMediaHandler.php
Normal file
36
api/Classes/RecentMediaHandler.php
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
namespace App\Classes;
|
||||
|
||||
class RecentMediaHandler extends BaseHandler
|
||||
{
|
||||
protected int $cacheTTL = 300;
|
||||
|
||||
public function getRecentMedia(): array
|
||||
{
|
||||
try {
|
||||
$cacheKey = 'recent_media';
|
||||
|
||||
if ($this->cache) {
|
||||
$cached = $this->cache->get($cacheKey);
|
||||
|
||||
if ($cached) return json_decode($cached, true);
|
||||
}
|
||||
|
||||
$response = $this->makeRequest("GET", "optimized_recent_media?select=*");
|
||||
$activity = $response[0]['recent_activity'] ?? [];
|
||||
$data = [
|
||||
'recentMusic' => $activity['recentMusic'] ?? [],
|
||||
'recentWatchedRead' => $activity['recentWatchedRead'] ?? [],
|
||||
];
|
||||
|
||||
if ($this->cache) $this->cache->set($cacheKey, json_encode($data), $this->cacheTTL);
|
||||
|
||||
return $data;
|
||||
} catch (\Exception $e) {
|
||||
error_log("RecentMediaHandler error: " . $e->getMessage());
|
||||
|
||||
return ['recentMusic' => [], 'recentWatchedRead' => []];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
require __DIR__ . "/Utils/init.php";
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require __DIR__ . '/../server/utils/init.php';
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . '/../server/utils/init.php';
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
$id = $_GET['id'] ?? null;
|
||||
$class = $_GET['class'] ?? null;
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
|
||||
class LatestListenHandler extends BaseHandler
|
||||
{
|
||||
protected int $cacheTTL = 60;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->initializeCache();
|
||||
}
|
||||
|
||||
public function handleRequest(): void
|
||||
{
|
||||
try {
|
||||
$cachedData = $this->cache ? $this->cache->get("latest_listen") : null;
|
||||
|
||||
if ($cachedData) {
|
||||
$this->sendResponse(json_decode($cachedData, true));
|
||||
return;
|
||||
}
|
||||
|
||||
$data = $this->makeRequest("GET", "optimized_latest_listen?select=*");
|
||||
|
||||
if (!is_array($data) || empty($data[0])) {
|
||||
$this->sendResponse(["message" => "No recent tracks found"], 404);
|
||||
return;
|
||||
}
|
||||
|
||||
$latestListen = $this->formatLatestListen($data[0]);
|
||||
|
||||
if ($this->cache) $this->cache->set(
|
||||
"latest_listen",
|
||||
json_encode($latestListen),
|
||||
$this->cacheTTL
|
||||
);
|
||||
|
||||
$this->sendResponse($latestListen);
|
||||
} catch (\Exception $e) {
|
||||
error_log("LatestListenHandler Error: " . $e->getMessage());
|
||||
|
||||
$this->sendErrorResponse("Internal Server Error: " . $e->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
private function formatLatestListen(array $latestListen): array
|
||||
{
|
||||
$emoji = $latestListen["artist_emoji"] ?? ($latestListen["genre_emoji"] ?? "🎧");
|
||||
$trackName = htmlspecialchars(
|
||||
$latestListen["track_name"] ?? "Unknown Track",
|
||||
ENT_QUOTES,
|
||||
"UTF-8"
|
||||
);
|
||||
$artistName = htmlspecialchars(
|
||||
$latestListen["artist_name"] ?? "Unknown Artist",
|
||||
ENT_QUOTES,
|
||||
"UTF-8"
|
||||
);
|
||||
$url = htmlspecialchars($latestListen["url"] ?? "/", ENT_QUOTES, "UTF-8");
|
||||
|
||||
return [
|
||||
"content" => sprintf(
|
||||
'%s %s by <a href="https://www.coryd.dev%s">%s</a>',
|
||||
$emoji,
|
||||
$trackName,
|
||||
$url,
|
||||
$artistName
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$handler = new LatestListenHandler();
|
||||
$handler->handleRequest();
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require __DIR__ . '/../server/utils/init.php';
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
|
||||
|
@ -20,7 +19,7 @@ class QueryHandler extends BaseHandler
|
|||
$referer = $_SERVER['HTTP_REFERER'] ?? '';
|
||||
$hostAllowed = fn($url) => in_array(parse_url($url, PHP_URL_HOST), $allowedHosts, true);
|
||||
|
||||
if (!$hostAllowed($origin) && !$hostAllowed($referer)) $this->sendErrorResponse("Forbidden — invalid origin", 403);
|
||||
if (!$hostAllowed($origin) && !$hostAllowed($referer)) $this->sendErrorResponse("Forbidden: invalid origin", 403);
|
||||
|
||||
$allowedSource = $origin ?: $referer;
|
||||
$scheme = parse_url($allowedSource, PHP_URL_SCHEME) ?? 'https';
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require __DIR__ . "/Utils/init.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require __DIR__ . '/../server/utils/init.php';
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\BaseHandler;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
154
api/umami.php
154
api/umami.php
|
@ -1,95 +1,95 @@
|
|||
<?php
|
||||
|
||||
$umamiHost = 'https://stats.coryd.dev';
|
||||
$requestUri = $_SERVER['REQUEST_URI'];
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$proxyPrefix = '/assets/scripts';
|
||||
$forwardPath = parse_url($requestUri, PHP_URL_PATH);
|
||||
$forwardPath = str_replace($proxyPrefix, '', $forwardPath);
|
||||
$targetUrl = $umamiHost . $forwardPath;
|
||||
$umamiHost = 'https://stats.coryd.dev';
|
||||
$requestUri = $_SERVER['REQUEST_URI'];
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$proxyPrefix = '/assets/scripts';
|
||||
$forwardPath = parse_url($requestUri, PHP_URL_PATH);
|
||||
$forwardPath = str_replace($proxyPrefix, '', $forwardPath);
|
||||
$targetUrl = $umamiHost . $forwardPath;
|
||||
|
||||
if (isset($contentType) && preg_match('#^(application/json|text/|application/javascript)#', $contentType)) {
|
||||
ob_start('ob_gzhandler');
|
||||
} else {
|
||||
ob_start();
|
||||
}
|
||||
if (isset($contentType) && preg_match('#^(application/json|text/|application/javascript)#', $contentType)) {
|
||||
ob_start('ob_gzhandler');
|
||||
} else {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
if ($method === 'GET' && preg_match('#^/utils\.js$#', $forwardPath)) {
|
||||
$remoteUrl = $umamiHost . '/script.js';
|
||||
$cacheKey = 'remote_stats_script';
|
||||
$ttl = 3600;
|
||||
$js = null;
|
||||
$code = 200;
|
||||
$redis = null;
|
||||
if ($method === 'GET' && preg_match('#^/utils\.js$#', $forwardPath)) {
|
||||
$remoteUrl = $umamiHost . '/script.js';
|
||||
$cacheKey = 'remote_stats_script';
|
||||
$ttl = 3600;
|
||||
$js = null;
|
||||
$code = 200;
|
||||
$redis = null;
|
||||
|
||||
try {
|
||||
if (extension_loaded('redis')) {
|
||||
$redis = new Redis();
|
||||
$redis->connect('127.0.0.1', 6379);
|
||||
try {
|
||||
if (extension_loaded('redis')) {
|
||||
$redis = new Redis();
|
||||
$redis->connect('127.0.0.1', 6379);
|
||||
|
||||
if ($redis->exists($cacheKey)) $js = $redis->get($cacheKey);
|
||||
if ($redis->exists($cacheKey)) $js = $redis->get($cacheKey);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis unavailable: " . $e->getMessage());
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Redis unavailable: " . $e->getMessage());
|
||||
|
||||
if (!is_string($js)) {
|
||||
$ch = curl_init($remoteUrl);
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
|
||||
$js = curl_exec($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($redis && $code === 200 && $js) $redis->setex($cacheKey, $ttl, $js);
|
||||
}
|
||||
|
||||
if (!is_string($js) || trim($js) === '') {
|
||||
$js = '// Failed to fetch remote script';
|
||||
$code = 502;
|
||||
}
|
||||
|
||||
http_response_code($code);
|
||||
header('Content-Type: application/javascript; charset=UTF-8');
|
||||
echo $js;
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!is_string($js)) {
|
||||
$ch = curl_init($remoteUrl);
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) $headers[] = 'User-Agent: ' . $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
$js = curl_exec($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$ch = curl_init($targetUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
curl_close($ch);
|
||||
if ($method === 'POST') {
|
||||
$body = file_get_contents('php://input');
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if ($redis && $code === 200 && $js) $redis->setex($cacheKey, $ttl, $js);
|
||||
if (strpos($forwardPath, '/api/send') === 0 && is_array($data)) $data['payload'] = array_merge($data['payload'] ?? [], [
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',
|
||||
]);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
|
||||
if (!is_string($js) || trim($js) === '') {
|
||||
$js = '// Failed to fetch remote script';
|
||||
$code = 502;
|
||||
}
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
|
||||
http_response_code($code);
|
||||
header('Content-Type: application/javascript; charset=UTF-8');
|
||||
echo $js;
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
http_response_code($httpCode);
|
||||
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
];
|
||||
if ($contentType) header("Content-Type: $contentType");
|
||||
|
||||
if (isset($_SERVER['HTTP_USER_AGENT'])) $headers[] = 'User-Agent: ' . $_SERVER['HTTP_USER_AGENT'];
|
||||
|
||||
$ch = curl_init($targetUrl);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
if ($method === 'POST') {
|
||||
$body = file_get_contents('php://input');
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (strpos($forwardPath, '/api/send') === 0 && is_array($data)) $data['payload'] = array_merge($data['payload'] ?? [], [
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',
|
||||
]);
|
||||
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
|
||||
$response = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
|
||||
curl_close($ch);
|
||||
http_response_code($httpCode);
|
||||
|
||||
if ($contentType) header("Content-Type: $contentType");
|
||||
|
||||
echo $response ?: '';
|
||||
echo $response ?: '';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
require_once __DIR__ . '/../bootstrap.php';
|
||||
|
||||
use App\Classes\ApiHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue