From b0cdbd41edcc007c3770aeec241b62972358f243 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 14 Oct 2016 19:01:51 +0200 Subject: [PATCH 01/46] Refactor code --- classes/VideoDownload.php | 123 ++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 52 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 188432d..3eed861 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -147,6 +147,75 @@ class VideoDownload ); } + /** + * Get a process that runs rtmp in order to download a video + * @param object $video Video object returned by youtube-dl + * @return \Symfony\Component\Process\Process Process + */ + private function getRtmpProcess($video) + { + if (!shell_exec('which '.$this->config->rtmpdump)) { + throw(new \Exception('Can\'t find rtmpdump')); + } + $builder = new ProcessBuilder( + [ + $this->config->rtmpdump, + '-q', + '-r', + $video->url, + '--pageUrl', $video->webpage_url, + ] + ); + if (isset($video->player_url)) { + $builder->add('--swfVfy'); + $builder->add($video->player_url); + } + if (isset($video->flash_version)) { + $builder->add('--flashVer'); + $builder->add($video->flash_version); + } + if (isset($video->play_path)) { + $builder->add('--playpath'); + $builder->add($video->play_path); + } + if (isset($video->rtmp_conn)) { + foreach ($video->rtmp_conn as $conn) { + $builder->add('--conn'); + $builder->add($conn); + } + } + if (isset($video->app)) { + $builder->add('--app'); + $builder->add($video->app); + } + return $builder->getProcess(); + } + + /** + * Get a process that runs curl in order to download a video + * @param object $video Video object returned by youtube-dl + * @return \Symfony\Component\Process\Process Process + */ + private function getCurlProcess($video) + { + if (!shell_exec('which '.$this->config->curl)) { + throw(new \Exception('Can\'t find curl')); + } + $builder = ProcessBuilder::create( + array_merge( + [ + $this->config->curl, + '--silent', + '--location', + '--user-agent', $video->http_headers->{'User-Agent'}, + $video->url, + ], + $this->config->curl_params + ) + ); + return $builder->getProcess(); + } + /** * Get audio stream of converted video. * @@ -180,60 +249,10 @@ class VideoDownload ); if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') { - if (!shell_exec('which '.$this->config->rtmpdump)) { - throw(new \Exception('Can\'t find rtmpdump')); - } - $builder = new ProcessBuilder( - [ - $this->config->rtmpdump, - '-q', - '-r', - $video->url, - '--pageUrl', $video->webpage_url, - ] - ); - if (isset($video->player_url)) { - $builder->add('--swfVfy'); - $builder->add($video->player_url); - } - if (isset($video->flash_version)) { - $builder->add('--flashVer'); - $builder->add($video->flash_version); - } - if (isset($video->play_path)) { - $builder->add('--playpath'); - $builder->add($video->play_path); - } - if (isset($video->rtmp_conn)) { - foreach ($video->rtmp_conn as $conn) { - $builder->add('--conn'); - $builder->add($conn); - } - } - if (isset($video->app)) { - $builder->add('--app'); - $builder->add($video->app); - } - $chain = new Chain($builder->getProcess()); + $chain = new Chain($this->getRtmpProcess($video)); $chain->add('|', $avconvProc); } else { - if (!shell_exec('which '.$this->config->curl)) { - throw(new \Exception('Can\'t find curl')); - } - $chain = new Chain( - ProcessBuilder::create( - array_merge( - [ - $this->config->curl, - '--silent', - '--location', - '--user-agent', $video->http_headers->{'User-Agent'}, - $video->url, - ], - $this->config->curl_params - ) - ) - ); + $chain = new Chain($this->getCurlProcess($video)); $chain->add('|', $avconvProc); } From fdc746a69d507fcaf26d41ac5d0c7a31b308ed50 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 14 Oct 2016 17:02:14 +0000 Subject: [PATCH 02/46] Applied fixes from StyleCI --- classes/VideoDownload.php | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 3eed861..a4c589d 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -148,8 +148,10 @@ class VideoDownload } /** - * Get a process that runs rtmp in order to download a video - * @param object $video Video object returned by youtube-dl + * Get a process that runs rtmp in order to download a video. + * + * @param object $video Video object returned by youtube-dl + * * @return \Symfony\Component\Process\Process Process */ private function getRtmpProcess($video) @@ -188,12 +190,15 @@ class VideoDownload $builder->add('--app'); $builder->add($video->app); } + return $builder->getProcess(); } /** - * Get a process that runs curl in order to download a video - * @param object $video Video object returned by youtube-dl + * Get a process that runs curl in order to download a video. + * + * @param object $video Video object returned by youtube-dl + * * @return \Symfony\Component\Process\Process Process */ private function getCurlProcess($video) @@ -213,6 +218,7 @@ class VideoDownload $this->config->curl_params ) ); + return $builder->getProcess(); } From b4d3b9d88b64ab3224accb281daa77e00145aee3 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Fri, 14 Oct 2016 19:16:52 +0200 Subject: [PATCH 03/46] Duplicate code --- classes/VideoDownload.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index a4c589d..ddc1fa3 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -255,12 +255,12 @@ class VideoDownload ); if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') { - $chain = new Chain($this->getRtmpProcess($video)); - $chain->add('|', $avconvProc); + $process = $this->getRtmpProcess($video); } else { - $chain = new Chain($this->getCurlProcess($video)); - $chain->add('|', $avconvProc); + $process = $this->getCurlProcess($video); } + $chain = new Chain($process); + $chain->add('|', $avconvProc); return popen($chain->getProcess()->getCommandLine(), 'r'); } From 7d930d5083015ef70c91c01ea69ff02de6cf4111 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Sat, 15 Oct 2016 16:18:04 +0200 Subject: [PATCH 04/46] Code refactoring --- classes/VideoDownload.php | 48 +++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index ddc1fa3..5124aca 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -147,6 +147,32 @@ class VideoDownload ); } + /** + * Add options to a process builder running rtmp. + * + * @param ProcessBuilder $builder Process builder + * @param object $video Video object returned by youtube-dl + * + * @return ProcessBuilder + */ + private function addOptionsToRtmpProcess(ProcessBuilder $builder, $video) + { + foreach ([ + 'url' => 'rtmp', + 'webpage_url' => 'pageUrl', + 'player_url' => 'swfVfy', + 'flash_version' => 'flashVer', + 'play_path' => 'playpath', + 'app' => 'app', + ] as $property => $option) { + if (isset($video->{$property})) { + $builder->add('--'.$option); + $builder->add($video->{$property}); + } + } + return $builder; + } + /** * Get a process that runs rtmp in order to download a video. * @@ -162,34 +188,16 @@ class VideoDownload $builder = new ProcessBuilder( [ $this->config->rtmpdump, - '-q', - '-r', - $video->url, - '--pageUrl', $video->webpage_url, + '-q' ] ); - if (isset($video->player_url)) { - $builder->add('--swfVfy'); - $builder->add($video->player_url); - } - if (isset($video->flash_version)) { - $builder->add('--flashVer'); - $builder->add($video->flash_version); - } - if (isset($video->play_path)) { - $builder->add('--playpath'); - $builder->add($video->play_path); - } + $builder = $this->addOptionsToRtmpProcess($builder, $video); if (isset($video->rtmp_conn)) { foreach ($video->rtmp_conn as $conn) { $builder->add('--conn'); $builder->add($conn); } } - if (isset($video->app)) { - $builder->add('--app'); - $builder->add($video->app); - } return $builder->getProcess(); } From 21967b77fbd59094e6af6009039980235de4c06f Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Sat, 15 Oct 2016 14:20:54 +0000 Subject: [PATCH 05/46] Applied fixes from StyleCI --- classes/VideoDownload.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 5124aca..498a56b 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -170,6 +170,7 @@ class VideoDownload $builder->add($video->{$property}); } } + return $builder; } @@ -188,7 +189,7 @@ class VideoDownload $builder = new ProcessBuilder( [ $this->config->rtmpdump, - '-q' + '-q', ] ); $builder = $this->addOptionsToRtmpProcess($builder, $video); From eedaa338a94ecc5c5fbe1f385f9930c24911d44c Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Mon, 17 Oct 2016 11:22:53 +0200 Subject: [PATCH 06/46] Add instructions for missing CSS and JS files in FAQ --- FAQ.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/FAQ.md b/FAQ.md index 1bfb336..2a79dbf 100644 --- a/FAQ.md +++ b/FAQ.md @@ -55,3 +55,11 @@ There are two known workarounds: * You can run Alltube locally on your computer. * You can use the experimental `feature/stream` branch which streams the video through the server in order to bypass IP restrictions. Please note that this can use a lot of resources on the server (which is why we won't enable it on alltubedownload.net). + +## CSS and JavaScript files are missing + +You probably don't have the minified files (in the `dist` folder). +You need to either: + +* Use a [release package](https://github.com/Rudloff/alltube/releases) +* Run `npm install` (see detailed instructions in the [README](README.md#from-git)) From 0d2d1cd54836d989b09ea62345a675ff0884501f Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 09:17:16 +0200 Subject: [PATCH 07/46] ffmpeg and youtube-dl should be dev dependencies as they can be installed from elsewhere --- .travis.yml | 2 +- composer.json | 6 +++--- composer.lock | 52 +++++++++++++++++++++++++-------------------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9f514fb..3ffe9d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php install: - - composer install --no-dev + - composer install before_install: - composer selfupdate after_success: diff --git a/composer.json b/composer.json index 635283f..b6c5a26 100644 --- a/composer.json +++ b/composer.json @@ -6,20 +6,20 @@ "type": "project", "require": { "smarty/smarty": "~3.1.29", - "rg3/youtube-dl": "~2016.09.08", "slim/slim": "~3.5.0", "mathmarques/smarty-view": "~1.1.0", "symfony/yaml": "~3.1.0", "symfony/process": "~3.1.0", "ptachoire/process-builder-chain": "~1.2.0", - "ffmpeg/ffmpeg": "dev-release", "rudloff/smarty-plugin-noscheme": "~0.1.0", "rudloff/rtmpdump-bin": "~2.3" }, "require-dev": { "symfony/var-dumper": "~3.1.0", "squizlabs/php_codesniffer": "~2.7.0", - "phpunit/phpunit": "~5.5.2" + "phpunit/phpunit": "~5.5.2", + "ffmpeg/ffmpeg": "dev-release", + "rg3/youtube-dl": "~2016.09.08" }, "extra": { "paas": { diff --git a/composer.lock b/composer.lock index 541e11f..70bb48c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "02cf80c6d4373a564269fea77fcd50a5", - "content-hash": "efbcfe87c3855d9559551638e85519f3", + "hash": "186f884cc6378240af71c2f966772e91", + "content-hash": "f247f0e474ec96305a224fdce94e0dae", "packages": [ { "name": "container-interop/container-interop", @@ -34,20 +34,6 @@ "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "time": "2014-12-30 15:22:37" }, - { - "name": "ffmpeg/ffmpeg", - "version": "dev-release", - "dist": { - "type": "xz", - "url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz", - "reference": null, - "shasum": null - }, - "bin": [ - "ffmpeg" - ], - "type": "library" - }, { "name": "jeremykendall/php-domain-parser", "version": "3.0.0", @@ -399,16 +385,6 @@ "description": "Add ability to chain symfony processes", "time": "2016-04-10 08:33:20" }, - { - "name": "rg3/youtube-dl", - "version": "2016.09.08", - "source": { - "type": "git", - "url": "https://github.com/rg3/youtube-dl.git", - "reference": "2016.09.08" - }, - "type": "library" - }, { "name": "rudloff/rtmpdump-bin", "version": "2.3", @@ -757,6 +733,20 @@ ], "time": "2015-06-14 21:17:01" }, + { + "name": "ffmpeg/ffmpeg", + "version": "dev-release", + "dist": { + "type": "xz", + "url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz", + "reference": null, + "shasum": null + }, + "bin": [ + "ffmpeg" + ], + "type": "library" + }, { "name": "myclabs/deep-copy", "version": "1.5.4", @@ -1393,6 +1383,16 @@ ], "time": "2016-10-09 07:01:45" }, + { + "name": "rg3/youtube-dl", + "version": "2016.09.08", + "source": { + "type": "git", + "url": "https://github.com/rg3/youtube-dl.git", + "reference": "2016.09.08" + }, + "type": "library" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.0", From 5e969733f1bf66597c0a679e9166ee5ad25f6b81 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 09:19:05 +0200 Subject: [PATCH 08/46] Don't include phpunit and phpcs in release package --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 6e13bd6..dcc42ff 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -68,7 +68,7 @@ module.exports = function (grunt) { options: { archive: 'alltube-<%= githash.main.tag %>.zip' }, - src: ['*.php', '!config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg'] + src: ['*.php', '!config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg', '!vendor/phpunit/**', '!vendor/squizlabs/**'] } }, phpdocumentor: { From 13be997ddbcdfe7d2d46dd2ccf2caa2e698577ce Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 09:27:28 +0200 Subject: [PATCH 09/46] Throw exception if youtube-dl can't be found --- classes/VideoDownload.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 498a56b..74b927b 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -33,6 +33,9 @@ class VideoDownload { $this->config = Config::getInstance(); $this->procBuilder = new ProcessBuilder(); + if (!is_file($this->config->youtubedl)) { + throw new \Exception("Can't find youtube-dl at ".$this->config->youtubedl); + } $this->procBuilder->setPrefix( array_merge( [$this->config->python, $this->config->youtubedl], From f549cc8ce3d847fb534d081f82e77074ea6d6945 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 09:44:45 +0200 Subject: [PATCH 10/46] We need PHP 5.6 on Travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3ffe9d7..a76d3d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: php +php: + - 5.6 install: - composer install before_install: From a3dee17b2af37485e620afb23956099fabe98faa Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 09:54:08 +0200 Subject: [PATCH 11/46] Move YAML parsing to Config::getInstance() Make Config::__construct() public --- classes/Config.php | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/classes/Config.php b/classes/Config.php index 674717b..66e728d 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -84,18 +84,24 @@ class Config /** * Config constructor. * - * @param string $yamlfile YAML config file path + * Available options: + * * youtubedl: youtube-dl binary path + * * python: Python binary path + * * avconv: avconv or ffmpeg binary path + * * rtmpdump: rtmpdump binary path + * * curl: curl binary path + * * params: Array of youtube-dl parameters + * * curl_params: Array of curl parameters + * * convert: Enable conversion? + * + * @param array $options Options */ - private function __construct($yamlfile) + public function __construct(array $options) { - $this->file = $yamlfile; - if (is_file($yamlfile)) { - $yaml = Yaml::parse(file_get_contents($yamlfile)); - if (isset($yaml) && is_array($yaml)) { - foreach ($yaml as $param => $value) { - if (isset($this->$param) && isset($value)) { - $this->$param = $value; - } + if (isset($options) && is_array($options)) { + foreach ($options as $option => $value) { + if (isset($this->$option) && isset($value)) { + $this->$option = $value; } } } @@ -105,7 +111,7 @@ class Config } /** - * Get singleton instance. + * Get Config singleton instance from YAML config file. * * @param string $yamlfile YAML config file name * @@ -113,9 +119,21 @@ class Config */ public static function getInstance($yamlfile = 'config.yml') { - $yamlfile = __DIR__.'/../'.$yamlfile; + $yamlPath = __DIR__.'/../'.$yamlfile; if (is_null(self::$instance) || self::$instance->file != $yamlfile) { - self::$instance = new self($yamlfile); + if (is_file($yamlfile)) { + $options = Yaml::parse(file_get_contents($yamlPath)); + } elseif ($yamlfile == 'config.yml') { + /* + Allow for the default file to be missing in order to + not surprise users that did not create a config file + */ + $options = []; + } else { + throw new \Exception("Can't find config file at ".$yamlPath); + } + self::$instance = new self($options); + self::$instance->file = $yamlfile; } return self::$instance; From b6f8e585be847ebf4d59c8592e76381ee74cf755 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 10:03:50 +0200 Subject: [PATCH 12/46] Add a way to pass a Config object to VideoDownload --- classes/VideoDownload.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 74b927b..6da3d5b 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -29,9 +29,13 @@ class VideoDownload /** * VideoDownload constructor. */ - public function __construct() + public function __construct(Config $config = null) { - $this->config = Config::getInstance(); + if (isset($config)) { + $this->config = $config; + } else { + $this->config = Config::getInstance(); + } $this->procBuilder = new ProcessBuilder(); if (!is_file($this->config->youtubedl)) { throw new \Exception("Can't find youtube-dl at ".$this->config->youtubedl); From cb7dad19dc39c88c2b2dac04dfd6a82a6720b4b5 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 10:15:09 +0200 Subject: [PATCH 13/46] Throw exception is Python is missing --- classes/VideoDownload.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 6da3d5b..b48c53d 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -39,6 +39,8 @@ class VideoDownload $this->procBuilder = new ProcessBuilder(); if (!is_file($this->config->youtubedl)) { throw new \Exception("Can't find youtube-dl at ".$this->config->youtubedl); + } elseif (!is_file($this->config->python)) { + throw new \Exception("Can't find Python at ".$this->config->python); } $this->procBuilder->setPrefix( array_merge( From 201d7c3376f2c94f18035962dfedacf988b020f0 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 10:22:06 +0200 Subject: [PATCH 14/46] rtmpdump is not required as it can be installed elsewhere --- composer.json | 6 +++--- composer.lock | 60 +++++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/composer.json b/composer.json index b6c5a26..466cbcc 100644 --- a/composer.json +++ b/composer.json @@ -11,15 +11,15 @@ "symfony/yaml": "~3.1.0", "symfony/process": "~3.1.0", "ptachoire/process-builder-chain": "~1.2.0", - "rudloff/smarty-plugin-noscheme": "~0.1.0", - "rudloff/rtmpdump-bin": "~2.3" + "rudloff/smarty-plugin-noscheme": "~0.1.0" }, "require-dev": { "symfony/var-dumper": "~3.1.0", "squizlabs/php_codesniffer": "~2.7.0", "phpunit/phpunit": "~5.5.2", "ffmpeg/ffmpeg": "dev-release", - "rg3/youtube-dl": "~2016.09.08" + "rg3/youtube-dl": "~2016.09.08", + "rudloff/rtmpdump-bin": "~2.3" }, "extra": { "paas": { diff --git a/composer.lock b/composer.lock index 70bb48c..5426bf6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "186f884cc6378240af71c2f966772e91", - "content-hash": "f247f0e474ec96305a224fdce94e0dae", + "hash": "d0a06c9bc6164cc788eb8ad3d2a9291c", + "content-hash": "91057608d6f29b8de8a9761bb419f19c", "packages": [ { "name": "container-interop/container-interop", @@ -385,34 +385,6 @@ "description": "Add ability to chain symfony processes", "time": "2016-04-10 08:33:20" }, - { - "name": "rudloff/rtmpdump-bin", - "version": "2.3", - "source": { - "type": "git", - "url": "https://github.com/Rudloff/rtmpdump-bin.git", - "reference": "133cdd80e3bab66593e88a5276158596383afd97" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97", - "reference": "133cdd80e3bab66593e88a5276158596383afd97", - "shasum": "" - }, - "require-dev": { - "rtmpdump/rtmpdump": "2.3" - }, - "bin": [ - "rtmpdump" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0" - ], - "description": "rtmpdump binary for Linux 64 bit", - "time": "2016-04-12 19:17:32" - }, { "name": "rudloff/smarty-plugin-noscheme", "version": "0.1.1", @@ -1393,6 +1365,34 @@ }, "type": "library" }, + { + "name": "rudloff/rtmpdump-bin", + "version": "2.3", + "source": { + "type": "git", + "url": "https://github.com/Rudloff/rtmpdump-bin.git", + "reference": "133cdd80e3bab66593e88a5276158596383afd97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97", + "reference": "133cdd80e3bab66593e88a5276158596383afd97", + "shasum": "" + }, + "require-dev": { + "rtmpdump/rtmpdump": "2.3" + }, + "bin": [ + "rtmpdump" + ], + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0" + ], + "description": "rtmpdump binary for Linux 64 bit", + "time": "2016-04-12 19:17:32" + }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.0", From 85fb3a54cd7372c651df4e26458acb8451f27c9a Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 10:45:16 +0200 Subject: [PATCH 15/46] Test for exceptions when creating config --- tests/ConfigTest.php | 11 +++++++++++ tests/VideoDownloadTest.php | 29 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 9e7e1d8..da6cdf7 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -42,6 +42,17 @@ class ConfigTest extends \PHPUnit_Framework_TestCase $this->assertInternalType('string', $this->config->rtmpdump); } + /** + * Test the getInstance function with a missing config file. + * + * @return void + * @expectedException Exception + */ + public function testGetInstanceWithMissingFile() + { + Config::getInstance('foo'); + } + /** * Test the getInstance function with the CONVERT environment variable. * diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php index 8e5d705..55e5915 100644 --- a/tests/VideoDownloadTest.php +++ b/tests/VideoDownloadTest.php @@ -5,6 +5,7 @@ namespace Alltube\Test; use Alltube\VideoDownload; +use Alltube\Config; /** * Unit tests for the VideoDownload class. @@ -31,7 +32,33 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ protected function tearDown() { - \Alltube\Config::destroyInstance(); + Config::destroyInstance(); + } + + /** + * Test VideoDownload constructor with wrong youtube-dl path. + * + * @return void + * @expectedException Exception + */ + public function testConstructorWithMissingYoutubedl() + { + new VideoDownload( + new Config(['youtubedl'=>'foo']) + ); + } + + /** + * Test VideoDownload constructor with wrong Python path. + * + * @return void + * @expectedException Exception + */ + public function testConstructorWithMissingPython() + { + new VideoDownload( + new Config(['python'=>'foo']) + ); } /** From 18a15a7484c9d5c65958afc6a0995157731605c5 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Tue, 18 Oct 2016 08:45:54 +0000 Subject: [PATCH 16/46] Applied fixes from StyleCI --- tests/VideoDownloadTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php index 55e5915..22aa6c9 100644 --- a/tests/VideoDownloadTest.php +++ b/tests/VideoDownloadTest.php @@ -4,8 +4,8 @@ */ namespace Alltube\Test; -use Alltube\VideoDownload; use Alltube\Config; +use Alltube\VideoDownload; /** * Unit tests for the VideoDownload class. @@ -44,7 +44,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase public function testConstructorWithMissingYoutubedl() { new VideoDownload( - new Config(['youtubedl'=>'foo']) + new Config(['youtubedl' => 'foo']) ); } @@ -57,7 +57,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase public function testConstructorWithMissingPython() { new VideoDownload( - new Config(['python'=>'foo']) + new Config(['python' => 'foo']) ); } From 96b961e72cf5771a3659a6cf30adce97856aa6a7 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 17:17:02 +0200 Subject: [PATCH 17/46] Generate doc with Travis --- .travis.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.travis.yml b/.travis.yml index a76d3d2..bc33f0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,18 @@ install: - composer install before_install: - composer selfupdate + - npm install -g npm@3 after_success: - bash <(curl -s https://codecov.io/bash) +before_deploy: + - npm install + - ./node_modules/.bin/grunt doc +deploy: + provider: surge + project: ./docs/ + domain: alltube.surge.sh + skip_cleanup: true +env: + global: + - SURGE_LOGIN=contact@rudloff.pro + - secure: Icw8UqAilq0+neZsdXn7pny5OrDin1tTN0H3HGPFDBawHWBEffettRsURljnBlm0IcAE8HPvl0DlaGFMedM3ZlYjvp7OqMqe84p7dY22JMvirV4MsMz546FKEYI+g3txawAMDFPCorE+fgkDrL1eUoozGVJxc5c4w4nBVm84QvjxRvCvEKbfevd4giaie1Xuo927lKAwTaVFZryYNotPyJVB2pBBndxfl2EJczJ4DXQc3VczFXkTmuE/QLa2tQVJm5vnVPwOi1xmvgh6g1ChEOw0zAks1Mf5+UvxtVV7qTicVAWK0fVVBL9mHPpNzSNb4pPqHPWQjhAPdCW+WPn6+DhqS5BHeSfQit/OtLMpUWO1IceVDRwU3jkXmMgnKwz1t9yDh6VBZRvGPkXfU3cjQ9SFpmnnu/4JLgwA/zSU2Pzl7/+gsHQBazkXh8HYAbOjF2w1IBXOpZ8Yv7D5axRIDduS/TUQ6oNK3KYmRMBcg8ZzVzIdz+55NchaDtihcp5akaHhKxR7GMPrfi66b+wARSw3OsYmCGLNFF8zj/6zo3/zB02+oVMlXXySOAKKi0A2OvH9xV4W4Jl0TGua/27XOWr9c5btrZrykk3PXfKe5YgT46Q8CtK8yN97bDKbwbAp6gNEyMFFatdHKlEndZYsVDQ16htd0b/303SZfXYMvO0= From 9c35b5177708c05085576cc8a839b5143cbf9c44 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 18:05:58 +0200 Subject: [PATCH 18/46] Add title to code doc --- phpdoc.xml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 phpdoc.xml diff --git a/phpdoc.xml b/phpdoc.xml new file mode 100644 index 0000000..27bf4a6 --- /dev/null +++ b/phpdoc.xml @@ -0,0 +1,4 @@ + + + Alltube Download library documentation + From 257b7ed9fd4d773b6fd6d9ceb546d3da4882fd5a Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 18:11:22 +0200 Subject: [PATCH 19/46] We don't need grunt-cli --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index eb8b13b..fc6ec07 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "dependencies": { "bower": "~1.7.1", "grunt": "~1.0.1", - "grunt-cli": "~1.2.0", "grunt-contrib-cssmin": "~1.0.0", "grunt-contrib-uglify": "~2.0.0" }, @@ -39,6 +38,6 @@ "url": "https://github.com/Rudloff/alltube.git" }, "scripts": { - "postinstall": "node node_modules/bower/bin/bower install && node node_modules/grunt-cli/bin/grunt" + "postinstall": "node node_modules/.bin/bower install && node node_modules/.bin/grunt" } } From be92413e3cb18b07490edd05fa931e686d67666f Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 18:32:13 +0200 Subject: [PATCH 20/46] Add how to use as a library in README --- README.md | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 63fea97..f35d40b 100644 --- a/README.md +++ b/README.md @@ -110,12 +110,6 @@ server { } ``` -## License - -This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html). - -Please __use a different name and logo__ if you run it on a public server. - ## Other dependencies You need [avconv](https://libav.org/avconv.html), [rtmpdump](http://rtmpdump.mplayerhq.hu/) and [curl](https://curl.haxx.se/) in order to enable conversions. @@ -129,6 +123,45 @@ sudo apt-get install libav-tools rtmpdump curl You also probably need to edit the `avconv` variable in `config.yml` so that it points to your ffmpeg/avconv binary (`/usr/bin/avconv` on Debian/Ubuntu). +## Use as library + +Alltube can also be used as a library to extract a video URL from a webpage. + +You can install it with: + +```bash +composer require rudloff/alltube +``` + +You can then use it in your PHP code: + +```php +use Alltube\Config; +use Alltube\VideoDownload; + +require_once __DIR__.'/vendor/autoload.php'; + +$downloader = new VideoDownload( + new Config( + [ + 'youtubedl' => '/usr/local/bin/youtube-dl', + ] + ) +); + +$downloader->getURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); +``` + +The library documentation is available on [alltube.surge.sh](https://alltube.surge.sh/classes/Alltube.VideoDownload.html). + +You can also have a look at this [example project](https://github.com/Rudloff/alltube-example-project). + ## FAQ Please read the [FAQ](FAQ.md) before reporting any issue. + +## License + +This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html). + +Please __use a different name and logo__ if you run it on a public server. From e575e16e4fc6c2106a7c4d7d9029ee49a2938abf Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 18:33:45 +0200 Subject: [PATCH 21/46] 0.6.0 release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fc6ec07..9606f58 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "alltube", "description": "HTML GUI for youtube-dl", - "version": "0.5.2", + "version": "0.6.0", "author": "Pierre Rudloff", "bugs": "https://github.com/Rudloff/alltube/issues", "dependencies": { From 4cb699207d913f43ed7d977e5e109a9b1f11ca36 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Wed, 19 Oct 2016 19:13:44 +0200 Subject: [PATCH 22/46] Force dev dependencis on Heroku --- composer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/composer.json b/composer.json index 466cbcc..2e26009 100644 --- a/composer.json +++ b/composer.json @@ -78,5 +78,8 @@ }, "config": { "secure-http": false + }, + "scripts": { + "compile": "composer install --dev" } } From 621ccfb4912a94fd3548f1a91c2ecd6e24692392 Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Thu, 20 Oct 2016 18:34:09 +0200 Subject: [PATCH 23/46] composer.lock update --- composer.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.lock b/composer.lock index 5426bf6..854f2de 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d0a06c9bc6164cc788eb8ad3d2a9291c", + "hash": "2814570fa83cedc8e079c1d236a787d2", "content-hash": "91057608d6f29b8de8a9761bb419f19c", "packages": [ { From e34b01f2c47df219460c94d28783e6c6bc5b572c Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Thu, 20 Oct 2016 23:01:31 +0200 Subject: [PATCH 24/46] Add support for password protected videos --- classes/PasswordException.php | 13 +++++++ classes/VideoDownload.php | 49 +++++++++++++++--------- composer.json | 3 +- composer.lock | 66 ++++++++++++++++++++++++++++++++- controllers/FrontController.php | 41 ++++++++++++++++++-- index.php | 2 +- templates/password.tpl | 13 +++++++ templates/video.tpl | 6 +-- tests/VideoDownloadTest.php | 32 ++++++++++++++++ 9 files changed, 196 insertions(+), 29 deletions(-) create mode 100644 classes/PasswordException.php create mode 100644 templates/password.tpl diff --git a/classes/PasswordException.php b/classes/PasswordException.php new file mode 100644 index 0000000..abf1ce5 --- /dev/null +++ b/classes/PasswordException.php @@ -0,0 +1,13 @@ +procBuilder->setArguments( [ @@ -88,10 +89,21 @@ class VideoDownload if (isset($format)) { $this->procBuilder->add('-f '.$format); } + if (isset($password)) { + $this->procBuilder->add('--video-password'); + $this->procBuilder->add($password); + } $process = $this->procBuilder->getProcess(); $process->run(); if (!$process->isSuccessful()) { - throw new \Exception($process->getErrorOutput()); + $errorOutput = trim($process->getErrorOutput()); + if ($errorOutput == 'ERROR: This video is protected by a password, use the --video-password option') { + throw new PasswordException($errorOutput); + } elseif (substr($errorOutput, 0, 21) == 'ERROR: Wrong password') { + throw new \Exception('Wrong password'); + } else { + throw new \Exception($errorOutput); + } } else { return $process->getOutput(); } @@ -100,40 +112,43 @@ class VideoDownload /** * Get all information about a video. * - * @param string $url URL of page - * @param string $format Format to use for the video + * @param string $url URL of page + * @param string $format Format to use for the video + * @param string $password Video password * * @return object Decoded JSON * */ - public function getJSON($url, $format = null) + public function getJSON($url, $format = null, $password = null) { - return json_decode($this->getProp($url, $format, 'dump-json')); + return json_decode($this->getProp($url, $format, 'dump-json', $password)); } /** * Get URL of video from URL of page. * - * @param string $url URL of page - * @param string $format Format to use for the video + * @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 * */ - public function getURL($url, $format = null) + public function getURL($url, $format = null, $password = null) { - return $this->getProp($url, $format, 'get-url'); + return $this->getProp($url, $format, 'get-url', $password); } /** * Get filename of video file from URL of page. * - * @param string $url URL of page - * @param string $format Format to use for the video + * @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 * */ - public function getFilename($url, $format = null) + public function getFilename($url, $format = null, $password = null) { - return trim($this->getProp($url, $format, 'get-filename')); + return trim($this->getProp($url, $format, 'get-filename', $password)); } /** diff --git a/composer.json b/composer.json index 2e26009..c617f5d 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "symfony/yaml": "~3.1.0", "symfony/process": "~3.1.0", "ptachoire/process-builder-chain": "~1.2.0", - "rudloff/smarty-plugin-noscheme": "~0.1.0" + "rudloff/smarty-plugin-noscheme": "~0.1.0", + "aura/session": "~2.1.0" }, "require-dev": { "symfony/var-dumper": "~3.1.0", diff --git a/composer.lock b/composer.lock index 854f2de..547746b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,71 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2814570fa83cedc8e079c1d236a787d2", - "content-hash": "91057608d6f29b8de8a9761bb419f19c", + "hash": "7feb22c9a83e389562253bd1e7389080", + "content-hash": "0ca3a07c96a159c3a44ae007b56a9fbf", "packages": [ + { + "name": "aura/session", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/auraphp/Aura.Session.git", + "reference": "7d2f7d41ad693970b5b6b83facca0961d3378883" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/auraphp/Aura.Session/zipball/7d2f7d41ad693970b5b6b83facca0961d3378883", + "reference": "7d2f7d41ad693970b5b6b83facca0961d3378883", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "aura/di": "~2.0" + }, + "suggest": { + "ext-mcrypt": "Mcrypt generates the next best secure CSRF tokens.", + "ext-openssl": "OpenSSL generates the best secure CSRF tokens.", + "ircmaxell/random-lib": "A Library For Generating Secure Random Numbers", + "paragonie/random_compat": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7" + }, + "type": "library", + "extra": { + "aura": { + "type": "library", + "config": { + "common": "Aura\\Session\\_Config\\Common" + } + } + }, + "autoload": { + "psr-4": { + "Aura\\Session\\": "src/", + "Aura\\Session\\_Config\\": "config/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Aura.Session Contributors", + "homepage": "https://github.com/auraphp/Aura.Session/contributors" + } + ], + "description": "Provides session management functionality, including lazy session starting, session segments, next-request-only (\"flash\") values, and CSRF tools.", + "homepage": "https://github.com/auraphp/Aura.Session", + "keywords": [ + "csrf", + "flash", + "flash message", + "session", + "sessions" + ], + "time": "2016-10-03 20:28:32" + }, { "name": "container-interop/container-interop", "version": "1.1.0", diff --git a/controllers/FrontController.php b/controllers/FrontController.php index d6b71e6..b25b691 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -6,6 +6,7 @@ namespace Alltube\Controller; use Alltube\Config; use Alltube\VideoDownload; +use Alltube\PasswordException; use Interop\Container\ContainerInterface; use Slim\Container; use Slim\Http\Request; @@ -48,6 +49,9 @@ class FrontController $this->config = Config::getInstance(); $this->download = new VideoDownload(); $this->container = $container; + $session_factory = new \Aura\Session\SessionFactory; + $session = $session_factory->newInstance($_COOKIE); + $this->sessionSegment = $session->getSegment('Alltube\Controller\FrontController'); } /** @@ -98,6 +102,28 @@ class FrontController } } + /** + * Display a password prompt + * @param Request $request PSR-7 request + * @param Response $response PSR-7 response + * + * @return Response HTTP response + */ + public function password(Request $request, Response $response) + { + if ($this->container instanceof Container) { + $this->container->view->render( + $response, + 'password.tpl', + [ + 'class' => 'password', + 'title' => 'Password prompt', + 'description' => 'You need a password in order to download this video with Alltube Download', + ] + ); + } + } + /** * Dislay information about the video. * @@ -109,8 +135,11 @@ class FrontController public function video(Request $request, Response $response) { $params = $request->getQueryParams(); - $this->config = Config::getInstance(); if (isset($params['url'])) { + $password = $request->getParam('password'); + if (isset($password)) { + $this->sessionSegment->setFlash($params['url'], $password); + } if (isset($params['audio'])) { try { $url = $this->download->getURL($params['url'], 'mp3[protocol^=http]'); @@ -132,7 +161,11 @@ class FrontController return $response; } } else { - $video = $this->download->getJSON($params['url']); + try { + $video = $this->download->getJSON($params['url'], null, $password); + } catch (PasswordException $e) { + return $this->password($request, $response); + } if ($this->container instanceof Container) { $this->container->view->render( $response, @@ -190,9 +223,11 @@ class FrontController $params = $request->getQueryParams(); if (isset($params['url'])) { try { - $url = $this->download->getURL($params['url'], $params['format']); + $url = $this->download->getURL($params['url'], $request->getParam('format'), $this->sessionSegment->getFlash($params['url'])); return $response->withRedirect($url); + } catch (PasswordException $e) { + return $response->withRedirect($this->container->get('router')->pathFor('video').'?url='.urlencode($params['url'])); } catch (\Exception $e) { $response->getBody()->write($e->getMessage()); diff --git a/index.php b/index.php index f9fdd7d..6a01bc4 100644 --- a/index.php +++ b/index.php @@ -35,7 +35,7 @@ $app->get( '/extractors', [$controller, 'extractors'] )->setName('extractors'); -$app->get( +$app->any( '/video', [$controller, 'video'] )->setName('video'); diff --git a/templates/password.tpl b/templates/password.tpl new file mode 100644 index 0000000..ab8e302 --- /dev/null +++ b/templates/password.tpl @@ -0,0 +1,13 @@ +{include file='inc/head.tpl'} +
+
+ {include file="inc/logo.tpl"} +

This video is protected

+

You need a password in order to download this video.

+
+ +

+ +
+
+{include file='inc/footer.tpl'} diff --git a/templates/video.tpl b/templates/video.tpl index e3790b1..6f11251 100644 --- a/templates/video.tpl +++ b/templates/video.tpl @@ -28,11 +28,7 @@