'Nur POST-Anfragen erlaubt']); exit; } // Lese JSON-Input $rawInput = file_get_contents('php://input'); $input = json_decode($rawInput, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('Ungültiges JSON: ' . json_last_error_msg()); } if (!isset($input['playlistId']) || !isset($input['apiKey'])) { http_response_code(400); echo json_encode(['error' => 'playlistId und apiKey sind erforderlich']); exit; } $playlistId = $input['playlistId']; $apiKey = $input['apiKey']; // Validierung if (empty($playlistId) || empty($apiKey)) { http_response_code(400); echo json_encode(['error' => 'playlistId und apiKey dürfen nicht leer sein']); exit; } $videos = []; $pageToken = ''; $maxResults = 50; $playlistTitle = ''; // Prüfe ob cURL verfügbar ist if (!function_exists('curl_init')) { throw new Exception('cURL ist nicht verfügbar. Bitte aktiviere die cURL-Extension in PHP.'); } // Hole Playlist-Informationen (Titel) $playlistInfoUrl = "https://www.googleapis.com/youtube/v3/playlists?part=snippet&id=" . urlencode($playlistId) . "&key=" . urlencode($apiKey); $playlistInfoResponse = curlRequest($playlistInfoUrl); if ($playlistInfoResponse !== false) { $playlistInfoData = json_decode($playlistInfoResponse, true); if (isset($playlistInfoData['items'][0]['snippet']['title'])) { $playlistTitle = $playlistInfoData['items'][0]['snippet']['title']; } } // Hole alle Videos der Playlist (paginiert) do { $url = "https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails&playlistId=" . urlencode($playlistId) . "&maxResults=" . $maxResults . "&pageToken=" . urlencode($pageToken) . "&key=" . urlencode($apiKey); $response = curlRequest($url); if ($response === false) { throw new Exception('API-Anfrage fehlgeschlagen (Netzwerkfehler)'); } $data = json_decode($response, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('Ungültige JSON-Antwort von YouTube API'); } if (isset($data['error'])) { $errorMsg = $data['error']['message'] ?? 'YouTube API Fehler'; $errorCode = $data['error']['code'] ?? 'unbekannt'; throw new Exception("YouTube API Fehler ($errorCode): $errorMsg"); } if (!isset($data['items'])) { throw new Exception('Ungültige API-Antwort: items fehlt'); } // Sammle Video-IDs $videoIds = array_map(function($item) { return $item['contentDetails']['videoId']; }, $data['items']); if (empty($videoIds)) { break; // Keine Videos mehr } // Hole Video-Details (inkl. Upload-Datum und Dauer) $videoDetailsUrl = "https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=" . implode(',', $videoIds) . "&key=" . urlencode($apiKey); $videoResponse = curlRequest($videoDetailsUrl); if ($videoResponse === false) { throw new Exception('Video-Details konnten nicht geladen werden'); } $videoData = json_decode($videoResponse, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('Ungültige JSON-Antwort bei Video-Details'); } if (isset($videoData['error'])) { $errorMsg = $videoData['error']['message'] ?? 'YouTube API Fehler'; throw new Exception("YouTube API Fehler bei Video-Details: $errorMsg"); } // Extrahiere Upload-Daten und Dauer if (isset($videoData['items'])) { foreach ($videoData['items'] as $video) { $videos[] = [ 'publishedAt' => $video['snippet']['publishedAt'] ?? null, 'duration' => $video['contentDetails']['duration'] ?? null ]; } } $pageToken = $data['nextPageToken'] ?? ''; } while ($pageToken); // Berechne Gesamtdauer $totalMinutes = 0; foreach ($videos as $video) { if ($video['duration']) { $totalMinutes += parseDuration($video['duration']); } } // Finde ältestes und neuestes Datum $dates = array_filter(array_map(function($video) { return $video['publishedAt']; }, $videos)); sort($dates); $oldestDate = count($dates) > 0 ? substr($dates[0], 0, 10) : null; $newestDate = count($dates) > 0 ? substr($dates[count($dates) - 1], 0, 10) : null; // Sende Ergebnis echo json_encode([ 'playlistTitle' => $playlistTitle, 'videoCount' => count($videos), 'totalMinutes' => $totalMinutes, 'oldestDate' => $oldestDate, 'newestDate' => $newestDate ]); } catch (Exception $e) { http_response_code(500); echo json_encode([ 'error' => $e->getMessage(), 'file' => basename($e->getFile()), 'line' => $e->getLine() ]); } /** * Macht HTTP-Anfrage mit cURL */ function curlRequest($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_TIMEOUT, 30); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'YouTube Playlist Analyzer/1.0'); $response = curl_exec($ch); $error = curl_error($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($response === false) { throw new Exception('cURL-Fehler: ' . $error); } return $response; } /** * Konvertiert ISO 8601 Duration in Minuten * Format: PT#H#M#S */ function parseDuration($duration) { preg_match('/PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/', $duration, $matches); $hours = isset($matches[1]) ? (int)$matches[1] : 0; $minutes = isset($matches[2]) ? (int)$matches[2] : 0; $seconds = isset($matches[3]) ? (int)$matches[3] : 0; // Auf volle Minuten aufrunden $totalMinutes = $hours * 60 + $minutes + ceil($seconds / 60); return $totalMinutes; } ?>