1
0
Files
Bridges/TheTVDBBridge.php
2025-11-24 19:15:33 +01:00

184 lines
6.0 KiB
PHP

<?php
declare(strict_types=1);
/**
* TheTVDB Bridge
* Returns new episodes from TheTVDB series pages
*/
class TheTVDBBridge extends BridgeAbstract
{
const NAME = 'TheTVDB Bridge';
const URI = 'https://www.thetvdb.com/';
const DESCRIPTION = 'Returns new episodes from TheTVDB series pages (English)';
const MAINTAINER = 'Your Name';
private $seriesTitle = '';
const PARAMETERS = [
[
'series' => [
'name' => 'Series Slug',
'type' => 'text',
'required' => true,
'exampleValue' => 'hot-ones',
'title' => 'Series slug from the URL (e.g., "hot-ones" from https://www.thetvdb.com/series/hot-ones)'
],
'limit' => [
'name' => 'Max Episodes',
'type' => 'number',
'required' => false,
'defaultValue' => 20,
'title' => 'Maximum number of episodes to return (default: 20)'
]
]
];
public function collectData()
{
$series = $this->getInput('series');
$limit = $this->getInput('limit') ?? 20;
$url = self::URI . 'series/' . $series . '/allseasons/official';
$html = getSimpleHTMLDOM($url);
if (!$html) {
throw new \Exception('Unable to load page: ' . $url);
}
// Extract series title for author field
// Try to get series title from the page title
$titleElement = $html->find('title', 0);
if ($titleElement) {
// Format: "Hot Ones - Aired Order - All Seasons - TheTVDB.com"
$pageTitle = trim($titleElement->plaintext);
// Take only the first part before " - "
$parts = explode(' - ', $pageTitle);
if (!empty($parts[0])) {
$this->seriesTitle = trim($parts[0]);
}
}
// Find all episode list items
$episodes = $html->find('li.list-group-item');
if (empty($episodes)) {
throw new \Exception('No episodes found. Please check if the series slug is correct.');
}
// Reverse to get newest episodes first
$episodes = array_reverse($episodes);
$count = 0;
foreach ($episodes as $episode) {
if ($count >= $limit) {
break;
}
// Skip if this is not an episode (some list items might be headers)
$heading = $episode->find('h4.list-group-item-heading', 0);
if (!$heading) {
continue;
}
// Check if this is a special episode
$isSpecial = strpos($episode->class, 'list-group-item-special') !== false;
// Extract episode label (S28E08 or SPECIAL 0x202)
$labelElement = $isSpecial
? $episode->find('small.episode-label', 0)
: $episode->find('span.episode-label', 0);
$episodeLabel = $labelElement ? trim($labelElement->plaintext) : '';
// Convert SPECIAL format to S00E## format
if ($isSpecial && preg_match('/SPECIAL\s+0x(\d+)/i', $episodeLabel, $matches)) {
$episodeLabel = 'S00E' . str_pad($matches[1], 2, '0', STR_PAD_LEFT);
}
// Extract title and URL
$titleLink = $episode->find('h4 a', 0);
if (!$titleLink) {
continue; // Skip if no title link found
}
$title = trim($titleLink->plaintext);
$episodeUrl = self::URI . ltrim($titleLink->href, '/');
// Extract air date
$dateElement = $episode->find('ul.list-inline li', 0);
$airDate = $dateElement ? trim($dateElement->plaintext) : '';
// Extract network/platform
$networkElement = $episode->find('ul.list-inline li', 1);
$network = $networkElement ? trim($networkElement->plaintext) : '';
// Extract description
$descElement = $episode->find('.list-group-item-text p', 0);
$description = $descElement ? trim($descElement->innertext) : '';
// Extract thumbnail image
$imgElement = $episode->find('.list-group-item-text img', 0);
$thumbnail = '';
if ($imgElement) {
// Check for lazy-loaded images (data-src) first, then fallback to src
$thumbnail = $imgElement->getAttribute('data-src') ?: $imgElement->src;
// Make sure URL is absolute
if ($thumbnail && !str_starts_with($thumbnail, 'http')) {
$thumbnail = 'https:' . $thumbnail;
}
}
// Build content HTML
$content = '';
// Add thumbnail if available
if ($thumbnail) {
$content .= '<p><img src="' . htmlspecialchars($thumbnail) . '" style="max-width: 100%; height: auto;"></p>';
}
// Add description
if ($description) {
$content .= '<p>' . $description . '</p>';
}
// Parse timestamp from air date
$timestamp = null;
if ($airDate) {
$parsedTime = strtotime($airDate);
if ($parsedTime !== false) {
$timestamp = $parsedTime;
}
}
// Create RSS item
$item = [
'uri' => $episodeUrl,
'title' => $this->seriesTitle ? ($this->seriesTitle . ' ' . $episodeLabel . ' - ' . $title) : ($episodeLabel . ' - ' . $title),
'author' => $this->seriesTitle,
'content' => $content,
'timestamp' => $timestamp,
'uid' => $episodeUrl,
];
$this->items[] = $item;
$count++;
}
}
public function getName()
{
if ($this->seriesTitle) {
return $this->seriesTitle . ' - TheTVDB';
}
return parent::getName();
}
public function getIcon()
{
return 'https://www.google.com/s2/favicons?domain=thetvdb.com&sz=32';
}
}