diff --git a/classes/Config.php b/classes/Config.php
index c57c848..14c42c0 100644
--- a/classes/Config.php
+++ b/classes/Config.php
@@ -38,7 +38,12 @@ class Config
*
* @var array
*/
- public $params = ['--no-playlist', '--no-warnings', '-f best[protocol^=http]', '--playlist-end', 1];
+ public $params = [
+ '--no-playlist', '--no-warnings',
+ //We can allow non-HTTP URLs on the feature/stream branch
+ '-f best',
+ '--playlist-end', 1
+ ];
/**
* Enable audio conversion.
diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php
index 2284840..18de6d5 100644
--- a/classes/VideoDownload.php
+++ b/classes/VideoDownload.php
@@ -292,4 +292,28 @@ class VideoDownload
return popen($chain->getProcess()->getCommandLine(), 'r');
}
+
+ public function getM3uStream(\stdClass $video)
+ {
+ if (!shell_exec('which '.$this->config->avconv)) {
+ throw(new \Exception('Can\'t find avconv or ffmpeg'));
+ }
+
+ $procBuilder = ProcessBuilder::create(
+ [
+ $this->config->avconv,
+ '-v', 'quiet',
+ '-i', $video->url,
+ '-f', $video->ext,
+ '-c', 'copy',
+ '-bsf:a', 'aac_adtstoasc',
+ '-movflags', 'frag_keyframe+empty_moov',
+ 'pipe:1',
+ ]
+ );
+
+ //dump($procBuilder->getProcess()->getCommandLine()); die;
+
+ return popen($procBuilder->getProcess()->getCommandLine(), 'r');
+ }
}
diff --git a/controllers/FrontController.php b/controllers/FrontController.php
index 19c8342..5f7ef09 100644
--- a/controllers/FrontController.php
+++ b/controllers/FrontController.php
@@ -153,7 +153,7 @@ class FrontController
}
if (isset($params['audio'])) {
try {
- return $this->getStream($params['url'], 'mp3[protocol^=http]', $response, $request, $password);
+ return $this->getStream($params['url'], 'mp3', $response, $request, $password);
} catch (PasswordException $e) {
return $this->password($request, $response);
} catch (\Exception $e) {
@@ -223,14 +223,22 @@ class FrontController
$format = 'best';
}
$video = $this->download->getJSON($url, $format, $password);
- $client = new \GuzzleHttp\Client();
- $stream = $client->request('GET', $video->url, ['stream' => true]);
- $response = $response->withHeader('Content-Disposition', 'attachment; filename="'.$video->_filename.'"');
- $response = $response->withHeader('Content-Type', $stream->getHeader('Content-Type'));
- $response = $response->withHeader('Content-Length', $stream->getHeader('Content-Length'));
- if ($request->isGet()) {
- $response = $response->withBody($stream->getBody());
+ if ($video->protocol == 'm3u8') {
+ $stream = $this->download->getM3uStream($video);
+ $response = $response->withHeader('Content-Type', 'video/'.$video->ext);
+ if ($request->isGet()) {
+ $response = $response->withBody(new Stream($stream));
+ }
+ } else {
+ $client = new \GuzzleHttp\Client();
+ $stream = $client->request('GET', $video->url, ['stream' => true]);
+ $response = $response->withHeader('Content-Type', $stream->getHeader('Content-Type'));
+ $response = $response->withHeader('Content-Length', $stream->getHeader('Content-Length'));
+ if ($request->isGet()) {
+ $response = $response->withBody($stream->getBody());
+ }
}
+ $response = $response->withHeader('Content-Disposition', 'attachment; filename="'.$video->_filename.'"');
return $response;
}
diff --git a/templates/video.tpl b/templates/video.tpl
index 6f11251..5ff0f96 100644
--- a/templates/video.tpl
+++ b/templates/video.tpl
@@ -26,18 +26,17 @@
{else}
-
+
Download
{/if}
diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php
index c1053bd..bd5ebe7 100644
--- a/tests/VideoDownloadTest.php
+++ b/tests/VideoDownloadTest.php
@@ -176,6 +176,13 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
'edgefcs.net',
'GRIP sucht den Sommerkönig-folge-203-0.mp3',
],
+ [
+ //Only works on the feature/stream branch
+ 'https://twitter.com/verge/status/813055465324056576/video/1', null,
+ 'The Verge - This tiny origami robot can self-fold and complete tasks-813055465324056576.mp4',
+ 'video.twimg.com',
+ 'The Verge - This tiny origami robot can self-fold and complete tasks-813055465324056576.mp3',
+ ]
];
}