Better error reporting for errors when sending video to dreambox
[playVideoOnDreamboxProxy.git] / www / functions.php
1 <?php
2 function getPageUrl()
3 {
4     global $argv, $argc;
5     if (php_sapi_name() == 'cli') {
6         if ($argc < 2) {
7             errorInput('No URL given as command line parameter');
8         }
9         $pageUrl = $argv[1];
10     } else {
11         if (!isset($_SERVER['CONTENT_TYPE'])) {
12             errorInput('Content type header missing');
13         } else if ($_SERVER['CONTENT_TYPE'] != 'text/plain') {
14             errorInput('Content type is not text/plain but ' . $_SERVER['CONTENT_TYPE']);
15         }
16         $pageUrl = file_get_contents('php://input');
17     }
18     $parts = parse_url($pageUrl);
19     if ($parts === false) {
20         errorInput('Invalid URL in POST data');
21     } else if (!isset($parts['scheme'])) {
22         errorInput('Invalid URL in POST data: No scheme');
23     } else if ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https') {
24         errorInput('Invalid URL in POST data: Non-HTTP scheme');
25     }
26     return $pageUrl;
27 }
28
29 function getYoutubeDlJson($pageUrl, $youtubedlPath)
30 {
31     $cmd = $youtubedlPath
32         . ' --no-playlist'//would otherwise cause multiple json blocks
33         . ' --quiet'
34         . ' --dump-json'
35         . ' ' . escapeshellarg($pageUrl);
36
37     $descriptors = [
38         1 => ['pipe', 'w'],//stdout
39         2 => ['pipe', 'w'],//stderr
40     ];
41     $proc = proc_open($cmd, $descriptors, $pipes);
42     if ($proc === false) {
43         errorOut('Error running youtube-dl');
44     }
45     $stdout = stream_get_contents($pipes[1]);
46     $stderr = stream_get_contents($pipes[2]);
47
48     $exitCode = proc_close($proc);
49
50     if ($exitCode === 0) {
51         //stdout contains the JSON data
52         return $stdout;
53     }
54
55     if (strlen($stderr)) {
56         $lines = explode("\n", trim($stderr));
57         $lastLine = end($lines);
58     } else {
59         $lines = explode("\n", trim($stdout));
60         $lastLine = end($lines);
61     }
62
63     if ($exitCode === 127) {
64         errorOut(
65             'youtube-dl not found at ' . $youtubedlPath,
66             '500 youtube-dl not found'
67         );
68     } else if (strpos($lastLine, 'Unsupported URL') !== false) {
69         errorOut(
70             'Unsupported URL  at ' . $pageUrl,
71             '406 Unsupported URL (No video found)'
72         );
73     }
74
75     errorOut('youtube-dl error: ' . $lastLine);
76 }
77
78 function extractVideoUrlFromJson($json)
79 {
80     $data = json_decode($json);
81     if ($data === null) {
82         errorOut('Cannot decode JSON: ' . json_last_error_msg());
83     }
84
85     $url = null;
86     foreach ($data->formats as $format) {
87         if (strpos($format->format, 'hls') !== false) {
88             //dreambox 7080hd does not play hls files
89             continue;
90         }
91         if ($format->protocol == 'http_dash_segments') {
92             //split up into multiple small files
93             continue;
94         }
95         $url = $format->url;
96     }
97
98     if ($url === null) {
99         //use URL chosen by youtube-dl
100         $url = $data->url;
101     }
102
103     if ($url == '') {
104         errorOut(
105             'No video URL found',
106             '406 No video URL found'
107         );
108     }
109     return $url;
110 }
111
112 function playVideoOnDreambox($videoUrl, $dreamboxUrl)
113 {
114     ini_set('track_errors', 1);
115     $xml = @file_get_contents($dreamboxUrl . '/web/session');
116     if ($xml === false) {
117         if (!isset($http_response_header)) {
118             errorOut(
119                 'Error fetching dreambox web interface token: '
120                 . $GLOBALS['lastError']
121             );
122         }
123
124         list($http, $code, $message) = explode(
125             ' ', $http_response_header[0], 3
126         );
127         if ($code == 401) {
128             //dreambox web interface authentication has been enabled
129             errorOut(
130                 'Error: Web interface authentication is required',
131                 '401 Dreambox web authentication required'
132             );
133         } else {
134             errorOut(
135                 'Failed to fetch dreambox session token: ' . $php_errormsg,
136                 $code . ' ' . $message
137             );
138         }
139     }
140     $sx = simplexml_load_string($xml);
141     $token = (string) $sx;
142
143     $playUrl = $dreamboxUrl
144         . '/web/mediaplayerplay'
145         . '?file=4097:0:1:0:0:0:0:0:0:0:'
146         . str_replace('%3A', '%253A', rawurlencode($videoUrl));
147
148     $ctx = stream_context_create(
149         array(
150             'http' => array(
151                 'method'  => 'POST',
152                 'header'  => 'Content-type: application/x-www-form-urlencoded',
153                 'content' => 'sessionid=' . $token,
154                 //'ignore_errors' => true
155             )
156         )
157     );
158     $ret = file_get_contents($playUrl, false, $ctx);
159     if ($ret !== false) {
160         if (php_sapi_name() != 'cli') {
161             header('HTTP/1.0 200 OK');
162         }
163         echo "Video play request sent to dreambox\n";
164         exit(0);
165     } else {
166         errorOut(
167             'Failed to send video play request to dreambox: ' . $php_errormsg
168         );
169     }
170 }
171
172 function errorHandlerStore($number, $message, $file, $line)
173 {
174     $GLOBALS['lastError'] = $message;
175     return false;
176 }
177 $GLOBALS['lastError'] = null;
178 ?>