function getPageUrl()
{
global $argv, $argc;
+
+ $dryRun = false;
if (php_sapi_name() == 'cli') {
if ($argc < 2) {
- errorInput('No URL given as command line parameter');
+ errorInput(
+ "No URL given as command line parameter\n"
+ . "Usage:\n"
+ . " play.php [--dry-run|-n] <url>"
+ );
}
- $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']);
+ $options = [];
+ array_shift($argv);//remove script itself
+ foreach ($argv as $val) {
+ if ($val[0] == '-') {
+ $options[$val] = true;
+ } else {
+ $pageUrl = $val;
+ }
}
+ if (isset($options['--dry-run']) || isset($options['-n'])) {
+ $dryRun = true;
+ }
+ } 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);
+
+ $parts = parse_url($pageUrl ?? null);
if ($parts === false) {
errorInput('Invalid URL in POST data');
} else if (!isset($parts['scheme'])) {
} else if ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https') {
errorInput('Invalid URL in POST data: Non-HTTP scheme');
}
- return $pageUrl;
+ return [$pageUrl, $dryRun];
}
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 ($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)'
- );
- } 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;
+ }
+
+ 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)'
+ );
}
- $json = implode("\n", $output);
- return $json;
+ errorOut('youtube-dl error: ' . $lastLine);
}
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
+ || $format->vcodec == 'vp9'
+ ) {
+ //dreambox 7080hd does not play VP9 video streams
+ continue;
+ }
+ if (strtolower(substr($format->vcodec, 0, 6)) == 'avc1.6') {
+ //dreambox DM7080 does not play H.264 High Profile
+ 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) {
+ $a->acodec = $a->acodec ?? null;
+ $b->acodec = $b->acodec ?? null;
+ if ((($a->acodec != 'none') + ($b->acodec != 'none')) == 1) {
+ return ($b->acodec != 'none') - ($a->acodec != 'none');
+ }
+ return ($b->quality ?? 0) - ($a->quality ?? 0);
+ });
+ foreach ($safeFormats as $format) {
+ //echo $format->format . ' | ' . $format->vcodec . ' | ' . $format->acodec . "\n";
$url = $format->url;
+ break;
}
if ($url === null) {
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) {
+ if (!isset($http_response_header)) {
+ errorOut(
+ 'Error fetching dreambox web interface token: '
+ . $GLOBALS['lastError']
+ );
+ }
+
list($http, $code, $message) = explode(
' ', $http_response_header[0], 3
);
$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));
);
}
}
+
+function errorHandlerStore($number, $message, $file, $line)
+{
+ $GLOBALS['lastError'] = $message;
+ return false;
+}
+$GLOBALS['lastError'] = null;
?>