Filter out VP9 streams, sort by quality
[playVideoOnDreamboxProxy.git] / www / functions.php
index 18cfaff288604064aba615ad9236a859a8cf8d4a..617724a6fe382e71505d70bef33f604246e1023a 100644 (file)
@@ -7,14 +7,21 @@ function getPageUrl()
             errorInput('No URL given as command line parameter');
         }
         $pageUrl = $argv[1];
-    } else {
-        if (!isset($_SERVER['CONTENT_TYPE'])) {
-            errorInput('Content type header missing');
-        } else if ($_SERVER['CONTENT_TYPE'] != 'text/plain') {
-            errorInput('Content type is not text/plain but ' . $_SERVER['CONTENT_TYPE']);
-        }
+    } else if (!isset($_SERVER['CONTENT_TYPE'])) {
+        errorInput('Content type header missing');
+    } else if ($_SERVER['CONTENT_TYPE'] == 'text/plain') {
+        //Android app
         $pageUrl = file_get_contents('php://input');
+    } else if ($_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded') {
+        //Web form
+        if (!isset($_POST['url'])) {
+            errorInput('"url" POST parameter missing');
+        }
+        $pageUrl = $_POST['url'];
+    } else {
+        errorInput('Content type is not text/plain but ' . $_SERVER['CONTENT_TYPE']);
     }
+
     $parts = parse_url($pageUrl);
     if ($parts === false) {
         errorInput('Invalid URL in POST data');
@@ -32,22 +39,47 @@ function getYoutubeDlJson($pageUrl, $youtubedlPath)
         . ' --no-playlist'//would otherwise cause multiple json blocks
         . ' --quiet'
         . ' --dump-json'
-        . ' ' . escapeshellarg($pageUrl)
-        . ' 2> /dev/null';
+        . ' ' . escapeshellarg($pageUrl);
 
-    $lastLine = exec($cmd, $output, $exitCode);
-    if ($exitCode !== 0) {
-        if (strpos($lastLine, 'Unsupported URL') !== false) {
-            errorOut(
-                'Unsupported URL  at ' . $pageUrl,
-                '406 Unsupported URL (No video found)'
-            );
-        } else {
-            errorOut('youtube-dl error: ' . $lastLine);
-        }
+    $descriptors = [
+        1 => ['pipe', 'w'],//stdout
+        2 => ['pipe', 'w'],//stderr
+    ];
+    $proc = proc_open($cmd, $descriptors, $pipes);
+    if ($proc === false) {
+        errorOut('Error running youtube-dl');
+    }
+    $stdout = stream_get_contents($pipes[1]);
+    $stderr = stream_get_contents($pipes[2]);
+
+    $exitCode = proc_close($proc);
+
+    if ($exitCode === 0) {
+        //stdout contains the JSON data
+        return $stdout;
     }
 
-    $json = implode("\n", $output);
+    if (strlen($stderr)) {
+        $lines = explode("\n", trim($stderr));
+        $lastLine = end($lines);
+    } else {
+        $lines = explode("\n", trim($stdout));
+        $lastLine = end($lines);
+    }
+
+    if ($exitCode === 127) {
+        errorOut(
+            'youtube-dl not found at ' . $youtubedlPath,
+            '500 youtube-dl not found'
+        );
+    } else if (strpos($lastLine, 'Unsupported URL') !== false) {
+        errorOut(
+            'Unsupported URL  at ' . $pageUrl,
+            '406 Unsupported URL (No video found)'
+        );
+    }
+
+    errorOut('youtube-dl error: ' . $lastLine);
 }
 
 function extractVideoUrlFromJson($json)
@@ -57,17 +89,36 @@ function extractVideoUrlFromJson($json)
         errorOut('Cannot decode JSON: ' . json_last_error_msg());
     }
 
-    $url = null;
+    $safeFormats = [];
     foreach ($data->formats as $format) {
         if (strpos($format->format, 'hls') !== false) {
             //dreambox 7080hd does not play hls files
             continue;
         }
+        if (strpos($format->format, 'vp9') !== false) {
+            //dreambox 7080hd does not play VP9 video streams
+            continue;
+        }
         if ($format->protocol == 'http_dash_segments') {
             //split up into multiple small files
             continue;
         }
+        if ($format->ext == 'flv') {
+            //Internal data flow error
+            continue;
+        }
+        $safeFormats[] = $format;
+    }
+
+    $url = null;
+
+    //filter: best quality
+    usort($safeFormats, function ($a, $b) {
+        return ($b->quality ?? 0) - ($a->quality ?? 0);
+    });
+    foreach ($safeFormats as $format) {
         $url = $format->url;
+        break;
     }
 
     if ($url === null) {
@@ -84,17 +135,38 @@ function extractVideoUrlFromJson($json)
     return $url;
 }
 
-function playVideoOnDreambox($videoUrl, $dreamboxHost)
+function playVideoOnDreambox($videoUrl, $dreamboxUrl)
 {
     ini_set('track_errors', 1);
-    $xml = @file_get_contents('http://' . $dreamboxHost . '/web/session');
+    $xml = @file_get_contents($dreamboxUrl . '/web/session');
     if ($xml === false) {
-        errorOut('Failed to fetch dreambox session token: ' . $php_errormsg);
+        if (!isset($http_response_header)) {
+            errorOut(
+                'Error fetching dreambox web interface token: '
+                . $GLOBALS['lastError']
+            );
+        }
+
+        list($http, $code, $message) = explode(
+            ' ', $http_response_header[0], 3
+        );
+        if ($code == 401) {
+            //dreambox web interface authentication has been enabled
+            errorOut(
+                'Error: Web interface authentication is required',
+                '401 Dreambox web authentication required'
+            );
+        } else {
+            errorOut(
+                'Failed to fetch dreambox session token: ' . $php_errormsg,
+                $code . ' ' . $message
+            );
+        }
     }
     $sx = simplexml_load_string($xml);
     $token = (string) $sx;
 
-    $playUrl = 'http://' . $dreamboxHost
+    $playUrl = $dreamboxUrl
         . '/web/mediaplayerplay'
         . '?file=4097:0:1:0:0:0:0:0:0:0:'
         . str_replace('%3A', '%253A', rawurlencode($videoUrl));
@@ -111,7 +183,9 @@ function playVideoOnDreambox($videoUrl, $dreamboxHost)
     );
     $ret = file_get_contents($playUrl, false, $ctx);
     if ($ret !== false) {
-        header('HTTP/1.0 200 OK');
+        if (php_sapi_name() != 'cli') {
+            header('HTTP/1.0 200 OK');
+        }
         echo "Video play request sent to dreambox\n";
         exit(0);
     } else {
@@ -120,4 +194,11 @@ function playVideoOnDreambox($videoUrl, $dreamboxHost)
         );
     }
 }
+
+function errorHandlerStore($number, $message, $file, $line)
+{
+    $GLOBALS['lastError'] = $message;
+    return false;
+}
+$GLOBALS['lastError'] = null;
 ?>