New remux feature (fixes #103)
This commit is contained in:
parent
b80b9c7b2e
commit
e6bbe54474
6 changed files with 169 additions and 16 deletions
|
@ -75,6 +75,13 @@ class Config
|
|||
*/
|
||||
public $stream = false;
|
||||
|
||||
/**
|
||||
* Allow to remux video + audio?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $remux = false;
|
||||
|
||||
/**
|
||||
* YAML config file path.
|
||||
*
|
||||
|
|
|
@ -119,15 +119,19 @@ class VideoDownload
|
|||
/**
|
||||
* Get URL of video from URL of page.
|
||||
*
|
||||
* It generally returns only one URL.
|
||||
* But it can return two URLs when multiple formats are specified
|
||||
* (eg. bestvideo+bestaudio).
|
||||
*
|
||||
* @param string $url URL of page
|
||||
* @param string $format Format to use for the video
|
||||
* @param string $password Video password
|
||||
*
|
||||
* @return string URL of video
|
||||
* @return array URLs of video
|
||||
* */
|
||||
public function getURL($url, $format = null, $password = null)
|
||||
{
|
||||
return $this->getProp($url, $format, 'get-url', $password);
|
||||
return explode(PHP_EOL, $this->getProp($url, $format, 'get-url', $password));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,6 +148,28 @@ class VideoDownload
|
|||
return trim($this->getProp($url, $format, 'get-filename', $password));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename of video with the specified extension
|
||||
*
|
||||
* @param string $extension New file extension
|
||||
* @param string $url URL of page
|
||||
* @param string $format Format to use for the video
|
||||
* @param string $password Video password
|
||||
*
|
||||
* @return string Filename of extracted video with specified extension
|
||||
*/
|
||||
public function getFileNameWithExtension($extension, $url, $format = null, $password = null)
|
||||
{
|
||||
return html_entity_decode(
|
||||
pathinfo(
|
||||
$this->getFilename($url, $format, $password),
|
||||
PATHINFO_FILENAME
|
||||
).'.'.$extension,
|
||||
ENT_COMPAT,
|
||||
'ISO-8859-1'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filename of audio from URL of page.
|
||||
*
|
||||
|
@ -155,14 +181,7 @@ class VideoDownload
|
|||
* */
|
||||
public function getAudioFilename($url, $format = null, $password = null)
|
||||
{
|
||||
return html_entity_decode(
|
||||
pathinfo(
|
||||
$this->getFilename($url, $format, $password),
|
||||
PATHINFO_FILENAME
|
||||
).'.mp3',
|
||||
ENT_COMPAT,
|
||||
'ISO-8859-1'
|
||||
);
|
||||
return $this->getFileNameWithExtension('mp3', $url, $format, $password);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,6 +326,31 @@ class VideoDownload
|
|||
return popen($procBuilder->getProcess()->getCommandLine(), 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an avconv stream to remux audio and video.
|
||||
*
|
||||
* @param array $urls URLs of the video ($urls[0]) and audio ($urls[1]) files
|
||||
*
|
||||
* @return resource popen stream
|
||||
*/
|
||||
public function getRemuxStream(array $urls)
|
||||
{
|
||||
$procBuilder = ProcessBuilder::create(
|
||||
[
|
||||
$this->config->avconv,
|
||||
'-v', 'quiet',
|
||||
'-i', $urls[0],
|
||||
'-i', $urls[1],
|
||||
'-c', 'copy',
|
||||
'-map', '0:v:0 ',
|
||||
'-map', '1:a:0',
|
||||
'-f', 'matroska',
|
||||
'pipe:1',
|
||||
]
|
||||
);
|
||||
return popen($procBuilder->getProcess()->getCommandLine(), 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get video stream from an RTMP video.
|
||||
*
|
||||
|
|
|
@ -177,9 +177,9 @@ class FrontController
|
|||
if ($this->config->stream) {
|
||||
return $this->getStream($params['url'], 'mp3', $response, $request, $password);
|
||||
} else {
|
||||
$url = $this->download->getURL($params['url'], 'mp3[protocol^=http]', $password);
|
||||
$urls = $this->download->getURL($params['url'], 'mp3[protocol^=http]', $password);
|
||||
|
||||
return $response->withRedirect($url);
|
||||
return $response->withRedirect($urls[0]);
|
||||
}
|
||||
} catch (PasswordException $e) {
|
||||
return $this->password($request, $response);
|
||||
|
@ -234,6 +234,7 @@ class FrontController
|
|||
'config' => $this->config,
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'uglyUrls' => $this->config->uglyUrls,
|
||||
'remux' => $this->config->remux,
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -358,13 +359,33 @@ class FrontController
|
|||
$this->sessionSegment->getFlash($params['url'])
|
||||
);
|
||||
} else {
|
||||
$url = $this->download->getURL(
|
||||
$urls = $this->download->getURL(
|
||||
$params['url'],
|
||||
$format,
|
||||
$this->sessionSegment->getFlash($params['url'])
|
||||
);
|
||||
if (count($urls) > 1) {
|
||||
if (!$this->config->remux) {
|
||||
throw new \Exception('You need to enable remux mode to merge two formats.');
|
||||
}
|
||||
$stream = $this->download->getRemuxStream($urls);
|
||||
$response = $response->withHeader('Content-Type', 'video/x-matroska');
|
||||
if ($request->isGet()) {
|
||||
$response = $response->withBody(new Stream($stream));
|
||||
}
|
||||
|
||||
return $response->withRedirect($url);
|
||||
return $response->withHeader('Content-Disposition', 'attachment; filename="'.pathinfo(
|
||||
$this->download->getFileNameWithExtension(
|
||||
'mkv',
|
||||
$params['url'],
|
||||
$format,
|
||||
$this->sessionSegment->getFlash($params['url'])
|
||||
),
|
||||
PATHINFO_FILENAME
|
||||
).'.mkv"');
|
||||
} else {
|
||||
return $response->withRedirect($urls[0]);
|
||||
}
|
||||
}
|
||||
} catch (PasswordException $e) {
|
||||
return $response->withRedirect(
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
Best ({$video->ext})
|
||||
{/strip}
|
||||
</option>
|
||||
{if $remux}
|
||||
<option value="bestvideo+bestaudio">
|
||||
Remux best video with best audio
|
||||
</option>
|
||||
{/if}
|
||||
<option value="worst{$protocol}">
|
||||
Worst
|
||||
</option>
|
||||
|
|
|
@ -361,6 +361,45 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertTrue($result->isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the redirect() function with a remuxed video.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRedirectWithRemux()
|
||||
{
|
||||
$controller = new FrontController($this->container, new Config(['remux'=>true]));
|
||||
$result = $controller->redirect(
|
||||
$this->request->withQueryParams(
|
||||
[
|
||||
'url'=>'https://www.youtube.com/watch?v=M7IpKCZ47pU',
|
||||
'format'=>'bestvideo+bestaudio'
|
||||
]
|
||||
),
|
||||
$this->response
|
||||
);
|
||||
$this->assertTrue($result->isOk());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the redirect() function with a remuxed video but remux disabled.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRedirectWithRemuxDisabled()
|
||||
{
|
||||
$result = $this->controller->redirect(
|
||||
$this->request->withQueryParams(
|
||||
[
|
||||
'url'=>'https://www.youtube.com/watch?v=M7IpKCZ47pU',
|
||||
'format'=>'bestvideo+bestaudio'
|
||||
]
|
||||
),
|
||||
$this->response
|
||||
);
|
||||
$this->assertTrue($result->isServerError());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the redirect() function with a missing password.
|
||||
*
|
||||
|
|
|
@ -88,7 +88,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
public function testGetURL($url, $format, $filename, $extension, $domain)
|
||||
{
|
||||
$videoURL = $this->download->getURL($url, $format);
|
||||
$this->assertContains($domain, $videoURL);
|
||||
$this->assertContains($domain, $videoURL[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,7 +98,8 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
public function testGetURLWithPassword()
|
||||
{
|
||||
$this->assertContains('vimeocdn.com', $this->download->getURL('http://vimeo.com/68375962', null, 'youtube-dl'));
|
||||
$videoURL = $this->download->getURL('http://vimeo.com/68375962', null, 'youtube-dl');
|
||||
$this->assertContains('vimeocdn.com', $videoURL[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -184,6 +185,23 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function remuxUrlProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'bestvideo+bestaudio',
|
||||
"It's Not Me, It's You - Hearts Under Fire-M7IpKCZ47pU",
|
||||
'mp4',
|
||||
'googlevideo.com',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides URLs for remux tests.
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function m3uUrlProvider()
|
||||
{
|
||||
return [
|
||||
|
@ -390,6 +408,25 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertFalse(feof($stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getRemuxStream function.
|
||||
*
|
||||
* @param string $url URL
|
||||
* @param string $format Format
|
||||
*
|
||||
* @return void
|
||||
* @dataProvider remuxUrlProvider
|
||||
*/
|
||||
public function testGetRemuxStream($url, $format)
|
||||
{
|
||||
$urls = $this->download->getURL($url, $format);
|
||||
if (count($urls) > 1) {
|
||||
$stream = $this->download->getRemuxStream($urls);
|
||||
$this->assertInternalType('resource', $stream);
|
||||
$this->assertFalse(feof($stream));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getRtmpStream function.
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue