-
Notifications
You must be signed in to change notification settings - Fork 19
/
xmltv.php
126 lines (104 loc) · 4.33 KB
/
xmltv.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php
set_time_limit(300);
$remoteEpgUrl = 'https://raw.githubusercontent.com/gogetta69/public-files/main/epg.xml';
$localEpgFilePath = 'channels/epg.xml';
$lastUpdatedFile = 'channels/last_updated_epg.txt';
$content = @file_get_contents($remoteEpgUrl);
if ($content === false) {
// Fallback: Check if we need to update the local EPG file
if (!file_exists($lastUpdatedFile) || (time() - file_get_contents($lastUpdatedFile)) > 10800) {
$epgUrls = [
"http://m3u4u.com/xml/jwmzn1wx72cj6m8dn721",
"https://raw.githubusercontent.com/gogetta69/public-files/main/Pluto-TV/us.xml",
"https://epg.pw/xmltv/epg_ZA.xml",
"https://epg.pw/api/epg.xml?channel_id=9025",
"https://epg.pw/api/epg.xml?channel_id=8862",
"https://epg.pw/api/epg.xml?channel_id=8306"
];
$mergedXml = new SimpleXMLElement('<tv/>');
foreach ($epgUrls as $url) {
$epgContent = fetchEPGContent($url);
if ($epgContent === false) {
continue;
}
// Check if the content is gzipped and decompress it
if (substr($url, -3) == '.gz') {
$epgContent = @gzdecode($epgContent);
if ($epgContent === false) {
error_log("Failed to decompress gzipped content from URL: $url");
continue;
}
}
// Fix the XML issues before parsing
$epgContent = fixXMLIssues($epgContent);
// Check if the XML content is valid
if (!preg_match('/<tv[^>]*>.*<\/tv>/s', $epgContent)) {
error_log("Invalid XML structure from URL: $url");
continue;
}
$xml = @simplexml_load_string($epgContent);
if ($xml === false) {
error_log("Failed to parse XML from URL: $url");
continue;
}
// Merge the data
foreach ($xml->channel as $channel) {
$dom = dom_import_simplexml($mergedXml);
$dom2 = dom_import_simplexml($channel);
$dom->appendChild($dom->ownerDocument->importNode($dom2, true));
}
foreach ($xml->programme as $programme) {
$dom = dom_import_simplexml($mergedXml);
$dom2 = dom_import_simplexml($programme);
$dom->appendChild($dom->ownerDocument->importNode($dom2, true));
}
}
// Save the merged EPG
file_put_contents($localEpgFilePath, $mergedXml->asXML());
file_put_contents($lastUpdatedFile, time());
}
// Use the local EPG file as the fallback content
$content = @file_get_contents($localEpgFilePath);
if ($content === false) {
// Log an error if reading the local file also fails
error_log('Failed to fetch the local EPG file.');
header('HTTP/1.1 500 Internal Server Error');
echo '<error>Unable to fetch the EPG data</error>';
exit;
}
} else {
// Save the fetched remote content to the local file for future use
if (file_put_contents($localEpgFilePath, $content) === false) {
// Log an error if saving the content fails
error_log('Failed to save the remote EPG content to the local file.');
} else {
file_put_contents($lastUpdatedFile, time());
}
}
// Output the EPG content
header('Content-Type: application/xml');
echo $content;
exit;
function fetchEPGContent($url) {
$context = stream_context_create(array(
'http' => array(
'timeout' => 30
)
));
$content = @file_get_contents($url, false, $context);
if ($content === false) {
error_log("Failed to fetch URL: $url");
return false;
}
return $content;
}
function fixXMLIssues($xmlContent) {
// Fix common encoding issues
$xmlContent = str_replace('&amp;', '&', $xmlContent);
// Ensure each <programme> tag is properly closed and separated
$xmlContent = preg_replace('/<\/programme>\s*<programme/', "</programme>\n<programme", $xmlContent);
// Clean up any hidden or special characters
$xmlContent = preg_replace('/[^\x20-\x7E]/', '', $xmlContent);
return $xmlContent;
}
?>