From 11e8243443adaa52cbcbab5373733e52c2ad4529 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 8 Apr 2016 19:06:41 +0200 Subject: [PATCH 1/3] Don't use static functions --- classes/VideoDownload.php | 40 +++++++++++++++---------------- controllers/FrontController.php | 42 ++++++++++++++++++--------------- index.php | 15 +++++++----- tests/VideoDownloadTest.php | 19 +++++++++------ 4 files changed, 64 insertions(+), 52 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index ea0ca2c..7c0588c 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -27,17 +27,21 @@ use Symfony\Component\Process\Process; * */ class VideoDownload { + public function __construct() + { + $this->config = Config::getInstance(); + } + /** * Get the user agent used youtube-dl * * @return string UA * */ - public static function getUA() + public function getUA() { - $config = Config::getInstance(); $cmd = escapeshellcmd( - $config->python.' '.escapeshellarg($config->youtubedl). - ' '.$config->params + $this->config->python.' '.escapeshellarg($this->config->youtubedl). + ' '.$this->config->params ); $process = new Process($cmd.' --dump-user-agent'); $process->run(); @@ -49,12 +53,11 @@ class VideoDownload * * @return array Extractors * */ - public static function listExtractors() + public function listExtractors() { - $config = Config::getInstance(); $cmd = escapeshellcmd( - $config->python.' '.escapeshellarg($config->youtubedl). - ' '.$config->params + $this->config->python.' '.escapeshellarg($this->config->youtubedl). + ' '.$this->config->params ); $process = new Process($cmd.' --list-extractors'); $process->run(); @@ -69,12 +72,11 @@ class VideoDownload * * @return string Filename * */ - public static function getFilename($url, $format = null) + public function getFilename($url, $format = null) { - $config = Config::getInstance(); $cmd = escapeshellcmd( - $config->python.' '.escapeshellarg($config->youtubedl). - ' '.$config->params + $this->config->python.' '.escapeshellarg($this->config->youtubedl). + ' '.$this->config->params ); if (isset($format)) { $cmd .= ' -f '.escapeshellarg($format); @@ -93,12 +95,11 @@ class VideoDownload * * @return string JSON * */ - public static function getJSON($url, $format = null) + public function getJSON($url, $format = null) { - $config = Config::getInstance(); $cmd = escapeshellcmd( - $config->python.' '.escapeshellarg($config->youtubedl). - ' '.$config->params + $this->config->python.' '.escapeshellarg($this->config->youtubedl). + ' '.$this->config->params ); if (isset($format)) { $cmd .= ' -f '.escapeshellarg($format); @@ -121,12 +122,11 @@ class VideoDownload * * @return string URL of video * */ - public static function getURL($url, $format = null) + public function getURL($url, $format = null) { - $config = Config::getInstance(); $cmd = escapeshellcmd( - $config->python.' '.escapeshellarg($config->youtubedl). - ' '.$config->params + $this->config->python.' '.escapeshellarg($this->config->youtubedl). + ' '.$this->config->params ); if (isset($format)) { $cmd .= ' -f '.escapeshellarg($format); diff --git a/controllers/FrontController.php b/controllers/FrontController.php index 06f8188..0f5846a 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -28,6 +28,11 @@ use Alltube\Config; * */ class FrontController { + public function __construct() + { + $this->config = Config::getInstance(); + $this->download = new VideoDownload(); + } /** * Display index page @@ -37,10 +42,9 @@ class FrontController * * @return void */ - public static function index($request, $response) + public function index($request, $response) { global $container; - $config = Config::getInstance(); $container->view->render( $response, 'head.tpl', @@ -56,7 +60,7 @@ class FrontController $response, 'index.tpl', array( - 'convert'=>$config->convert + 'convert'=>$this->config->convert ) ); $container->view->render($response, 'footer.tpl'); @@ -70,7 +74,7 @@ class FrontController * * @return void */ - public static function extractors($request, $response) + public function extractors($request, $response) { global $container; $container->view->render( @@ -86,7 +90,7 @@ class FrontController $response, 'extractors.tpl', array( - 'extractors'=>VideoDownload::listExtractors() + 'extractors'=>$this->download->listExtractors() ) ); $container->view->render($response, 'footer.tpl'); @@ -100,17 +104,17 @@ class FrontController * * @return void */ - public static function video($request, $response) + public function video($request, $response) { global $container; - $config = Config::getInstance(); + $this->config = Config::getInstance(); if (isset($_GET["url"])) { if (isset($_GET['audio'])) { try { - $video = VideoDownload::getJSON($_GET["url"]); + $video = $this->download->getJSON($_GET["url"]); //Vimeo needs a correct user-agent - $UA = VideoDownload::getUA(); + $UA = $this->download->getUA(); ini_set( 'user_agent', $UA @@ -122,7 +126,7 @@ class FrontController 'Content-Disposition: attachment; filename="'. html_entity_decode( pathinfo( - VideoDownload::getFilename( + $this->download->getFilename( $video->webpage_url ), PATHINFO_FILENAME @@ -134,7 +138,7 @@ class FrontController header("Content-Type: audio/mpeg"); passthru( '/usr/bin/rtmpdump -q -r '.escapeshellarg($video->url). - ' | '.$config->avconv. + ' | '.$this->config->avconv. ' -v quiet -i - -f mp3 -vn pipe:1' ); exit; @@ -144,7 +148,7 @@ class FrontController 'Content-Disposition: attachment; filename="'. html_entity_decode( pathinfo( - VideoDownload::getFilename( + $this->download->getFilename( $video->webpage_url ), PATHINFO_FILENAME @@ -155,10 +159,10 @@ class FrontController ); header("Content-Type: audio/mpeg"); passthru( - 'curl '.$config->curl_params. + 'curl '.$this->config->curl_params. ' --user-agent '.escapeshellarg($UA). ' '.escapeshellarg($video->url). - ' | '.$config->avconv. + ' | '.$this->config->avconv. ' -v quiet -i - -f mp3 -vn pipe:1' ); exit; @@ -168,7 +172,7 @@ class FrontController } } else { try { - $video = VideoDownload::getJSON($_GET["url"]); + $video = $this->download->getJSON($_GET["url"]); $container->view->render( $response, 'head.tpl', @@ -216,12 +220,12 @@ class FrontController * * @return void */ - public static function redirect($request, $response) + public function redirect($request, $response) { global $app; if (isset($_GET["url"])) { try { - $video = VideoDownload::getURL($_GET["url"]); + $video = $this->download->getURL($_GET["url"]); return $response->withRedirect($video['url']); } catch (\Exception $e) { echo $e->getMessage().PHP_EOL; @@ -238,12 +242,12 @@ class FrontController * * @return void */ - public static function json($request, $response) + public function json($request, $response) { global $app; if (isset($_GET["url"])) { try { - $video = VideoDownload::getJSON($_GET["url"]); + $video = $this->download->getJSON($_GET["url"]); return $response->withJson($video); } catch (\Exception $e) { return $response->withJson( diff --git a/index.php b/index.php index 468a685..959e9d7 100644 --- a/index.php +++ b/index.php @@ -15,6 +15,7 @@ require_once __DIR__.'/vendor/autoload.php'; require_once __DIR__.'/vendor/rudloff/smarty-plugin-noscheme/modifier.noscheme.php'; use Alltube\VideoDownload; +use Alltube\Controller\FrontController; $app = new \Slim\App(); $container = $app->getContainer(); @@ -22,30 +23,32 @@ $container['view'] = function ($c) { $view = new \Slim\Views\Smarty(__DIR__.'/templates/'); $view->addSlimPlugins($c['router'], $c['request']->getUri()); - $view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme'); + $view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme'); return $view; }; +$controller = new FrontController(); + $app->get( '/', - array('Alltube\Controller\FrontController', 'index') + array($controller, 'index') ); $app->get( '/extractors', - array('Alltube\Controller\FrontController', 'extractors') + array($controller, 'extractors') )->setName('extractors'); $app->get( '/video', - array('Alltube\Controller\FrontController', 'video') + array($controller, 'video') )->setName('video'); $app->get( '/redirect', - array('Alltube\Controller\FrontController', 'redirect') + array($controller, 'redirect') ); $app->get( '/json', - array('Alltube\Controller\FrontController', 'json') + array($controller, 'json') ); $app->run(); diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php index 9f0c7b4..35b632d 100644 --- a/tests/VideoDownloadTest.php +++ b/tests/VideoDownloadTest.php @@ -27,6 +27,11 @@ use Alltube\VideoDownload; * */ class VideoDownloadTest extends \PHPUnit_Framework_TestCase { + protected function setUp() + { + $this->download = new VideoDownload(); + } + /** * Test getUA function * @@ -34,7 +39,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ 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() { - $extractors = VideoDownload::listExtractors(); + $extractors = $this->download->listExtractors(); $this->assertContains('youtube', $extractors); } @@ -59,7 +64,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetURL($url, $format) { - $videoURL = VideoDownload::getURL($url, $format); + $videoURL = $this->download->getURL($url, $format); $this->assertArrayHasKey('success', $videoURL); $this->assertArrayHasKey('url', $videoURL); } @@ -75,7 +80,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetURLError($url) { - $videoURL = VideoDownload::getURL($url); + $videoURL = $this->download->getURL($url); } /** @@ -126,7 +131,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetFilename($url, $format, $result) { - $filename = VideoDownload::getFilename($url, $format); + $filename = $this->download->getFilename($url, $format); $this->assertEquals($filename, $result); } @@ -141,7 +146,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetJSON($url, $format) { - $info = VideoDownload::getJSON($url, $format); + $info = $this->download->getJSON($url, $format); $this->assertObjectHasAttribute('webpage_url', $info); $this->assertObjectHasAttribute('url', $info); $this->assertObjectHasAttribute('ext', $info); @@ -161,6 +166,6 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetJSONError($url) { - $videoURL = VideoDownload::getJSON($url); + $videoURL = $this->download->getJSON($url); } } From f7f0a7b7f4dc0979f244244dd6e3198a9ed26505 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 8 Apr 2016 19:37:59 +0200 Subject: [PATCH 2/3] Use ProcessBuilder to build commands (fixes #51) --- classes/Config.php | 2 +- classes/VideoDownload.php | 69 +++++++++++++++++++++++---------------- config.example.yml | 5 ++- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/classes/Config.php b/classes/Config.php index 0c1aa8c..77cfa57 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -31,7 +31,7 @@ class Config public $youtubedl = 'vendor/rg3/youtube-dl/youtube_dl/__main__.py'; 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 $avconv = 'vendor/bin/ffmpeg'; public $curl_params = ''; diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 7c0588c..5803b9f 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -13,6 +13,7 @@ namespace Alltube; use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessBuilder; /** * Main class @@ -30,6 +31,13 @@ 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 + ) + ); } /** @@ -39,11 +47,12 @@ class VideoDownload * */ public function getUA() { - $cmd = escapeshellcmd( - $this->config->python.' '.escapeshellarg($this->config->youtubedl). - ' '.$this->config->params + $this->procBuilder->setArguments( + array( + '--dump-user-agent' + ) ); - $process = new Process($cmd.' --dump-user-agent'); + $process = $this->procBuilder->getProcess(); $process->run(); return trim($process->getOutput()); } @@ -55,11 +64,12 @@ class VideoDownload * */ public function listExtractors() { - $cmd = escapeshellcmd( - $this->config->python.' '.escapeshellarg($this->config->youtubedl). - ' '.$this->config->params + $this->procBuilder->setArguments( + array( + '--list-extractors' + ) ); - $process = new Process($cmd.' --list-extractors'); + $process = $this->procBuilder->getProcess(); $process->run(); return explode(PHP_EOL, $process->getOutput()); } @@ -74,15 +84,16 @@ class VideoDownload * */ public function getFilename($url, $format = null) { - $cmd = escapeshellcmd( - $this->config->python.' '.escapeshellarg($this->config->youtubedl). - ' '.$this->config->params + $this->procBuilder->setArguments( + array( + '--get-filename', + $url + ) ); if (isset($format)) { - $cmd .= ' -f '.escapeshellarg($format); + $this->procBuilder->add('-f '.$format); } - $cmd .=' --get-filename '.escapeshellarg($url)." 2>&1"; - $process = new Process($cmd); + $process = $this->procBuilder->getProcess(); $process->run(); return trim($process->getOutput()); } @@ -97,18 +108,19 @@ class VideoDownload * */ public function getJSON($url, $format = null) { - $cmd = escapeshellcmd( - $this->config->python.' '.escapeshellarg($this->config->youtubedl). - ' '.$this->config->params + $this->procBuilder->setArguments( + array( + '--dump-json', + $url + ) ); if (isset($format)) { - $cmd .= ' -f '.escapeshellarg($format); + $this->procBuilder->add('-f '.$format); } - $cmd .=' --dump-json '.escapeshellarg($url)." 2>&1"; - $process = new Process($cmd); + $process = $this->procBuilder->getProcess(); $process->run(); if (!$process->isSuccessful()) { - throw new \Exception($process->getOutput()); + throw new \Exception($process->getErrorOutput()); } else { return json_decode($process->getOutput()); } @@ -124,18 +136,19 @@ class VideoDownload * */ public function getURL($url, $format = null) { - $cmd = escapeshellcmd( - $this->config->python.' '.escapeshellarg($this->config->youtubedl). - ' '.$this->config->params + $this->procBuilder->setArguments( + array( + '--get-url', + $url + ) ); if (isset($format)) { - $cmd .= ' -f '.escapeshellarg($format); + $this->procBuilder->add('-f '.$format); } - $cmd .=' -g '.escapeshellarg($url)." 2>&1"; - $process = new Process($cmd); + $process = $this->procBuilder->getProcess(); $process->run(); if (!$process->isSuccessful()) { - throw new \Exception($process->getOutput()); + throw new \Exception($process->getErrorOutput()); } else { return array('success'=>true, 'url'=>$process->getOutput()); } diff --git a/config.example.yml b/config.example.yml index 0734d4d..a9b905e 100644 --- a/config.example.yml +++ b/config.example.yml @@ -1,6 +1,9 @@ youtubedl: vendor/rg3/youtube-dl/youtube_dl/__main__.py python: /usr/bin/python -params: --no-playlist --no-warnings -f best +params: + - --no-playlist + - --no-warnings + - -f best curl_params: convert: false avconv: vendor/bin/ffmpeg From f14bec35ea4ecdb7d0bc8e19a2fd5ded29701993 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 8 Apr 2016 20:08:04 +0200 Subject: [PATCH 3/3] getURL() should not return an array --- classes/VideoDownload.php | 4 ++-- controllers/FrontController.php | 4 ++-- tests/VideoDownloadTest.php | 16 +++++++++------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 5803b9f..8643207 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -104,7 +104,7 @@ class VideoDownload * @param string $url URL of page * @param string $format Format to use for the video * - * @return string JSON + * @return object Decoded JSON * */ public function getJSON($url, $format = null) { @@ -150,7 +150,7 @@ class VideoDownload if (!$process->isSuccessful()) { throw new \Exception($process->getErrorOutput()); } else { - return array('success'=>true, 'url'=>$process->getOutput()); + return $process->getOutput(); } } diff --git a/controllers/FrontController.php b/controllers/FrontController.php index 0f5846a..29778c4 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -225,8 +225,8 @@ class FrontController global $app; if (isset($_GET["url"])) { try { - $video = $this->download->getURL($_GET["url"]); - return $response->withRedirect($video['url']); + $url = $this->download->getURL($_GET["url"]); + return $response->withRedirect($url); } catch (\Exception $e) { echo $e->getMessage().PHP_EOL; return $response->withHeader('Content-Type', 'text/plain'); diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php index 35b632d..d137735 100644 --- a/tests/VideoDownloadTest.php +++ b/tests/VideoDownloadTest.php @@ -62,11 +62,10 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase * @return void * @dataProvider urlProvider */ - public function testGetURL($url, $format) + public function testGetURL($url, $format, $filename, $domain) { $videoURL = $this->download->getURL($url, $format); - $this->assertArrayHasKey('success', $videoURL); - $this->assertArrayHasKey('url', $videoURL); + $this->assertContains($domain, $videoURL); } /** @@ -80,7 +79,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetURLError($url) { - $videoURL = $this->download->getURL($url); + $this->download->getURL($url); } /** @@ -93,16 +92,19 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase return array( array( '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( 'https://www.youtube.com/watch?v=RJJ6FCAXvKg', 22, "'Heart Attack' - Demi Lovato ". - "(Sam Tsui & Against The Current)-RJJ6FCAXvKg.mp4" + "(Sam Tsui & Against The Current)-RJJ6FCAXvKg.mp4", + 'googlevideo.com' ), array( 'https://vimeo.com/24195442', null, - "Carving the Mountains-24195442.mp4" + "Carving the Mountains-24195442.mp4", + 'vimeocdn.com' ), ); }