From f642bba7ce699a5c3a540d1e8472d4744786338d Mon Sep 17 00:00:00 2001 From: Akamaru Date: Mon, 24 Nov 2025 00:00:38 +0100 Subject: [PATCH] Neu: KiKA Serien Bridge --- KiKASeriesBridge.php | 219 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) create mode 100644 KiKASeriesBridge.php diff --git a/KiKASeriesBridge.php b/KiKASeriesBridge.php new file mode 100644 index 0000000..075c2f8 --- /dev/null +++ b/KiKASeriesBridge.php @@ -0,0 +1,219 @@ + [ + 'series_id' => [ + 'name' => 'Serien-ID', + 'type' => 'text', + 'required' => true, + 'exampleValue' => 'tanoshii-100', + 'title' => 'Die Serien-ID findest du in der URL: kika.de/serien-name/serien-name-100' + ], + 'limit' => [ + 'name' => 'Maximale Anzahl an Episoden', + 'type' => 'number', + 'required' => false, + 'defaultValue' => 50 + ] + ] + ]; + + private $seriesTitle = ''; + private $seriesUrl = ''; + + public function getIcon() + { + return 'https://www.google.com/s2/favicons?domain=www.kika.de&sz=32'; + } + + public function getName() + { + if (!empty($this->seriesTitle)) { + return $this->seriesTitle . ' - KiKA'; + } + return parent::getName(); + } + + public function getURI() + { + if (!empty($this->seriesUrl)) { + return self::URI . $this->seriesUrl; + } + + $seriesId = $this->getInput('series_id'); + if (!empty($seriesId)) { + return self::URI . '/' . $seriesId; + } + + return self::URI; + } + + public function collectData() + { + $seriesId = $this->getInput('series_id'); + $limit = $this->getInput('limit') ?? 50; + + if (empty($seriesId)) { + returnClientError('Serien-ID ist erforderlich.'); + } + + // Serien-Informationen abrufen + $brandsUrl = self::API_URI . urlencode($seriesId); + $brandsJson = getContents($brandsUrl); + $brandsData = json_decode($brandsJson, true); + + if (!$brandsData) { + returnServerError('Serie nicht gefunden. Überprüfe die Serien-ID.'); + } + + $this->seriesTitle = $brandsData['title'] ?? 'Unbekannte Serie'; + $this->seriesUrl = $brandsData['urlPath'] ?? ''; + + // Videos-API-URL extrahieren + $videosPageUrl = $brandsData['videoSubchannel']['videosPageUrl'] ?? null; + if (!$videosPageUrl) { + returnServerError('Keine Videos für diese Serie gefunden.'); + } + + // Alle Seiten der API abrufen (Videos sind nicht chronologisch sortiert) + $videos = []; + $page = 0; + $maxPages = 10; // Sicherheitslimit + + while ($page < $maxPages) { + $pageUrl = preg_replace('/page=\d+/', 'page=' . $page, $videosPageUrl); + + try { + $videosJson = getContents($pageUrl); + } catch (Exception $e) { + // 404 = keine weiteren Seiten + break; + } + + $videosData = json_decode($videosJson, true); + + if (!$videosData || !isset($videosData['content']) || !is_array($videosData['content'])) { + break; + } + + $pageVideos = $videosData['content']; + if (empty($pageVideos)) { + break; + } + + $videos = array_merge($videos, $pageVideos); + $page++; + } + + if (empty($videos)) { + returnServerError('Keine Episoden gefunden.'); + } + + // Sortiere nach Datum (neueste zuerst) + usort($videos, function ($a, $b) { + $timeA = strtotime($a['date'] ?? '1970-01-01'); + $timeB = strtotime($b['date'] ?? '1970-01-01'); + return $timeB - $timeA; + }); + + // Limitiere die Anzahl + $videos = array_slice($videos, 0, (int)$limit); + + foreach ($videos as $video) { + $item = []; + + // Titel zusammenbauen + $episodeTitle = $video['title'] ?? 'Unbekannte Episode'; + $season = $video['videoDetails']['season'] ?? null; + $episodeNum = $video['videoDetails']['episodeNumber'] ?? null; + + if ($season && $episodeNum) { + $item['title'] = sprintf( + '%s S%02dE%02d: %s', + $this->seriesTitle, + (int)$season, + (int)$episodeNum, + $episodeTitle + ); + } else { + $item['title'] = $this->seriesTitle . ': ' . $episodeTitle; + } + + // URL zur Episode + $videoId = $video['id'] ?? ''; + $urlPath = $video['urlPath'] ?? ''; + if (!empty($urlPath) && !empty($videoId)) { + $item['uri'] = self::URI . $urlPath . '/' . $videoId; + } else { + $item['uri'] = $this->getURI(); + } + + // Eindeutige ID + $item['uid'] = 'kika-' . $videoId; + + // Zeitstempel + if (!empty($video['date'])) { + $timestamp = strtotime($video['date']); + if ($timestamp !== false) { + $item['timestamp'] = $timestamp; + } + } + + // Autor + $item['author'] = 'KiKA'; + + // Content: Bild + Beschreibung + Details + $content = ''; + + // Vorschaubild + $imageUrlScheme = $video['teaserImage']['urlScheme'] ?? null; + if ($imageUrlScheme) { + $imageUrl = self::URI . str_replace(['**imageVariant**', '**width**'], ['tlarge169', '960'], $imageUrlScheme); + $imageAlt = $video['teaserImage']['alt'] ?? $episodeTitle; + $content .= '' . htmlspecialchars($imageAlt) . '
'; + $item['enclosures'] = [$imageUrl]; + } + + // Beschreibung + $description = $video['videoDetails']['description'] ?? $video['teaserText'] ?? ''; + if (!empty($description)) { + $content .= '

' . htmlspecialchars($description) . '

'; + } + + $item['content'] = $content; + + $this->items[] = $item; + } + } + + public function detectParameters($url) + { + // URL-Format: https://www.kika.de/serien-name/serien-name-100 + // oder: https://www.kika.de/serien-name/videos/video-id + if (preg_match('#kika\.de/([^/]+)/([^/]+-\d+)(?:/|$)#i', $url, $matches)) { + return [ + 'series_id' => $matches[2] + ]; + } + + // Fallback: Versuche nur den Slug zu extrahieren + if (preg_match('#kika\.de/([a-z0-9-]+-\d+)#i', $url, $matches)) { + return [ + 'series_id' => $matches[1] + ]; + } + + return null; + } +}