media = new Media($pdo); $this->series = new Series($pdo); $this->music = new Music($pdo); $this->game = new Game($pdo); $this->logger = ApiLogger::getInstance(); } public function handleRequest($method, $segments) { $id = isset($segments[1]) ? (int)$segments[1] : null; $subResource = isset($segments[2]) ? $segments[2] : null; // Sub-Endpunkte für Episoden und Tracks if ($id && $subResource) { if ($subResource === 'episodes') { return $this->handleEpisodes($method, $id, $segments); } if ($subResource === 'tracks') { return $this->handleTracks($method, $id, $segments); } } switch ($method) { case 'GET': return $id ? $this->getOne($id) : $this->getAll(); case 'POST': return $this->create(); case 'PUT': return $this->update($id); case 'DELETE': return $this->delete($id); default: http_response_code(405); return ['success' => false, 'error' => 'Method not allowed']; } } private function handleEpisodes($method, $mediaId, $segments) { $episodeId = isset($segments[3]) ? (int)$segments[3] : null; switch ($method) { case 'GET': if ($episodeId) { return $this->getEpisode($episodeId); } return $this->getEpisodes($mediaId); case 'POST': return $this->addEpisode($mediaId); case 'PUT': return $this->updateEpisode($episodeId); case 'DELETE': return $this->deleteEpisode($episodeId); default: http_response_code(405); return ['success' => false, 'error' => 'Method not allowed']; } } private function handleTracks($method, $mediaId, $segments) { $trackId = isset($segments[3]) ? (int)$segments[3] : null; switch ($method) { case 'GET': if ($trackId) { return $this->getTrack($trackId); } return $this->getTracks($mediaId); case 'POST': return $this->addTrack($mediaId); case 'PUT': return $this->updateTrack($trackId); case 'DELETE': return $this->deleteTrack($trackId); default: http_response_code(405); return ['success' => false, 'error' => 'Method not allowed']; } } private function getEpisodes($mediaId) { $season = isset($_GET['season']) ? (int)$_GET['season'] : null; $episodes = $this->series->getEpisodes($mediaId, $season); return ['success' => true, 'data' => ['items' => $episodes]]; } /** * Add a new episode to a series * @param int $mediaId Media ID * @return array Created episode ID */ private function addEpisode($mediaId) { $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } $episodeId = $this->series->addEpisode($mediaId, $data); http_response_code(201); return ['success' => true, 'data' => ['id' => $episodeId]]; } /** * Update an existing episode * @param int $episodeId Episode ID * @return array Updated episode ID */ private function updateEpisode($episodeId) { if (!$episodeId) { http_response_code(400); return ['success' => false, 'error' => 'Episode ID required']; } $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } $this->series->updateEpisode($episodeId, $data); return ['success' => true, 'data' => ['id' => $episodeId]]; } /** * Delete an episode * @param int $episodeId Episode ID * @return array Success message */ private function deleteEpisode($episodeId) { if (!$episodeId) { http_response_code(400); return ['success' => false, 'error' => 'Episode ID required']; } $deleted = $this->series->deleteEpisode($episodeId); if (!$deleted) { http_response_code(404); return ['success' => false, 'error' => 'Episode not found']; } return ['success' => true, 'message' => 'Episode deleted successfully']; } /** * Get a single episode by ID * @param int $episodeId Episode ID * @return array Episode data */ private function getEpisode($episodeId) { // Episode direkt aus Datenbank abrufen $stmt = $this->series->getConnection()->prepare("SELECT * FROM episodes WHERE id = ?"); $stmt->execute([$episodeId]); $episode = $stmt->fetch(); if (!$episode) { http_response_code(404); return ['success' => false, 'error' => 'Episode not found']; } return ['success' => true, 'data' => $episode]; } private function getTracks($mediaId) { $tracks = $this->music->getTracks($mediaId); return ['success' => true, 'data' => ['items' => $tracks]]; } private function addTrack($mediaId) { $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } $trackId = $this->music->addTrack($mediaId, $data); http_response_code(201); return ['success' => true, 'data' => ['id' => $trackId]]; } private function updateTrack($trackId) { if (!$trackId) { http_response_code(400); return ['success' => false, 'error' => 'Track ID required']; } $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } $this->music->updateTrack($trackId, $data); return ['success' => true, 'data' => ['id' => $trackId]]; } private function deleteTrack($trackId) { if (!$trackId) { http_response_code(400); return ['success' => false, 'error' => 'Track ID required']; } $deleted = $this->music->deleteTrack($trackId); if (!$deleted) { http_response_code(404); return ['success' => false, 'error' => 'Track not found']; } return ['success' => true, 'message' => 'Track deleted successfully']; } private function getTrack($trackId) { // Track direkt aus Datenbank abrufen $stmt = $this->music->getConnection()->prepare("SELECT * FROM tracks WHERE id = ?"); $stmt->execute([$trackId]); $track = $stmt->fetch(); if (!$track) { http_response_code(404); return ['success' => false, 'error' => 'Track not found']; } return ['success' => true, 'data' => $track]; } /** * Get a single media item by ID * @param int $id Media ID * @return array Media object with relations */ private function getOne($id) { // Zuerst Basis-Media abrufen um Typ zu bestimmen $baseMedia = $this->media->getBase($id); if (!$baseMedia) { http_response_code(404); return ['success' => false, 'error' => 'Media not found']; } // Typ-spezifisches Abrufen switch ($baseMedia['type']) { case 'TV': $media = $this->series->getWithEpisodes($id); break; case 'Album': $media = $this->music->getWithTracks($id); break; case 'Game': $media = $this->game->getWithGameInfo($id); break; default: $media = $this->media->getWithRelations($id); } return ['success' => true, 'data' => $media]; } /** * Get all media items with filtering and pagination * @return array Paginated media list */ private function getAll() { $filters = []; if (isset($_GET['category'])) $filters['category'] = $_GET['category']; if (isset($_GET['type'])) $filters['type'] = $_GET['type']; if (isset($_GET['search'])) $filters['search'] = $_GET['search']; $page = isset($_GET['page']) ? (int)$_GET['page'] : 1; $limit = isset($_GET['limit']) ? (int)$_GET['limit'] : 20; $result = $this->media->search($filters, $page, $limit); return ['success' => true, 'data' => $result]; } /** * Create a new media item * @return array Created media ID */ private function create() { $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } error_log("MediaController::create - Data received, poster field exists: " . (isset($data['poster']) ? 'yes' : 'no')); if (isset($data['poster'])) { error_log("MediaController::create - Poster length: " . strlen($data['poster'])); error_log("MediaController::create - Poster starts with: " . substr($data['poster'], 0, 50)); } $title = $data['title'] ?? null; if (!$title) { http_response_code(400); return ['success' => false, 'error' => 'Title is required']; } // Prüfen ob bereits Eintrag mit diesem cleanname existiert $cleanname = generateCleanName($title); $existing = $this->media->findByCleanName($cleanname); if ($existing) { http_response_code(200); $this->logger->logRequest('POST', '/api/media', [], $data); $this->logger->logResponse('POST', '/api/media', 200, ['id' => $existing['id'], 'message' => 'Media already exists']); return ['success' => true, 'data' => ['id' => $existing['id'], 'message' => 'Media already exists']]; } // Typ-spezifisches Erstellen $type = $data['type'] ?? null; if ($type === 'Game') { $mediaId = $this->game->createWithRelations($data); } elseif ($type === 'TV') { $mediaId = $this->series->createWithRelations($data); } elseif ($type === 'Album') { $mediaId = $this->music->createWithRelations($data); } else { $mediaId = $this->media->createWithRelations($data); } http_response_code(201); $this->logger->logRequest('POST', '/api/media', [], $data); $this->logger->logResponse('POST', '/api/media', 201, ['id' => $mediaId]); return ['success' => true, 'data' => ['id' => $mediaId]]; } /** * Update an existing media item * @param int $id Media ID * @return array Updated media ID */ private function update($id) { if (!$id) { http_response_code(400); return ['success' => false, 'error' => 'ID required']; } $data = json_decode(file_get_contents('php://input'), true); if (!$data) { http_response_code(400); return ['success' => false, 'error' => 'Invalid JSON']; } // Typ-spezifisches Aktualisieren $type = $data['type'] ?? null; if ($type === 'Game') { $this->game->updateWithRelations($id, $data); } elseif ($type === 'TV') { $this->series->updateWithRelations($id, $data); } elseif ($type === 'Album') { $this->music->updateWithRelations($id, $data); } else { $this->media->updateWithRelations($id, $data); } $this->logger->logRequest('PUT', "/api/media/$id", [], $data); $this->logger->logResponse('PUT', "/api/media/$id", 200, ['id' => $id]); return ['success' => true, 'data' => ['id' => $id]]; } /** * Delete a media item * @param int $id Media ID * @return array Success message */ private function delete($id) { if (!$id) { http_response_code(400); return ['success' => false, 'error' => 'ID required']; } $deleted = $this->media->delete($id); if (!$deleted) { http_response_code(404); return ['success' => false, 'error' => 'Media not found']; } $this->logger->logRequest('DELETE', "/api/media/$id", [], null); $this->logger->logResponse('DELETE', "/api/media/$id", 200, ['message' => 'Media deleted successfully']); return ['success' => true, 'message' => 'Media deleted successfully']; } }