diff --git a/.gitignore b/.gitignore index af93b59..b0dd8bb 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ alltube-*.zip coverage/ bower_components/ config.yml +docs/ diff --git a/.travis.yml b/.travis.yml index fbe6512..d12f0db 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,5 @@ language: php install: - - composer install - - npm install + - composer install --no-dev before_install: - composer selfupdate diff --git a/FAQ.md b/FAQ.md index 59c4b04..52c7ed6 100644 --- a/FAQ.md +++ b/FAQ.md @@ -3,3 +3,27 @@ ## My browser plays the video. How do I download it? Most recent browsers automatically play a video if it is a format they know how to play. You can ususally download the video by doing *File > Save to* or *ctrl + S*. + +## How do I change config parameters? +You need to create a YAML file called `config.yml` at the root of your project. +Here are the parameters that you can set: +* youtubedl: path to your youtube-dl binary +* python: path to your python binary +* params: an array of parameters to pass to youtube-dl +* curl_params: an array of parameters to pass to curl +* convert: true to enable audio conversion +* avconv: path to your avconv or ffmpeg binary +* rtmpdump: path to your rtmpdump binary + +See [config.example.yml](config.example.yml) for default values. + +## How do I enable audio conversion? +In order to enable audio conversion, you need to add this to your `config.yml` file: +```yaml +convert: true +avconv: path/to/avconv +``` +You will also need to install `avconv` and `curl` on your server: +```bash +sudo apt-get install libav-tools curl +``` diff --git a/Gruntfile.js b/Gruntfile.js index e18273a..76ec640 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -34,7 +34,8 @@ module.exports = function (grunt) { }, phpcs: { options: { - standard: 'PSR2' + standard: 'PSR2', + bin: 'vendor/bin/phpcs' }, php: { src: ['*.php', 'classes/*.php', 'controllers/*.php'] @@ -52,6 +53,12 @@ module.exports = function (grunt) { } }, phpunit: { + options: { + bin: 'php -dzend_extension=xdebug.so ./vendor/bin/phpunit', + stopOnError: true, + stopOnFailure: true, + followOutput: true + }, classes: { dir: 'tests/' } @@ -61,7 +68,14 @@ module.exports = function (grunt) { options: { archive: 'alltube-<%= githash.main.tag %>.zip' }, - src: ['*.php', '!config.yml', 'dist/**', 'fonts/**', '.htaccess', 'img/**', 'js/**', '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'] + } + }, + phpdocumentor: { + doc: { + options: { + directory: 'classes/,controllers/,tests/' + } } } } @@ -75,9 +89,11 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-phpunit'); grunt.loadNpmTasks('grunt-contrib-compress'); grunt.loadNpmTasks('grunt-jslint'); + grunt.loadNpmTasks('grunt-phpdocumentor'); grunt.registerTask('default', ['uglify', 'cssmin']); grunt.registerTask('lint', ['phpcs', 'jslint']); grunt.registerTask('test', ['phpunit']); + grunt.registerTask('doc', ['phpdocumentor']); grunt.registerTask('release', ['default', 'githash', 'compress']); }; diff --git a/README.md b/README.md index bf2ff3e..483b269 100644 --- a/README.md +++ b/README.md @@ -14,25 +14,28 @@ You just have to unzip it on your server and it should be ready to use. ### From Git In order to get AllTube working, you need to use [npm](https://www.npmjs.com/) and [Composer](https://getcomposer.org/): - - npm install - composer install +```bash +npm install +composer install +``` This will download all the required dependencies. (Note that it will download the ffmpeg binary for 64-bits Linux. If you are on another platform, you might want to specify the path to avconv/ffmpeg in your config file.) You should also ensure that the *templates_c* folder has the right permissions: - - chmod 777 templates_c/ +```bash +chmod 777 templates_c/ +``` If your web server is Apache, you need to set the `AllowOverride` setting to `All` or `FileInfo`. ## Config If you want to use a custom config, you need to create a config file: - - cp config.example.yml config.yml +```bash +cp config.example.yml config.yml +``` ## Web server configuration ### Apache @@ -43,52 +46,52 @@ You will need the following modules: ### Nginx Here is an exemple Nginx configuration: +```nginx +server { + server_name localhost; + listen 443 ssl; - server { - server_name localhost; - listen 443 ssl; + root /var/www/path/to/alltube; + index index.php; - root /var/www/path/to/alltube; - index index.php; + access_log /var/log/nginx/alltube.access.log; + error_log /var/log/nginx/alltube.error.log; - access_log /var/log/nginx/alltube.access.log; - error_log /var/log/nginx/alltube.error.log; + types { + text/html html htm shtml; + text/css css; + text/xml xml; + application/x-web-app-manifest+json webapp; + } - types { - text/html html htm shtml; - text/css css; - text/xml xml; - application/x-web-app-manifest+json webapp; - } + # Deny access to dotfiles + location ~ /\. { + deny all; + } - # Deny access to dotfiles - location ~ /\. { - deny all; - } + location / { + try_files $uri /index.php?$args; + } - location / { - try_files $uri /index.php?$args; - } + location ~ \.php$ { + try_files $uri /index.php?$args; - location ~ \.php$ { - try_files $uri /index.php?$args; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_pass unix:/var/run/php5-fpm.sock; + fastcgi_index index.php; + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_intercept_errors off; - fastcgi_pass unix:/var/run/php5-fpm.sock; - fastcgi_index index.php; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_intercept_errors off; - - fastcgi_buffer_size 16k; - fastcgi_buffers 4 16k; - - include fastcgi_params; - } - } + fastcgi_buffer_size 16k; + fastcgi_buffers 4 16k; + include fastcgi_params; + } +} +``` ## License This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html). @@ -100,7 +103,7 @@ You need [avconv](https://libav.org/avconv.html), [rtmpdump](http://rtmpdump.mpl If you don't want to enable conversions, you can disable it in *config.yml*. On Debian-based systems: - - sudo apt-get install libav-tools rtmpdump curl - +```bash +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). diff --git a/classes/Config.php b/classes/Config.php index c7befdf..c86f418 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -1,40 +1,68 @@ - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + */ namespace Alltube; use Symfony\Component\Yaml\Yaml; /** - * Class to manage config parameters - * - * PHP Version 5.3.10 - * - * @category Youtube-dl - * @package Youtubedl - * @author Pierre Rudloff - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + * Manage config parameters + */ class Config { + /** + * Singleton instance + * @var Config + */ private static $instance; + /** + * youtube-dl binary path + * @var string + */ public $youtubedl = 'vendor/rg3/youtube-dl/youtube_dl/__main__.py'; + + /** + * python binary path + * @var string + */ public $python = '/usr/bin/python'; + + /** + * youtube-dl parameters + * @var array + */ public $params = array('--no-playlist', '--no-warnings', '-f best[protocol^=http]', '--playlist-end', 1); + + /** + * Enable audio conversion + * @var bool + */ public $convert = false; + + /** + * avconv or ffmpeg binary path + * @var string + */ public $avconv = 'vendor/bin/ffmpeg'; + + /** + * rtmpdump binary path + * @var string + */ public $rtmpdump = 'vendor/bin/rtmpdump'; + + /** + * curl binary path + * @var string + */ + public $curl = '/usr/bin/curl'; + + /** + * curl parameters + * @var array + */ public $curl_params = array(); /** @@ -70,4 +98,13 @@ class Config } return self::$instance; } + + /** + * Destroy singleton instance + * @return void + */ + public static function destroyInstance() + { + self::$instance = null; + } } diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index 22033cc..5023a20 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -1,33 +1,22 @@ - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + */ namespace Alltube; use Symfony\Component\Process\Process; use Symfony\Component\Process\ProcessBuilder; +use Chain\Chain; /** - * Main class - * - * PHP Version 5.3.10 - * - * @category Youtube-dl - * @package Youtubedl - * @author Pierre Rudloff - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + * Extract info about videos + */ class VideoDownload { + + /** + * VideoDownload constructor + */ public function __construct() { $this->config = Config::getInstance(); @@ -43,7 +32,7 @@ class VideoDownload /** * List all extractors * - * @return array Extractors + * @return string[] Extractors * */ public function listExtractors() { @@ -54,7 +43,7 @@ class VideoDownload ); $process = $this->procBuilder->getProcess(); $process->run(); - return explode(PHP_EOL, $process->getOutput()); + return explode(PHP_EOL, trim($process->getOutput())); } /** @@ -111,6 +100,145 @@ class VideoDownload } else { return $process->getOutput(); } + } + /** + * Get filename of video file from URL of page + * + * @param string $url URL of page + * @param string $format Format to use for the video + * + * @return string Filename of extracted video + * */ + public function getFilename($url, $format = null) + { + $this->procBuilder->setArguments( + array( + '--get-filename', + $url + ) + ); + if (isset($format)) { + $this->procBuilder->add('-f '.$format); + } + $process = $this->procBuilder->getProcess(); + $process->run(); + if (!$process->isSuccessful()) { + throw new \Exception($process->getErrorOutput()); + } else { + return trim($process->getOutput()); + } + } + + /** + * Get filename of audio from URL of page + * + * @param string $url URL of page + * @param string $format Format to use for the video + * + * @return string Filename of converted audio file + * */ + public function getAudioFilename($url, $format = null) + { + return html_entity_decode( + pathinfo( + $this->getFilename($url, $format), + PATHINFO_FILENAME + ).'.mp3', + ENT_COMPAT, + 'ISO-8859-1' + ); + } + + /** + * Get audio stream of converted video + * + * @param string $url URL of page + * @param string $format Format to use for the video + * + * @return resource popen stream + */ + public function getAudioStream($url, $format) + { + if (!shell_exec('which '.$this->config->avconv)) { + throw(new \Exception('Can\'t find avconv or ffmpeg')); + } + + $video = $this->getJSON($url, $format); + + //Vimeo needs a correct user-agent + ini_set( + 'user_agent', + $video->http_headers->{'User-Agent'} + ); + $avconvProc = ProcessBuilder::create( + array( + $this->config->avconv, + '-v', 'quiet', + '-i', '-', + '-f', 'mp3', + '-vn', + 'pipe:1' + ) + ); + + 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( + array( + $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->add('|', $avconvProc); + } else { + if (!shell_exec('which '.$this->config->curl)) { + throw(new \Exception('Can\'t find curl')); + } + $chain = new Chain( + ProcessBuilder::create( + array_merge( + array( + $this->config->curl, + '--silent', + '--location', + '--user-agent', $video->http_headers->{'User-Agent'}, + $video->url + ), + $this->config->curl_params + ) + ) + ); + $chain->add('|', $avconvProc); + } + return popen($chain->getProcess()->getCommandLine(), 'r'); } } diff --git a/composer.json b/composer.json index 6c40265..9421e33 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "type": "project", "require": { "smarty/smarty": "~3.1.29", - "rg3/youtube-dl": "~2016.07.26.2", + "rg3/youtube-dl": "~2016.08.12", "slim/slim": "~3.5.0", "mathmarques/smarty-view": "~1.1.0", "symfony/yaml": "~3.1.0", @@ -18,7 +18,9 @@ "rudloff/rtmpdump-bin": "~2.3" }, "require-dev": { - "symfony/var-dumper": "~3.1.0" + "symfony/var-dumper": "~3.1.0", + "squizlabs/php_codesniffer": "~2.6.2", + "phpunit/phpunit": "~5.4.8" }, "extra": { "paas": { @@ -31,11 +33,11 @@ "type": "package", "package": { "name": "rg3/youtube-dl", - "version": "2016.07.26.2", + "version": "2016.08.12", "source": { "url": "https://github.com/rg3/youtube-dl.git", "type": "git", - "reference": "2016.07.26.2" + "reference": "2016.08.12" } } }, { diff --git a/composer.lock b/composer.lock index b0fa6a0..fdd5e99 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": "c4eb7b9cf1322b024130fba8517794f3", - "content-hash": "3608a48b9ac14ccba68577310338f6b7", + "hash": "45458ad3758a4bfcdcff81c70a53e796", + "content-hash": "2ee8e0ffa53778d2a2eaa5de447573e8", "packages": [ { "name": "container-interop/container-interop", @@ -486,16 +486,16 @@ }, { "name": "psr/http-message", - "version": "1.0", + "version": "1.0.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298" + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", - "reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", + "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", "shasum": "" }, "require": { @@ -523,6 +523,7 @@ } ], "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ "http", "http-message", @@ -531,7 +532,7 @@ "request", "response" ], - "time": "2015-05-04 20:22:00" + "time": "2016-08-06 14:39:51" }, { "name": "ptachoire/process-builder-chain", @@ -571,11 +572,11 @@ }, { "name": "rg3/youtube-dl", - "version": "2016.07.26.2", + "version": "2016.08.12", "source": { "type": "git", "url": "https://github.com/rg3/youtube-dl.git", - "reference": "2016.07.26.2" + "reference": "2016.08.12" }, "type": "library" }, @@ -720,16 +721,16 @@ }, { "name": "smarty/smarty", - "version": "v3.1.29", + "version": "v3.1.30", "source": { "type": "git", "url": "https://github.com/smarty-php/smarty.git", - "reference": "35480f10e7ce9b0fdaf23d3799d7b79463919b1e" + "reference": "ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/smarty-php/smarty/zipball/35480f10e7ce9b0fdaf23d3799d7b79463919b1e", - "reference": "35480f10e7ce9b0fdaf23d3799d7b79463919b1e", + "url": "https://api.github.com/repos/smarty-php/smarty/zipball/ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e", + "reference": "ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e", "shasum": "" }, "require": { @@ -771,20 +772,20 @@ "keywords": [ "templating" ], - "time": "2015-12-21 01:57:06" + "time": "2016-08-07 18:46:49" }, { "name": "symfony/process", - "version": "v3.1.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0" + "reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/5c11a1a4d4016662eeaf0f8757958c7de069f9a0", - "reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0", + "url": "https://api.github.com/repos/symfony/process/zipball/04c2dfaae4ec56a5c677b0c69fac34637d815758", + "reference": "04c2dfaae4ec56a5c677b0c69fac34637d815758", "shasum": "" }, "require": { @@ -820,20 +821,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:42:25" + "time": "2016-07-28 11:13:48" }, { "name": "symfony/yaml", - "version": "v3.1.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de" + "reference": "1819adf2066880c7967df7180f4f662b6f0567ac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de", - "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de", + "url": "https://api.github.com/repos/symfony/yaml/zipball/1819adf2066880c7967df7180f4f662b6f0567ac", + "reference": "1819adf2066880c7967df7180f4f662b6f0567ac", "shasum": "" }, "require": { @@ -869,10 +870,1286 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2016-06-29 05:41:56" + "time": "2016-07-17 14:02:08" } ], "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14 21:17:01" + }, + { + "name": "myclabs/deep-copy", + "version": "1.5.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "a8773992b362b58498eed24bf85005f363c34771" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/a8773992b362b58498eed24bf85005f363c34771", + "reference": "a8773992b362b58498eed24bf85005f363c34771", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2015-11-20 12:04:31" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", + "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-06-10 09:48:41" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", + "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-06-10 07:14:17" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", + "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-06-07 08:13:47" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3", + "reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "~1.0|~2.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.4.0", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2016-07-26 14:39:29" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2015-06-21 13:08:43" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2015-09-15 10:49:45" + }, + { + "name": "phpunit/phpunit", + "version": "5.4.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "3132365e1430c091f208e120b8845d39c25f20e6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3132365e1430c091f208e120b8845d39c25f20e6", + "reference": "3132365e1430c091f208e120b8845d39c25f20e6", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "^4.0.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.1", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3 || ^2.0", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/object-enumerator": "~1.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2016-07-26 14:48:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "4e83390f64e7ce04fcaec2ce95cd72823b431d19" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/4e83390f64e7ce04fcaec2ce95cd72823b431d19", + "reference": "4e83390f64e7ce04fcaec2ce95cd72823b431d19", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2016-08-17 09:33:51" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2016-02-13 06:45:14" + }, + { + "name": "sebastian/comparator", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", + "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2015-07-26 15:48:44" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18 05:49:44" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17 09:04:28" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/object-enumerator", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26", + "reference": "d4ca2fb70344987502567bc50081c03e6192fb26", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-01-28 13:25:10" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", + "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2015-11-11 19:50:13" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" + }, + { + "name": "sebastian/version", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-02-04 12:56:52" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "2.6.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "4edb770cb853def6e60c93abb088ad5ac2010c83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4edb770cb853def6e60c93abb088ad5ac2010c83", + "reference": "4edb770cb853def6e60c93abb088ad5ac2010c83", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "time": "2016-07-13 23:29:13" + }, { "name": "symfony/polyfill-mbstring", "version": "v1.2.0", @@ -934,16 +2211,16 @@ }, { "name": "symfony/var-dumper", - "version": "v3.1.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "39492b8b8fe514163e677bf154fd80f6cc995759" + "reference": "076235b750137518408f1bc17a8e69b43211836a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/39492b8b8fe514163e677bf154fd80f6cc995759", - "reference": "39492b8b8fe514163e677bf154fd80f6cc995759", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/076235b750137518408f1bc17a8e69b43211836a", + "reference": "076235b750137518408f1bc17a8e69b43211836a", "shasum": "" }, "require": { @@ -993,7 +2270,57 @@ "debug", "dump" ], - "time": "2016-06-29 05:41:56" + "time": "2016-07-26 08:04:17" + }, + { + "name": "webmozart/assert", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308", + "reference": "bb2d123231c095735130cc8f6d31385a44c7b308", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-08-09 15:02:57" } ], "aliases": [], diff --git a/config.example.yml b/config.example.yml index 9f66ab7..ca03f0b 100644 --- a/config.example.yml +++ b/config.example.yml @@ -10,3 +10,4 @@ curl_params: convert: false avconv: vendor/bin/ffmpeg rtmpdump: vendor/bin/rtmpdump +curl: /usr/bin/curl diff --git a/controllers/FrontController.php b/controllers/FrontController.php index ae4ec4e..40e87d0 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -1,39 +1,44 @@ - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + */ namespace Alltube\Controller; use Alltube\VideoDownload; use Alltube\Config; -use Symfony\Component\Process\ProcessBuilder; -use Chain\Chain; use Slim\Http\Stream; use Slim\Http\Request; use Slim\Http\Response; +use Slim\Container; /** * Main controller - * - * PHP Version 5.3.10 - * - * @category Youtube-dl - * @package Youtubedl - * @author Pierre Rudloff - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ + */ class FrontController { - public function __construct($container) + /** + * Config instance + * @var Config + */ + private $config; + + /** + * VideoDownload instance + * @var VideoDownload + */ + private $download; + + /** + * Slim dependency container + * @var Container + */ + private $container; + + /** + * FrontController constructor + * @param Container $container Slim dependency container + */ + public function __construct(Container $container) { $this->config = Config::getInstance(); $this->download = new VideoDownload(); @@ -52,24 +57,13 @@ class FrontController { $this->container->view->render( $response, - 'head.tpl', + 'index.tpl', array( + 'convert'=>$this->config->convert, 'class'=>'index', 'description'=>'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.' ) ); - $this->container->view->render( - $response, - 'header.tpl' - ); - $this->container->view->render( - $response, - 'index.tpl', - array( - 'convert'=>$this->config->convert - ) - ); - $this->container->view->render($response, 'footer.tpl'); } /** @@ -84,24 +78,15 @@ class FrontController { $this->container->view->render( $response, - 'head.tpl', + 'extractors.tpl', array( + 'extractors'=>$this->download->listExtractors(), 'class'=>'extractors', 'title'=>'Supported websites', 'description' =>'List of all supported websites from which Alltube Download can extract video or audio files' ) ); - $this->container->view->render($response, 'header.tpl'); - $this->container->view->render($response, 'logo.tpl'); - $this->container->view->render( - $response, - 'extractors.tpl', - array( - 'extractors'=>$this->download->listExtractors() - ) - ); - $this->container->view->render($response, 'footer.tpl'); } /** @@ -110,7 +95,7 @@ class FrontController * @param Request $request PSR-7 request * @param Response $response PSR-7 response * - * @return void + * @return Response HTTP response */ public function video(Request $request, Response $response) { @@ -121,96 +106,16 @@ class FrontController try { return $this->getStream($params["url"], 'mp3[protocol^=http]', $response, $request); } catch (\Exception $e) { - $video = $this->download->getJSON($params["url"], 'bestaudio/best'); - - if (!shell_exec('which '.$this->config->avconv)) { - throw(new \Exception('Can\'t find avconv or ffmpeg')); - } - - $avconvProc = ProcessBuilder::create( - array( - $this->config->avconv, - '-v', 'quiet', - '-i', '-', - '-f', 'mp3', - '-vn', - 'pipe:1' - ) - ); - - //Vimeo needs a correct user-agent - ini_set( - 'user_agent', - $video->http_headers->{'User-Agent'} - ); - $response = $response->withHeader( 'Content-Disposition', 'attachment; filename="'. - html_entity_decode( - pathinfo( - $video->_filename, - PATHINFO_FILENAME - ).'.mp3', - ENT_COMPAT, - 'ISO-8859-1' - ).'"' + $this->download->getAudioFilename($params["url"], 'bestaudio/best').'"' ); $response = $response->withHeader('Content-Type', 'audio/mpeg'); - 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( - array( - $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); - } - foreach ($video->rtmp_conn as $conn) { - $builder->add('--conn'); - $builder->add($conn); - } - $chain = new Chain($builder->getProcess()); - $chain->add('|', $avconvProc); - } else { - if (!shell_exec('which curl')) { - throw(new \Exception('Can\'t find curl')); - } - $chain = new Chain( - ProcessBuilder::create( - array_merge( - array( - 'curl', - '--silent', - '--location', - '--user-agent', $video->http_headers->{'User-Agent'}, - $video->url - ), - $this->config->curl_params - ) - ) - ); - $chain->add('|', $avconvProc); - } if ($request->isGet()) { - $response = $response->withBody(new Stream(popen($chain->getProcess()->getCommandLine(), 'r'))); + $process = $this->download->getAudioStream($params["url"], 'bestaudio/best'); + $response = $response->withBody(new Stream($process)); } return $response; } @@ -218,45 +123,38 @@ class FrontController $video = $this->download->getJSON($params["url"]); $this->container->view->render( $response, - 'head.tpl', + 'video.tpl', array( + 'video'=>$video, 'class'=>'video', 'title'=>$video->title, 'description'=>'Download "'.$video->title.'" from '.$video->extractor_key ) ); - $this->container->view->render( - $response, - 'video.tpl', - array( - 'video'=>$video - ) - ); - $this->container->view->render($response, 'footer.tpl'); } } else { return $response->withRedirect($this->container->get('router')->pathFor('index')); } } + /** + * Display an error page + * @param Request $request PSR-7 request + * @param Response $response PSR-7 response + * @param \Exception $exception Error to display + * @return Response HTTP response + */ public function error(Request $request, Response $response, \Exception $exception) { $this->container->view->render( $response, - 'head.tpl', + 'error.tpl', array( + 'errors'=>$exception->getMessage(), 'class'=>'video', 'title'=>'Error' ) ); - $this->container->view->render( - $response, - 'error.tpl', - array( - 'errors'=>$exception->getMessage() - ) - ); - $this->container->view->render($response, 'footer.tpl'); return $response->withStatus(500); } @@ -283,7 +181,7 @@ class FrontController * @param Request $request PSR-7 request * @param Response $response PSR-7 response * - * @return void + * @return Response HTTP response */ public function redirect(Request $request, Response $response) { @@ -304,7 +202,7 @@ class FrontController * @param Request $request PSR-7 request * @param Response $response PSR-7 response * - * @return void + * @return Response HTTP response */ public function json(Request $request, Response $response) { diff --git a/index.php b/index.php index e9cee6f..60026bf 100644 --- a/index.php +++ b/index.php @@ -1,17 +1,4 @@ - * @author Olivier Haquette - * @license GNU General Public License http://www.gnu.org/licenses/gpl.html - * @link http://rudloff.pro - * */ require_once __DIR__.'/vendor/autoload.php'; use Alltube\VideoDownload; use Alltube\Controller\FrontController; diff --git a/package.json b/package.json index 2620eab..8c9f981 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,17 @@ "grunt": "~1.0.1", "grunt-cli": "~1.2.0", "grunt-contrib-cssmin": "~1.0.0", - "grunt-contrib-uglify": "~1.0.0", + "grunt-contrib-uglify": "~2.0.0", + "bower": "~1.7.1" + }, + "devDependencies": { "grunt-contrib-watch": "~1.0.0", "grunt-phpcs": "~0.4.0", "grunt-phpunit": "~0.3.6", "grunt-contrib-compress": "~1.3.0", - "bower": "~1.7.1", "grunt-githash": "~0.1.3", - "grunt-jslint": "~1.1.14" + "grunt-jslint": "~1.1.14", + "grunt-phpdocumentor": "~0.4.1" }, "repository": { "type": "git", diff --git a/templates/error.tpl b/templates/error.tpl index d000ab3..67a0fae 100644 --- a/templates/error.tpl +++ b/templates/error.tpl @@ -1,6 +1,7 @@ +{include file='inc/head.tpl'}
- {include file="logo.tpl"} + {include file="inc/logo.tpl"}

An error occured

Please check the URL of your video.

@@ -9,4 +10,5 @@
{/foreach}

-
+
+{include file='inc/footer.tpl'} diff --git a/templates/extractors.tpl b/templates/extractors.tpl index 076f99e..4944193 100644 --- a/templates/extractors.tpl +++ b/templates/extractors.tpl @@ -1,8 +1,12 @@ +{include file='inc/head.tpl'} +{include file='inc/header.tpl'} +{include file='inc/logo.tpl'}

Supported websites

-
    +
      {foreach $extractors as $extractor}
    • {$extractor}
    • {/foreach}
+{include file='inc/footer.tpl'} diff --git a/templates/footer.tpl b/templates/inc/footer.tpl similarity index 100% rename from templates/footer.tpl rename to templates/inc/footer.tpl diff --git a/templates/head.tpl b/templates/inc/head.tpl similarity index 100% rename from templates/head.tpl rename to templates/inc/head.tpl diff --git a/templates/header.tpl b/templates/inc/header.tpl similarity index 100% rename from templates/header.tpl rename to templates/inc/header.tpl diff --git a/templates/logo.tpl b/templates/inc/logo.tpl similarity index 100% rename from templates/logo.tpl rename to templates/inc/logo.tpl diff --git a/templates/index.tpl b/templates/index.tpl index 5d046e6..93f44eb 100644 --- a/templates/index.tpl +++ b/templates/index.tpl @@ -1,4 +1,6 @@ -
+{include file='inc/head.tpl'} +{include file='inc/header.tpl'} +
@@ -27,3 +29,4 @@
+{include file='inc/footer.tpl'} diff --git a/templates/video.tpl b/templates/video.tpl index daaf3cc..e3790b1 100644 --- a/templates/video.tpl +++ b/templates/video.tpl @@ -1,7 +1,8 @@ +{include file="inc/head.tpl"}
-{include file="logo.tpl"} +{include file="inc/logo.tpl"}

You are going to download