diff --git a/GronkhTVBridge.php b/GronkhTVBridge.php
new file mode 100644
index 0000000..9ba9fe4
--- /dev/null
+++ b/GronkhTVBridge.php
@@ -0,0 +1,123 @@
+ [
+ 'name' => 'Limit',
+ 'type' => 'number',
+ 'required' => false,
+ 'defaultValue' => 20,
+ 'title' => 'Maximale Anzahl der Videos'
+ ]
+ ]
+ ];
+
+ public function getIcon()
+ {
+ return 'https://www.google.com/s2/favicons?domain=gronkh.tv&sz=32';
+ }
+
+ public function collectData()
+ {
+ $limit = $this->getInput('limit') ?? 20;
+
+ $apiUrl = 'https://api.gronkh.tv/v1/video/discovery/recent';
+ $json = getContents($apiUrl);
+ $data = json_decode($json, true);
+
+ if (!isset($data['discovery']) || !is_array($data['discovery'])) {
+ returnServerError('Konnte die GronkhTV-Videos nicht abrufen');
+ }
+
+ $count = 0;
+ foreach ($data['discovery'] as $video) {
+ if ($count >= $limit) {
+ break;
+ }
+
+ $item = [];
+ $item['title'] = $video['title'];
+ $item['uri'] = 'https://gronkh.tv/streams/' . $video['episode'];
+ $item['author'] = 'GronkhTV';
+ $item['timestamp'] = strtotime($video['created_at']);
+ $item['uid'] = 'gronkhtv-' . $video['episode'];
+
+ // Content mit Vorschaubild und Infos
+ $content = '';
+ if (!empty($video['preview_url'])) {
+ // Lade Bild mit Referer-Header und konvertiere zu base64
+ $imageData = $this->getImageAsBase64($video['preview_url']);
+ if ($imageData) {
+ $content .= '
';
+ }
+ }
+
+ // Videodauer formatieren
+ if (isset($video['video_length'])) {
+ $duration = $this->formatDuration($video['video_length']);
+ $content .= '
Dauer: ' . $duration . '
'; + } + + // Views + if (isset($video['views'])) { + $content .= 'Aufrufe: ' . number_format($video['views'], 0, ',', '.') . '
'; + } + + $item['content'] = $content; + + $this->items[] = $item; + $count++; + } + } + + private function formatDuration(int $seconds): string + { + $hours = floor($seconds / 3600); + $minutes = floor(($seconds % 3600) / 60); + $seconds = $seconds % 60; + + if ($hours > 0) { + return sprintf('%d:%02d:%02d', $hours, $minutes, $seconds); + } else { + return sprintf('%d:%02d', $minutes, $seconds); + } + } + + private function getImageAsBase64(string $imageUrl): ?string + { + try { + // Lade Bild mit Referer-Header + $imageData = getContents($imageUrl, [ + 'Referer: https://gronkh.tv' + ]); + + if ($imageData === false || empty($imageData)) { + return null; + } + + // Bestimme MIME-Type aus URL + $mimeType = 'image/jpeg'; // Standard + if (preg_match('/\.(png|gif|webp)$/i', $imageUrl, $matches)) { + $extension = strtolower($matches[1]); + $mimeType = 'image/' . $extension; + } + + // Konvertiere zu base64 data URI + $base64 = base64_encode($imageData); + return 'data:' . $mimeType . ';base64,' . $base64; + } catch (\Exception $e) { + // Bei Fehler null zurückgeben (Bild wird übersprungen) + return null; + } + } +} diff --git a/README.md b/README.md index 16f8f1e..123f792 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,15 @@ Diese Sammlung enthält verschiedene Bridge-Implementierungen für RSS-Bridge, u ### [Girls' Frontline 2: Exilium News Bridge](https://bridge.ponywave.de/#bridge-GirlsFrontline2ExiliumNewsBridge) (Von Akamaru) - **Beschreibung**: Zeigt die neuesten Nachrichten von Girls' Frontline 2: Exilium +### [GronkhTV Bridge](https://bridge.ponywave.de/#bridge-GronkhTVBridge) (Von Akamaru) +- **Beschreibung**: Neue Uploads auf GronkhTV +- **Parameter**: + - **Limit** (optional): Maximale Anzahl der Videos (Standard: 20) +- **Hinweise**: + - Vorschaubilder werden als base64-kodierte Data-URIs eingebettet (Referer-Schutz) + - Zeigt Videodauer und Aufrufe an + - Autor ist auf "GronkhTV" gesetzt + ### [Holonometria Manga Bridge](https://bridge.ponywave.de/#bridge-HolonometriaMangaBridge) (Von Brawl, Akamaru) - **Beschreibung**: Zeigt die neuesten Kapitel der Holonometria Manga-Serie