Add XMLTV JSON cache
This commit is contained in:
+134
-57
@@ -3,29 +3,66 @@
|
|||||||
class XmlTv
|
class XmlTv
|
||||||
{
|
{
|
||||||
private string $file;
|
private string $file;
|
||||||
|
private string $cacheFile;
|
||||||
private string $timezone;
|
private string $timezone;
|
||||||
|
|
||||||
public function __construct(string $file, string $timezone = 'Europe/Vienna')
|
public function __construct(
|
||||||
{
|
string $file,
|
||||||
|
string $timezone = 'Europe/Vienna',
|
||||||
|
string $cacheFile = '/var/www/cache/guide.json'
|
||||||
|
) {
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
$this->timezone = $timezone;
|
$this->timezone = $timezone;
|
||||||
|
$this->cacheFile = $cacheFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function synchronizeChannels(Config $config): void
|
||||||
|
{
|
||||||
|
$data = $this->getCachedData();
|
||||||
|
$storedChannels = $config->getChannels();
|
||||||
|
|
||||||
|
$maxNumber = 0;
|
||||||
|
foreach ($storedChannels as $stored) {
|
||||||
|
$maxNumber = max($maxNumber, (int)($stored['number'] ?? 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($data['channels'] ?? [] as $id => $channel) {
|
||||||
|
if (!isset($storedChannels[$id])) {
|
||||||
|
$maxNumber++;
|
||||||
|
|
||||||
|
$storedChannels[$id] = [
|
||||||
|
'uuid' => bin2hex(random_bytes(16)),
|
||||||
|
'name' => $channel['name'] ?? $id,
|
||||||
|
'icon' => $channel['icon'] ?? '',
|
||||||
|
'country' => '',
|
||||||
|
'language' => '',
|
||||||
|
'enabled' => true,
|
||||||
|
'favorite' => false,
|
||||||
|
'number' => $maxNumber,
|
||||||
|
'group' => 'Unknown',
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$storedChannels[$id]['name'] = $channel['name'] ?? $storedChannels[$id]['name'];
|
||||||
|
$storedChannels[$id]['icon'] = $channel['icon'] ?? ($storedChannels[$id]['icon'] ?? '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($storedChannels, function ($a, $b) {
|
||||||
|
return ((int)($a['number'] ?? 999999)) <=> ((int)($b['number'] ?? 999999));
|
||||||
|
});
|
||||||
|
|
||||||
|
$config->saveChannels($storedChannels);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function load(?Config $config = null): array
|
public function load(?Config $config = null): array
|
||||||
{
|
{
|
||||||
|
$data = $this->getCachedData();
|
||||||
|
|
||||||
|
$channelConfig = $config ? $config->getChannels() : [];
|
||||||
$channels = [];
|
$channels = [];
|
||||||
$programmes = [];
|
$programmes = [];
|
||||||
$channelConfig = $config ? $config->getChannels() : [];
|
|
||||||
|
|
||||||
if (!file_exists($this->file)) {
|
|
||||||
return [$channels, $programmes];
|
|
||||||
}
|
|
||||||
|
|
||||||
$xml = simplexml_load_file($this->file);
|
|
||||||
|
|
||||||
foreach ($xml->channel as $channel) {
|
|
||||||
$id = (string)$channel['id'];
|
|
||||||
|
|
||||||
|
foreach ($data['channels'] ?? [] as $id => $channel) {
|
||||||
$cfg = $channelConfig[$id] ?? [];
|
$cfg = $channelConfig[$id] ?? [];
|
||||||
|
|
||||||
if (($cfg['enabled'] ?? true) !== true) {
|
if (($cfg['enabled'] ?? true) !== true) {
|
||||||
@@ -34,16 +71,60 @@ class XmlTv
|
|||||||
|
|
||||||
$channels[$id] = [
|
$channels[$id] = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'name' => $cfg['name'] ?? (string)$channel->{'display-name'},
|
'name' => $cfg['name'] ?? $channel['name'] ?? $id,
|
||||||
'icon' => $cfg['icon'] ?? (isset($channel->icon) ? (string)$channel->icon['src'] : null),
|
'icon' => $cfg['icon'] ?? $channel['icon'] ?? '',
|
||||||
'number' => (int)($cfg['number'] ?? 999999),
|
'number' => (int)($cfg['number'] ?? 999999),
|
||||||
'favorite' => (bool)($cfg['favorite'] ?? false),
|
'favorite' => (bool)($cfg['favorite'] ?? false),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
foreach ($channel['programmes'] ?? [] as $p) {
|
||||||
|
$programmes[$id][] = [
|
||||||
|
'title' => $p['title'] ?? '',
|
||||||
|
'desc' => $p['description'] ?? '',
|
||||||
|
'category' => $p['category'] ?? '',
|
||||||
|
'start' => (new DateTime())->setTimestamp((int)$p['start'])->setTimezone(new DateTimeZone($this->timezone)),
|
||||||
|
'stop' => (new DateTime())->setTimestamp((int)$p['stop'])->setTimezone(new DateTimeZone($this->timezone)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uasort($channels, function ($a, $b) {
|
||||||
|
return ($a['number'] ?? 999999) <=> ($b['number'] ?? 999999);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [$channels, $programmes];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rebuildCache(): array
|
||||||
|
{
|
||||||
|
$data = [
|
||||||
|
'updated' => date('c'),
|
||||||
|
'source' => $this->file,
|
||||||
|
'channels' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (!file_exists($this->file)) {
|
||||||
|
$this->writeCache($data);
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = simplexml_load_file($this->file);
|
||||||
|
|
||||||
|
foreach ($xml->channel as $channel) {
|
||||||
|
$id = (string)$channel['id'];
|
||||||
|
|
||||||
|
$data['channels'][$id] = [
|
||||||
|
'id' => $id,
|
||||||
|
'name' => (string)$channel->{'display-name'},
|
||||||
|
'icon' => isset($channel->icon) ? (string)$channel->icon['src'] : '',
|
||||||
|
'programmes' => [],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($xml->programme as $programme) {
|
foreach ($xml->programme as $programme) {
|
||||||
$channelId = (string)$programme['channel'];
|
$channelId = (string)$programme['channel'];
|
||||||
if (!isset($channels[$channelId])) {
|
|
||||||
|
if (!isset($data['channels'][$channelId])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,66 +135,62 @@ class XmlTv
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$programmes[$channelId][] = [
|
$data['channels'][$channelId]['programmes'][] = [
|
||||||
'title' => (string)$programme->title,
|
'title' => (string)$programme->title,
|
||||||
'desc' => (string)$programme->desc,
|
'subtitle' => (string)$programme->{'sub-title'},
|
||||||
|
'description' => (string)$programme->desc,
|
||||||
'category' => (string)$programme->category,
|
'category' => (string)$programme->category,
|
||||||
'start' => $start,
|
'start' => $start->getTimestamp(),
|
||||||
'stop' => $stop,
|
'stop' => $stop->getTimestamp(),
|
||||||
|
'duration' => $stop->getTimestamp() - $start->getTimestamp(),
|
||||||
|
'year' => (string)$programme->date,
|
||||||
|
'rating' => isset($programme->rating->value) ? (string)$programme->rating->value : '',
|
||||||
|
'episode' => isset($programme->{'episode-num'}) ? (string)$programme->{'episode-num'} : '',
|
||||||
|
'icon' => isset($programme->icon) ? (string)$programme->icon['src'] : '',
|
||||||
|
'country' => (string)$programme->country,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
uasort($channels, function ($a, $b) {
|
foreach ($data['channels'] as &$channel) {
|
||||||
return ($a['number'] ?? 999999) <=> ($b['number'] ?? 999999);
|
usort($channel['programmes'], function ($a, $b) {
|
||||||
});
|
return $a['start'] <=> $b['start'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return [$channels, $programmes];
|
unset($channel);
|
||||||
|
|
||||||
|
$this->writeCache($data);
|
||||||
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function synchronizeChannels(Config $config): void
|
public function getCachedData(): array
|
||||||
{
|
{
|
||||||
if (!file_exists($this->file)) {
|
if (!file_exists($this->cacheFile)) {
|
||||||
return;
|
return $this->rebuildCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
$xml = simplexml_load_file($this->file);
|
$xmlMtime = file_exists($this->file) ? filemtime($this->file) : 0;
|
||||||
$storedChannels = $config->getChannels();
|
$cacheMtime = filemtime($this->cacheFile);
|
||||||
|
|
||||||
$maxNumber = 0;
|
if ($xmlMtime > $cacheMtime) {
|
||||||
foreach ($storedChannels as $stored) {
|
return $this->rebuildCache();
|
||||||
$maxNumber = max($maxNumber, (int)($stored['number'] ?? 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($xml->channel as $channel) {
|
$data = json_decode(file_get_contents($this->cacheFile), true);
|
||||||
$id = (string)$channel['id'];
|
|
||||||
$name = (string)$channel->{'display-name'};
|
|
||||||
$icon = isset($channel->icon) ? (string)$channel->icon['src'] : '';
|
|
||||||
|
|
||||||
if (!isset($storedChannels[$id])) {
|
if (!is_array($data)) {
|
||||||
$maxNumber++;
|
return $this->rebuildCache();
|
||||||
|
|
||||||
$storedChannels[$id] = [
|
|
||||||
'uuid' => bin2hex(random_bytes(16)),
|
|
||||||
'name' => $name,
|
|
||||||
'icon' => $icon,
|
|
||||||
'country' => '',
|
|
||||||
'language' => '',
|
|
||||||
'enabled' => true,
|
|
||||||
'favorite' => false,
|
|
||||||
'number' => $maxNumber,
|
|
||||||
'group' => 'Unknown',
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$storedChannels[$id]['name'] = $name;
|
|
||||||
$storedChannels[$id]['icon'] = $icon;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uasort($storedChannels, function ($a, $b) {
|
return $data;
|
||||||
return ((int)($a['number'] ?? 999999)) <=> ((int)($b['number'] ?? 999999));
|
}
|
||||||
});
|
|
||||||
|
|
||||||
$config->saveChannels($storedChannels);
|
private function writeCache(array $data): void
|
||||||
|
{
|
||||||
|
file_put_contents(
|
||||||
|
$this->cacheFile,
|
||||||
|
json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function parseTime(string $value): ?DateTime
|
private function parseTime(string $value): ?DateTime
|
||||||
|
|||||||
Reference in New Issue
Block a user