diff --git a/index.html b/index.html index edb5544..b7d9a35 100644 --- a/index.html +++ b/index.html @@ -217,6 +217,10 @@

YouTube Thumbnail Viewer

Zeige Thumbnails zu YouTube-Videos an und speicher sie

+ +

YouTube Playlist Analyzer

+

Analysiere YouTube-Playlists

+

Flash Downloader

Downloade Flash-Dateien von Z0R und FUS RO GA

diff --git a/sitemap.txt b/sitemap.txt index 6c0f6b4..05cd564 100644 --- a/sitemap.txt +++ b/sitemap.txt @@ -1,31 +1,32 @@ https://tools.ponywave.de/ -https://tools.ponywave.de/text_decoder -https://tools.ponywave.de/sys_info -https://tools.ponywave.de/zeitzonen -https://tools.ponywave.de/dsgvo_helper -https://tools.ponywave.de/text_cleaner -https://tools.ponywave.de/text_sorter -https://tools.ponywave.de/yt_thumb -https://tools.ponywave.de/flash_dl -https://tools.ponywave.de/kemonogen -https://tools.ponywave.de/breakout -https://tools.ponywave.de/emoji_jump https://tools.ponywave.de/2048 -https://tools.ponywave.de/solitaire -https://tools.ponywave.de/ba_memory -https://tools.ponywave.de/cell -https://tools.ponywave.de/shape_shifter -https://tools.ponywave.de/dogify -https://tools.ponywave.de/bohne -https://tools.ponywave.de/pinkie_timer -https://tools.ponywave.de/depp_gpt -https://tools.ponywave.de/emoji -https://tools.ponywave.de/banana_run -https://tools.ponywave.de/pokemon_quiz -https://tools.ponywave.de/gronkh_games -https://tools.ponywave.de/url_expander -https://tools.ponywave.de/minesweeper https://tools.ponywave.de/anime_graph -https://tools.ponywave.de/favorites_viewer +https://tools.ponywave.de/ba_memory +https://tools.ponywave.de/ba_steam +https://tools.ponywave.de/banana_run +https://tools.ponywave.de/bohne +https://tools.ponywave.de/breakout +https://tools.ponywave.de/cell https://tools.ponywave.de/chrome_extensions_checker -https://tools.ponywave.de/ba_steam \ No newline at end of file +https://tools.ponywave.de/depp_gpt +https://tools.ponywave.de/dogify +https://tools.ponywave.de/dsgvo_helper +https://tools.ponywave.de/emoji +https://tools.ponywave.de/emoji_jump +https://tools.ponywave.de/favorites_viewer +https://tools.ponywave.de/flash_dl +https://tools.ponywave.de/gronkh_games +https://tools.ponywave.de/kemonogen +https://tools.ponywave.de/minesweeper +https://tools.ponywave.de/pinkie_timer +https://tools.ponywave.de/pokemon_quiz +https://tools.ponywave.de/shape_shifter +https://tools.ponywave.de/solitaire +https://tools.ponywave.de/sys_info +https://tools.ponywave.de/text_cleaner +https://tools.ponywave.de/text_decoder +https://tools.ponywave.de/text_sorter +https://tools.ponywave.de/url_expander +https://tools.ponywave.de/yt_playlist +https://tools.ponywave.de/yt_thumb +https://tools.ponywave.de/zeitzonen \ No newline at end of file diff --git a/yt_playlist/fetch_playlist.php b/yt_playlist/fetch_playlist.php new file mode 100644 index 0000000..e734064 --- /dev/null +++ b/yt_playlist/fetch_playlist.php @@ -0,0 +1,214 @@ + '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; +} +?> diff --git a/yt_playlist/index.html b/yt_playlist/index.html new file mode 100644 index 0000000..f9449cb --- /dev/null +++ b/yt_playlist/index.html @@ -0,0 +1,822 @@ + + + + + + YouTube Playlist Analyzer | PonyWave Tools + + + + + + + + + + + + + + +
+ +
+

YouTube Playlist Analyzer

+ +
+
+ + +
+ + +
+ + + +
+

Ergebnisse

+ +
+
+ Playlist: + - +
+
+ Videos: + - +
+
+ Gesamtlänge: + - +
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+ + +
+ +
+ +
+
+
+ +
+ + + + + +