[ 'show_id' => [ 'name' => 'TVMaze Show ID', 'type' => 'number', 'required' => true, 'exampleValue' => '54421', 'title' => 'Find the Show ID in the URL: tvmaze.com/shows/ID/name' ], 'limit' => [ 'name' => 'Maximum number of episodes', 'type' => 'number', 'required' => false, 'defaultValue' => 50 ] ] ]; private $showTitle = ''; private $showUrl = ''; private $officialSite = ''; private $webChannelName = ''; public function getIcon() { return 'https://www.google.com/s2/favicons?domain=www.tvmaze.com&sz=32'; } public function getName() { if (!empty($this->showTitle)) { $suffix = !empty($this->webChannelName) ? $this->webChannelName : 'TVMaze'; return $this->showTitle . ' - ' . $suffix; } return parent::getName(); } public function getURI() { // Prefer officialSite (e.g. Amazon Prime link) if (!empty($this->officialSite)) { return $this->officialSite; } if (!empty($this->showUrl)) { return $this->showUrl; } $showId = $this->getInput('show_id'); if (!empty($showId)) { return self::URI . '/shows/' . $showId; } return self::URI; } public function collectData() { $showId = $this->getInput('show_id'); $limit = $this->getInput('limit') ?? 50; if (empty($showId)) { returnClientError('Show ID is required.'); } // First fetch show information $showUrl = 'https://api.tvmaze.com/shows/' . urlencode((string)$showId); $showJson = getContents($showUrl); $showData = json_decode($showJson, true); if (!$showData) { returnServerError('Show not found. Please check the Show ID.'); } $this->showTitle = $showData['name'] ?? 'Unknown Series'; $this->showUrl = $showData['url'] ?? ''; $this->officialSite = $showData['officialSite'] ?? ''; $this->webChannelName = $showData['webChannel']['name'] ?? $showData['network']['name'] ?? ''; // Fetch episodes $episodesUrl = 'https://api.tvmaze.com/shows/' . urlencode((string)$showId) . '/episodes'; $episodesJson = getContents($episodesUrl); $episodes = json_decode($episodesJson, true); if (!$episodes || !is_array($episodes)) { returnServerError('No episodes found.'); } // Sort by season and episode (newest first for feed) usort($episodes, function ($a, $b) { // First by season, then by episode (descending) if ($a['season'] !== $b['season']) { return $b['season'] - $a['season']; } return $b['number'] - $a['number']; }); // Limit the number of episodes $episodes = array_slice($episodes, 0, (int)$limit); foreach ($episodes as $episode) { $item = []; // Title: "Series Title S01E01: Episode Title" $seasonNum = $episode['season'] ?? 1; $episodeNum = $episode['number'] ?? 0; $episodeTitle = $episode['name'] ?? 'Unknown Episode'; $item['title'] = sprintf( '%s S%02dE%02d: %s', $this->showTitle, $seasonNum, $episodeNum, $episodeTitle ); // Episode URL (prefer streaming service officialSite) if (!empty($this->officialSite)) { $item['uri'] = $this->officialSite; } else { $item['uri'] = $episode['url'] ?? self::URI; } // Author: Streaming service name if (!empty($this->webChannelName)) { $item['author'] = $this->webChannelName; } // Unique ID $item['uid'] = 'tvmaze-' . ($episode['id'] ?? $showId . '-' . $seasonNum . '-' . $episodeNum); // Timestamp from airdate if (!empty($episode['airdate'])) { $timestamp = strtotime($episode['airdate']); if ($timestamp !== false) { $item['timestamp'] = $timestamp; } } // Content: Image + Description + Details $content = ''; // Thumbnail $imageUrl = $episode['image']['original'] ?? $episode['image']['medium'] ?? null; if ($imageUrl) { $content .= '' . htmlspecialchars($episodeTitle) . '
'; $item['enclosures'] = [$imageUrl]; } // Description $summary = $episode['summary'] ?? ''; if (!empty($summary)) { // TVMaze returns HTML, keep it for content $content .= '

' . $summary . '

'; } $item['content'] = $content; $this->items[] = $item; } } public function detectParameters($url) { // URL-Format: https://www.tvmaze.com/shows/54421/lol-last-one-laughing if (preg_match('#tvmaze\.com/shows/(\d+)#i', $url, $matches)) { return [ 'show_id' => $matches[1] ]; } return null; } }