query("SHOW COLUMNS FROM ac_releases LIKE 'artist_id'"); $artistJoinReady = (bool)($probe && $probe->fetch(\PDO::FETCH_ASSOC)); } catch (\Throwable $e) { $artistJoinReady = false; } if ($artistJoinReady) { $stmt = $db->prepare(" SELECT r.title, r.slug, r.release_date, r.cover_url, COALESCE(r.artist_name, a.name) AS artist_name FROM ac_releases r LEFT JOIN ac_artists a ON a.id = r.artist_id WHERE r.is_published = 1 ORDER BY r.release_date DESC, r.created_at DESC LIMIT :limit "); } else { $stmt = $db->prepare(" SELECT title, slug, release_date, cover_url, artist_name FROM ac_releases WHERE is_published = 1 ORDER BY release_date DESC, created_at DESC LIMIT :limit "); } $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT); $stmt->execute(); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: []; } catch (\Throwable $e) { return ''; } if (!$rows) { return '
No releases published yet.
'; } $cards = ''; foreach ($rows as $row) { $title = htmlspecialchars((string)($row['title'] ?? ''), ENT_QUOTES, 'UTF-8'); $slug = rawurlencode((string)($row['slug'] ?? '')); $artist = htmlspecialchars(trim((string)($row['artist_name'] ?? '')), ENT_QUOTES, 'UTF-8'); $date = htmlspecialchars((string)($row['release_date'] ?? ''), ENT_QUOTES, 'UTF-8'); $cover = trim((string)($row['cover_url'] ?? '')); $coverHtml = $cover !== '' ? '' : '
AC
'; $cards .= '' . '
' . $coverHtml . '
' . '
' . '
' . $title . '
' . ($artist !== '' ? '
' . $artist . '
' : '') . ($date !== '' ? '
' . $date . '
' : '') . '
' . '
'; } return '
' . $cards . '
'; }); return function (Router $router): void { $controller = new ReleasesController(); $router->get('/releases', [$controller, 'index']); $router->get('/release', [$controller, 'show']); $router->get('/admin/releases', [$controller, 'adminIndex']); $router->post('/admin/releases/install', [$controller, 'adminInstall']); $router->get('/admin/releases/new', [$controller, 'adminNew']); $router->get('/admin/releases/edit', function () use ($controller): Core\Http\Response { $id = isset($_GET['id']) ? (int)$_GET['id'] : 0; return $controller->adminEdit($id); }); $router->get('/admin/releases/tracks', function () use ($controller): Core\Http\Response { $releaseId = isset($_GET['release_id']) ? (int)$_GET['release_id'] : 0; return $controller->adminTracks($releaseId); }); $router->get('/admin/releases/tracks/new', function () use ($controller): Core\Http\Response { $releaseId = isset($_GET['release_id']) ? (int)$_GET['release_id'] : 0; return $controller->adminTrackEdit(0, $releaseId); }); $router->get('/admin/releases/tracks/edit', function () use ($controller): Core\Http\Response { $id = isset($_GET['id']) ? (int)$_GET['id'] : 0; $releaseId = isset($_GET['release_id']) ? (int)$_GET['release_id'] : 0; return $controller->adminTrackEdit($id, $releaseId); }); $router->post('/admin/releases/save', [$controller, 'adminSave']); $router->post('/admin/releases/delete', [$controller, 'adminDelete']); $router->post('/admin/releases/upload', [$controller, 'adminUpload']); $router->post('/admin/releases/tracks/save', [$controller, 'adminTrackSave']); $router->post('/admin/releases/tracks/delete', [$controller, 'adminTrackDelete']); $router->post('/admin/releases/tracks/upload', [$controller, 'adminTrackUpload']); };