1
0
Files
PonyWave-Tools/yt_playlist/fetch_playlist.php
2025-10-07 22:03:29 +02:00

215 lines
6.8 KiB
PHP

<?php
// Fehlerberichterstattung für Debugging
error_reporting(E_ALL);
ini_set('display_errors', 0); // Keine Ausgabe, nur JSON
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
// Fehlerbehandlung
set_error_handler(function($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
try {
// Nur POST-Anfragen erlauben
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => '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;
}
?>