Merge branch 'develop' into feature/stream

Conflicts:
	controllers/FrontController.php
	index.php
This commit is contained in:
Pierre Rudloff 2016-04-08 21:11:43 +02:00
commit 07b0ec9a99
6 changed files with 109 additions and 79 deletions

View file

@ -31,7 +31,7 @@ class Config
public $youtubedl = 'vendor/rg3/youtube-dl/youtube_dl/__main__.py'; public $youtubedl = 'vendor/rg3/youtube-dl/youtube_dl/__main__.py';
public $python = '/usr/bin/python'; public $python = '/usr/bin/python';
public $params = '--no-playlist --no-warnings -f best'; public $params = array('--no-playlist', '--no-warnings', '-f best');
public $convert = false; public $convert = false;
public $avconv = 'vendor/bin/ffmpeg'; public $avconv = 'vendor/bin/ffmpeg';
public $curl_params = ''; public $curl_params = '';

View file

@ -13,6 +13,7 @@
namespace Alltube; namespace Alltube;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessBuilder;
/** /**
* Main class * Main class
@ -27,19 +28,31 @@ use Symfony\Component\Process\Process;
* */ * */
class VideoDownload class VideoDownload
{ {
public function __construct()
{
$this->config = Config::getInstance();
$this->procBuilder = new ProcessBuilder();
$this->procBuilder->setPrefix(
array_merge(
array($this->config->python, $this->config->youtubedl),
$this->config->params
)
);
}
/** /**
* Get the user agent used youtube-dl * Get the user agent used youtube-dl
* *
* @return string UA * @return string UA
* */ * */
public static function getUA() public function getUA()
{ {
$config = Config::getInstance(); $this->procBuilder->setArguments(
$cmd = escapeshellcmd( array(
$config->python.' '.escapeshellarg($config->youtubedl). '--dump-user-agent'
' '.$config->params )
); );
$process = new Process($cmd.' --dump-user-agent'); $process = $this->procBuilder->getProcess();
$process->run(); $process->run();
return trim($process->getOutput()); return trim($process->getOutput());
} }
@ -49,14 +62,14 @@ class VideoDownload
* *
* @return array Extractors * @return array Extractors
* */ * */
public static function listExtractors() public function listExtractors()
{ {
$config = Config::getInstance(); $this->procBuilder->setArguments(
$cmd = escapeshellcmd( array(
$config->python.' '.escapeshellarg($config->youtubedl). '--list-extractors'
' '.$config->params )
); );
$process = new Process($cmd.' --list-extractors'); $process = $this->procBuilder->getProcess();
$process->run(); $process->run();
return explode(PHP_EOL, $process->getOutput()); return explode(PHP_EOL, $process->getOutput());
} }
@ -69,18 +82,18 @@ class VideoDownload
* *
* @return string Filename * @return string Filename
* */ * */
public static function getFilename($url, $format = null) public function getFilename($url, $format = null)
{ {
$config = Config::getInstance(); $this->procBuilder->setArguments(
$cmd = escapeshellcmd( array(
$config->python.' '.escapeshellarg($config->youtubedl). '--get-filename',
' '.$config->params $url
)
); );
if (isset($format)) { if (isset($format)) {
$cmd .= ' -f '.escapeshellarg($format); $this->procBuilder->add('-f '.$format);
} }
$cmd .=' --get-filename '.escapeshellarg($url)." 2>&1"; $process = $this->procBuilder->getProcess();
$process = new Process($cmd);
$process->run(); $process->run();
return trim($process->getOutput()); return trim($process->getOutput());
} }
@ -91,23 +104,23 @@ class VideoDownload
* @param string $url URL of page * @param string $url URL of page
* @param string $format Format to use for the video * @param string $format Format to use for the video
* *
* @return string JSON * @return object Decoded JSON
* */ * */
public static function getJSON($url, $format = null) public function getJSON($url, $format = null)
{ {
$config = Config::getInstance(); $this->procBuilder->setArguments(
$cmd = escapeshellcmd( array(
$config->python.' '.escapeshellarg($config->youtubedl). '--dump-json',
' '.$config->params $url
)
); );
if (isset($format)) { if (isset($format)) {
$cmd .= ' -f '.escapeshellarg($format); $this->procBuilder->add('-f '.$format);
} }
$cmd .=' --dump-json '.escapeshellarg($url)." 2>&1"; $process = $this->procBuilder->getProcess();
$process = new Process($cmd);
$process->run(); $process->run();
if (!$process->isSuccessful()) { if (!$process->isSuccessful()) {
throw new \Exception($process->getOutput()); throw new \Exception($process->getErrorOutput());
} else { } else {
return json_decode($process->getOutput()); return json_decode($process->getOutput());
} }
@ -121,23 +134,23 @@ class VideoDownload
* *
* @return string URL of video * @return string URL of video
* */ * */
public static function getURL($url, $format = null) public function getURL($url, $format = null)
{ {
$config = Config::getInstance(); $this->procBuilder->setArguments(
$cmd = escapeshellcmd( array(
$config->python.' '.escapeshellarg($config->youtubedl). '--get-url',
' '.$config->params $url
)
); );
if (isset($format)) { if (isset($format)) {
$cmd .= ' -f '.escapeshellarg($format); $this->procBuilder->add('-f '.$format);
} }
$cmd .=' -g '.escapeshellarg($url)." 2>&1"; $process = $this->procBuilder->getProcess();
$process = new Process($cmd);
$process->run(); $process->run();
if (!$process->isSuccessful()) { if (!$process->isSuccessful()) {
throw new \Exception($process->getOutput()); throw new \Exception($process->getErrorOutput());
} else { } else {
return array('success'=>true, 'url'=>$process->getOutput()); return $process->getOutput();
} }
} }

View file

@ -1,6 +1,9 @@
youtubedl: vendor/rg3/youtube-dl/youtube_dl/__main__.py youtubedl: vendor/rg3/youtube-dl/youtube_dl/__main__.py
python: /usr/bin/python python: /usr/bin/python
params: --no-playlist --no-warnings -f best params:
- --no-playlist
- --no-warnings
- -f best
curl_params: curl_params:
convert: false convert: false
avconv: vendor/bin/ffmpeg avconv: vendor/bin/ffmpeg

View file

@ -28,6 +28,11 @@ use Alltube\Config;
* */ * */
class FrontController class FrontController
{ {
public function __construct()
{
$this->config = Config::getInstance();
$this->download = new VideoDownload();
}
/** /**
* Display index page * Display index page
@ -37,10 +42,9 @@ class FrontController
* *
* @return void * @return void
*/ */
public static function index($request, $response) public function index($request, $response)
{ {
global $container; global $container;
$config = Config::getInstance();
$container->view->render( $container->view->render(
$response, $response,
'head.tpl', 'head.tpl',
@ -56,7 +60,7 @@ class FrontController
$response, $response,
'index.tpl', 'index.tpl',
array( array(
'convert'=>$config->convert 'convert'=>$this->config->convert
) )
); );
$container->view->render($response, 'footer.tpl'); $container->view->render($response, 'footer.tpl');
@ -70,7 +74,7 @@ class FrontController
* *
* @return void * @return void
*/ */
public static function extractors($request, $response) public function extractors($request, $response)
{ {
global $container; global $container;
$container->view->render( $container->view->render(
@ -86,7 +90,7 @@ class FrontController
$response, $response,
'extractors.tpl', 'extractors.tpl',
array( array(
'extractors'=>VideoDownload::listExtractors() 'extractors'=>$this->download->listExtractors()
) )
); );
$container->view->render($response, 'footer.tpl'); $container->view->render($response, 'footer.tpl');
@ -100,18 +104,18 @@ class FrontController
* *
* @return void * @return void
*/ */
public static function video($request, $response) public function video($request, $response)
{ {
global $container; global $container;
$params = $request->getQueryParams(); $params = $request->getQueryParams();
$config = Config::getInstance(); $this->config = Config::getInstance();
if (isset($params["url"])) { if (isset($params["url"])) {
if (isset($params['audio'])) { if (isset($params['audio'])) {
try { try {
$video = VideoDownload::getJSON($params["url"]); $video = $this->download->getJSON($params["url"]);
//Vimeo needs a correct user-agent //Vimeo needs a correct user-agent
$UA = VideoDownload::getUA(); $UA = $this->download->getUA();
ini_set( ini_set(
'user_agent', 'user_agent',
$UA $UA
@ -123,7 +127,7 @@ class FrontController
'Content-Disposition: attachment; filename="'. 'Content-Disposition: attachment; filename="'.
html_entity_decode( html_entity_decode(
pathinfo( pathinfo(
VideoDownload::getFilename( $this->download->getFilename(
$video->webpage_url $video->webpage_url
), ),
PATHINFO_FILENAME PATHINFO_FILENAME
@ -135,7 +139,7 @@ class FrontController
header("Content-Type: audio/mpeg"); header("Content-Type: audio/mpeg");
passthru( passthru(
'/usr/bin/rtmpdump -q -r '.escapeshellarg($video->url). '/usr/bin/rtmpdump -q -r '.escapeshellarg($video->url).
' | '.$config->avconv. ' | '.$this->config->avconv.
' -v quiet -i - -f mp3 -vn pipe:1' ' -v quiet -i - -f mp3 -vn pipe:1'
); );
exit; exit;
@ -145,7 +149,7 @@ class FrontController
'Content-Disposition: attachment; filename="'. 'Content-Disposition: attachment; filename="'.
html_entity_decode( html_entity_decode(
pathinfo( pathinfo(
VideoDownload::getFilename( $this->download->getFilename(
$video->webpage_url $video->webpage_url
), ),
PATHINFO_FILENAME PATHINFO_FILENAME
@ -156,10 +160,10 @@ class FrontController
); );
header("Content-Type: audio/mpeg"); header("Content-Type: audio/mpeg");
passthru( passthru(
'curl '.$config->curl_params. 'curl '.$this->config->curl_params.
' --user-agent '.escapeshellarg($UA). ' --user-agent '.escapeshellarg($UA).
' '.escapeshellarg($video->url). ' '.escapeshellarg($video->url).
' | '.$config->avconv. ' | '.$this->config->avconv.
' -v quiet -i - -f mp3 -vn pipe:1' ' -v quiet -i - -f mp3 -vn pipe:1'
); );
exit; exit;
@ -169,7 +173,7 @@ class FrontController
} }
} else { } else {
try { try {
$video = VideoDownload::getJSON($params["url"]); $video = $this->download->getJSON($params["url"]);
$container->view->render( $container->view->render(
$response, $response,
'head.tpl', 'head.tpl',
@ -217,14 +221,14 @@ class FrontController
* *
* @return void * @return void
*/ */
public static function redirect($request, $response) public function redirect($request, $response)
{ {
global $app; global $app;
$params = $request->getQueryParams(); $params = $request->getQueryParams();
if (isset($params["url"])) { if (isset($params["url"])) {
try { try {
$format = isset($params["format"]) ? $params["format"] : 'best'; $format = isset($params["format"]) ? $params["format"] : 'best';
$video = VideoDownload::getJSON($params["url"], $format); $video = $this->download->getJSON($params["url"], $format);
$client = new \GuzzleHttp\Client(); $client = new \GuzzleHttp\Client();
$stream = $client->request('GET', $video->url, array('stream'=>true)); $stream = $client->request('GET', $video->url, array('stream'=>true));
$response = $response->withHeader('Content-Disposition', 'inline; filename="'.$video->_filename.'"'); $response = $response->withHeader('Content-Disposition', 'inline; filename="'.$video->_filename.'"');
@ -249,13 +253,13 @@ class FrontController
* *
* @return void * @return void
*/ */
public static function json($request, $response) public function json($request, $response)
{ {
global $app; global $app;
$params = $request->getQueryParams(); $params = $request->getQueryParams();
if (isset($params["url"])) { if (isset($params["url"])) {
try { try {
$video = VideoDownload::getJSON($params["url"]); $video = $this->download->getJSON($params["url"]);
return $response->withJson($video); return $response->withJson($video);
} catch (\Exception $e) { } catch (\Exception $e) {
return $response->withJson( return $response->withJson(

View file

@ -15,6 +15,7 @@
require_once __DIR__.'/vendor/autoload.php'; require_once __DIR__.'/vendor/autoload.php';
require_once __DIR__.'/vendor/rudloff/smarty-plugin-noscheme/modifier.noscheme.php'; require_once __DIR__.'/vendor/rudloff/smarty-plugin-noscheme/modifier.noscheme.php';
use Alltube\VideoDownload; use Alltube\VideoDownload;
use Alltube\Controller\FrontController;
$app = new \Slim\App(); $app = new \Slim\App();
$container = $app->getContainer(); $container = $app->getContainer();
@ -28,24 +29,26 @@ $container['view'] = function ($c) {
return $view; return $view;
}; };
$controller = new FrontController();
$app->get( $app->get(
'/', '/',
array('Alltube\Controller\FrontController', 'index') array($controller, 'index')
); );
$app->get( $app->get(
'/extractors', '/extractors',
array('Alltube\Controller\FrontController', 'extractors') array($controller, 'extractors')
)->setName('extractors'); )->setName('extractors');
$app->get( $app->get(
'/video', '/video',
array('Alltube\Controller\FrontController', 'video') array($controller, 'video')
)->setName('video'); )->setName('video');
$app->get( $app->get(
'/redirect', '/redirect',
array('Alltube\Controller\FrontController', 'redirect') array($controller, 'redirect')
)->setName('redirect'); )->setName('redirect');
$app->get( $app->get(
'/json', '/json',
array('Alltube\Controller\FrontController', 'json') array($controller, 'json')
); );
$app->run(); $app->run();

View file

@ -27,6 +27,11 @@ use Alltube\VideoDownload;
* */ * */
class VideoDownloadTest extends \PHPUnit_Framework_TestCase class VideoDownloadTest extends \PHPUnit_Framework_TestCase
{ {
protected function setUp()
{
$this->download = new VideoDownload();
}
/** /**
* Test getUA function * Test getUA function
* *
@ -34,7 +39,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetUA() public function testGetUA()
{ {
$this->assertStringStartsWith('Mozilla/', VideoDownload::getUA()); $this->assertStringStartsWith('Mozilla/', $this->download->getUA());
} }
/** /**
@ -44,7 +49,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testListExtractors() public function testListExtractors()
{ {
$extractors = VideoDownload::listExtractors(); $extractors = $this->download->listExtractors();
$this->assertContains('youtube', $extractors); $this->assertContains('youtube', $extractors);
} }
@ -57,11 +62,10 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
* @return void * @return void
* @dataProvider urlProvider * @dataProvider urlProvider
*/ */
public function testGetURL($url, $format) public function testGetURL($url, $format, $filename, $domain)
{ {
$videoURL = VideoDownload::getURL($url, $format); $videoURL = $this->download->getURL($url, $format);
$this->assertArrayHasKey('success', $videoURL); $this->assertContains($domain, $videoURL);
$this->assertArrayHasKey('url', $videoURL);
} }
/** /**
@ -75,7 +79,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetURLError($url) public function testGetURLError($url)
{ {
$videoURL = VideoDownload::getURL($url); $this->download->getURL($url);
} }
/** /**
@ -88,16 +92,19 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
return array( return array(
array( array(
'https://www.youtube.com/watch?v=M7IpKCZ47pU', null, 'https://www.youtube.com/watch?v=M7IpKCZ47pU', null,
"It's Not Me, It's You - Hearts Under Fire-M7IpKCZ47pU.mp4" "It's Not Me, It's You - Hearts Under Fire-M7IpKCZ47pU.mp4",
'googlevideo.com'
), ),
array( array(
'https://www.youtube.com/watch?v=RJJ6FCAXvKg', 22, 'https://www.youtube.com/watch?v=RJJ6FCAXvKg', 22,
"'Heart Attack' - Demi Lovato ". "'Heart Attack' - Demi Lovato ".
"(Sam Tsui & Against The Current)-RJJ6FCAXvKg.mp4" "(Sam Tsui & Against The Current)-RJJ6FCAXvKg.mp4",
'googlevideo.com'
), ),
array( array(
'https://vimeo.com/24195442', null, 'https://vimeo.com/24195442', null,
"Carving the Mountains-24195442.mp4" "Carving the Mountains-24195442.mp4",
'vimeocdn.com'
), ),
); );
} }
@ -126,7 +133,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetFilename($url, $format, $result) public function testGetFilename($url, $format, $result)
{ {
$filename = VideoDownload::getFilename($url, $format); $filename = $this->download->getFilename($url, $format);
$this->assertEquals($filename, $result); $this->assertEquals($filename, $result);
} }
@ -141,7 +148,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetJSON($url, $format) public function testGetJSON($url, $format)
{ {
$info = VideoDownload::getJSON($url, $format); $info = $this->download->getJSON($url, $format);
$this->assertObjectHasAttribute('webpage_url', $info); $this->assertObjectHasAttribute('webpage_url', $info);
$this->assertObjectHasAttribute('url', $info); $this->assertObjectHasAttribute('url', $info);
$this->assertObjectHasAttribute('ext', $info); $this->assertObjectHasAttribute('ext', $info);
@ -161,6 +168,6 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
public function testGetJSONError($url) public function testGetJSONError($url)
{ {
$videoURL = VideoDownload::getJSON($url); $videoURL = $this->download->getJSON($url);
} }
} }