Files
MediaCollectorLibary/app/Controllers/TvShowController.php
2025-11-07 13:20:48 +01:00

261 lines
8.7 KiB
PHP

<?php
namespace App\Controllers;
use App\Models\TvShow;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Views\Twig;
class TvShowController extends Controller
{
private \PDO $pdo;
public function __construct(\PDO $pdo, Twig $view)
{
parent::__construct($view);
$this->pdo = $pdo;
}
public function index(Request $request, Response $response, $args)
{
$queryParams = $request->getQueryParams();
// Get pagination parameters
$page = max(1, (int)($queryParams['page'] ?? 1));
$perPage = max(12, min(100, (int)($queryParams['per_page'] ?? 24)));
// Get search parameters
$search = trim($queryParams['search'] ?? '');
// Get filter parameters
$genres = $queryParams['genres'] ?? [];
if (!is_array($genres)) {
$genres = [$genres];
}
$genres = array_filter($genres);
$years = $queryParams['years'] ?? [];
if (!is_array($years)) {
$years = [$years];
}
$years = array_filter($years);
// Get view mode and sort
$viewMode = $queryParams['view'] ?? 'grid'; // grid, list, covers
$sort = $queryParams['sort'] ?? 'title_asc';
// Validate view mode
if (!in_array($viewMode, ['grid', 'list', 'covers'])) {
$viewMode = 'grid';
}
// Validate sort option
$validSorts = ['title_asc', 'title_desc', 'year_asc', 'year_desc', 'rating_asc', 'rating_desc'];
if (!in_array($sort, $validSorts)) {
$sort = 'title_asc';
}
// Get TV shows with pagination, filters, and sorting
$tvshows = TvShow::getAllWithPagination($this->pdo, $page, $perPage, $search, $genres, $years, $sort);
// Get total count for pagination
$totalCount = TvShow::getTotalCount($this->pdo, $search, $genres, $years);
// Get available filter options
$availableGenres = TvShow::getAvailableGenres($this->pdo);
$availableYears = TvShow::getAvailableYears($this->pdo);
// Calculate pagination info
$totalPages = ceil($totalCount / $perPage);
$hasNextPage = $page < $totalPages;
$hasPrevPage = $page > 1;
return $this->view->render($response, 'tvshows/index.twig', [
'title' => 'TV Shows',
'tvshows' => $tvshows,
'pagination' => [
'current_page' => $page,
'per_page' => $perPage,
'total_pages' => $totalPages,
'total_items' => $totalCount,
'has_next' => $hasNextPage,
'has_prev' => $hasPrevPage,
'next_page' => $page + 1,
'prev_page' => $page - 1
],
'search' => $search,
'view_mode' => $viewMode,
'view_modes' => ['grid', 'list', 'covers'],
'filters' => [
'genres' => $genres,
'years' => $years
],
'available_filters' => [
'genres' => $availableGenres,
'years' => $availableYears
]
]);
}
public function show(Request $request, Response $response, $args)
{
$tvShowId = (int) $args['id'];
// Get TV show details
$stmt = $this->pdo->prepare("
SELECT t.*, s.display_name as source_name
FROM tv_shows t
JOIN sources s ON t.source_id = s.id
WHERE t.id = :id
");
$stmt->execute(['id' => $tvShowId]);
$tvShow = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!$tvShow) {
return $response->withStatus(404);
}
// Decode metadata and other JSON fields
$metadata = json_decode($tvShow['metadata'] ?? '{}', true);
$cast = json_decode($tvShow['cast'] ?? '[]', true);
$genre = json_decode($tvShow['genre'] ?? '[]', true);
// Get actors for this TV show (from main cast)
$stmt = $this->pdo->prepare("
SELECT a.*
FROM actors a
JOIN actor_tv_show ats ON a.id = ats.actor_id
WHERE ats.tv_show_id = :tv_show_id
ORDER BY a.name ASC
");
$stmt->execute(['tv_show_id' => $tvShowId]);
$mainActors = $stmt->fetchAll(\PDO::FETCH_ASSOC);
// Get all actors from episodes
$stmt = $this->pdo->prepare("
SELECT DISTINCT a.*
FROM actors a
JOIN actor_tv_episode ate ON a.id = ate.actor_id
JOIN tv_episodes e ON ate.tv_episode_id = e.id
WHERE e.tv_show_id = :tv_show_id
ORDER BY a.name ASC
");
$stmt->execute(['tv_show_id' => $tvShowId]);
$episodeActors = $stmt->fetchAll(\PDO::FETCH_ASSOC);
// Merge and deduplicate actors
$allActors = array_merge($mainActors, $episodeActors);
$actorsById = [];
foreach ($allActors as $actor) {
$actorsById[$actor['id']] = $actor;
}
$actors = array_values($actorsById);
// Sort by name
usort($actors, function($a, $b) {
return strcmp($a['name'], $b['name']);
});
// Get seasons and episodes for this TV show
$tvShowModel = new TvShow($this->pdo, $tvShow);
$seasons = $tvShowModel->getSeasonsWithEpisodes();
// Get recent episodes (last 5 aired episodes)
$stmt = $this->pdo->prepare("
SELECT e.*
FROM tv_episodes e
WHERE e.tv_show_id = :tv_show_id AND e.air_date IS NOT NULL
ORDER BY e.air_date DESC
LIMIT 5
");
$stmt->execute(['tv_show_id' => $tvShowId]);
$recent_episodes = $stmt->fetchAll(\PDO::FETCH_ASSOC);
// Add actors for recent episodes
foreach ($recent_episodes as &$episode) {
$episodeStmt = $this->pdo->prepare("
SELECT a.*
FROM actors a
JOIN actor_tv_episode ate ON a.id = ate.actor_id
WHERE ate.tv_episode_id = :tv_episode_id
ORDER BY a.name ASC
");
$episodeStmt->execute(['tv_episode_id' => $episode['id']]);
$episode['actors'] = $episodeStmt->fetchAll(\PDO::FETCH_ASSOC);
}
return $this->view->render($response, 'tvshows/show.twig', [
'title' => $tvShow['title'],
'tvshow' => $tvShow,
'metadata' => $metadata,
'cast' => $cast,
'genre' => $genre,
'actors' => $actors,
'seasons' => $seasons,
'recent_episodes' => $recent_episodes
]);
}
public function delete(Request $request, Response $response, $args)
{
$tvShowId = (int) $args['id'];
// Get TV show details to access metadata
$stmt = $this->pdo->prepare("
SELECT t.*
FROM tv_shows t
WHERE t.id = :id
");
$stmt->execute(['id' => $tvShowId]);
$tvShow = $stmt->fetch(\PDO::FETCH_ASSOC);
if (!$tvShow) {
return $response->withStatus(404);
}
// Decode metadata to find image paths
$metadata = json_decode($tvShow['metadata'], true);
// Delete associated images
$imagesDeleted = [];
if (!empty($metadata['local_poster_path'])) {
$posterPath = __DIR__ . '/../storage/images/' . $metadata['local_poster_path'];
if (file_exists($posterPath)) {
unlink($posterPath);
$imagesDeleted[] = $metadata['local_poster_path'];
}
}
if (!empty($metadata['local_backdrop_path'])) {
$backdropPath = __DIR__ . '/../storage/images/' . $metadata['local_backdrop_path'];
if (file_exists($backdropPath)) {
unlink($backdropPath);
$imagesDeleted[] = $metadata['local_backdrop_path'];
}
}
// Delete actor relationships
$stmt = $this->pdo->prepare("
DELETE FROM actor_tv_show
WHERE tv_show_id = :tv_show_id
");
$stmt->execute(['tv_show_id' => $tvShowId]);
// Delete the TV show record
$stmt = $this->pdo->prepare("DELETE FROM tv_shows WHERE id = :id");
$result = $stmt->execute(['id' => $tvShowId]);
if ($result) {
return $response->withJson([
'success' => true,
'message' => 'TV show deleted successfully',
'images_deleted' => $imagesDeleted
]);
} else {
return $response->withJson([
'success' => false,
'message' => 'Failed to delete TV show'
], 500);
}
}
}