diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..5445fbd --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,20 @@ +--- +install: + - sc config wuauserv start= auto + - net start wuauserv + - cinst php composer ffmpeg + - refreshenv + - copy C:\tools\php72\php.ini-development C:\tools\php72\php.ini + - echo extension=C:\tools\php72\ext\php_gmp.dll >> C:\tools\php72\php.ini + - echo extension=C:\tools\php72\ext\php_gettext.dll >> C:\tools\php72\php.ini + - echo extension=C:\tools\php72\ext\php_intl.dll >> C:\tools\php72\php.ini + - echo extension=C:\tools\php72\ext\php_openssl.dll >> C:\tools\php72\php.ini + - echo extension=C:\tools\php72\ext\php_mbstring.dll >> C:\tools\php72\php.ini + - composer install --no-dev + - composer global require phpunit/phpunit + - C:\Python36\python.exe -m pip install youtube-dl + +test_script: + - phpunit + +build: "off" diff --git a/.travis.yml b/.travis.yml index b005f82..de96aef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,18 @@ --- language: php -php: 7 +php: 7.1 addons: apt: packages: - language-pack-fr install: - composer install -script: vendor/bin/phpunit +script: composer exec -v phpunit after_success: - bash <(curl -s https://codecov.io/bash) before_deploy: - yarn install --ignore-scripts - - ./node_modules/.bin/grunt doc + - yarn grunt doc deploy: provider: surge project: ./docs/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 63ccbed..f5f081a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,4 +10,5 @@ Before opening a new issue, make sure that: ## Translation -If you want to help translating Alltube in your language, you can join our [POEditor project](https://poeditor.com/join/project/GJmE0wN7Xw). +If you want to help translating Alltube in your language, +you can join our [POEditor project](https://poeditor.com/join/project/GJmE0wN7Xw). diff --git a/Dockerfile b/Dockerfile index 52fd230..ecfc795 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,6 @@ RUN curl -sS https://getcomposer.org/installer | php COPY resources/php.ini /usr/local/etc/php/ COPY . /var/www/html/ RUN php composer.phar install --prefer-dist -RUN yarn install +RUN yarn install --prod RUN ./node_modules/.bin/grunt ENV CONVERT=1 diff --git a/Gruntfile.js b/Gruntfile.js index 7101e0a..4d20de1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -54,7 +54,7 @@ module.exports = function (grunt) { }, phpunit: { options: { - bin: 'php -dzend_extension=xdebug.so ./vendor/bin/phpunit', + bin: 'vendor/bin/phpunit', stopOnError: true, stopOnFailure: true, followOutput: true @@ -111,7 +111,12 @@ module.exports = function (grunt) { css: { src: 'css/*' } - } + }, + markdownlint: { + doc: { + src: ['README.md', 'CONTRIBUTING.md', 'resources/*.md'] + } + } } ); @@ -128,9 +133,10 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-fixpack'); grunt.loadNpmTasks('grunt-potomo'); grunt.loadNpmTasks('grunt-contrib-csslint'); + grunt.loadNpmTasks('grunt-markdownlint'); grunt.registerTask('default', ['cssmin', 'potomo']); - grunt.registerTask('lint', ['csslint', 'fixpack', 'jsonlint', 'phpcs']); + grunt.registerTask('lint', ['csslint', 'fixpack', 'jsonlint', 'markdownlint', 'phpcs']); grunt.registerTask('test', ['phpunit']); grunt.registerTask('doc', ['phpdocumentor']); grunt.registerTask('release', ['default', 'githash', 'compress']); diff --git a/README.md b/README.md index db0db29..1c9a929 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ 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 [Yarn](https://yarnpkg.com/) and [Composer](https://getcomposer.org/): +In order to get AllTube working, +you need to use [Yarn](https://yarnpkg.com/) and [Composer](https://getcomposer.org/): ```bash yarn install @@ -23,7 +24,9 @@ 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.) +(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: @@ -31,7 +34,8 @@ You should also ensure that the *templates_c* folder has the right permissions: chmod 777 templates_c/ ``` -If your web server is Apache, you need to set the `AllowOverride` setting to `All` or `FileInfo`. +If your web server is Apache, +you need to set the `AllowOverride` setting to `All` or `FileInfo`. #### Update @@ -39,7 +43,7 @@ When updating from Git, you need to run yarn and Composer again: ```bash git pull -yarn install +yarn install --prod composer install ``` @@ -126,16 +130,18 @@ server { ## Other dependencies -You need [avconv](https://libav.org/avconv.html) and [rtmpdump](http://rtmpdump.mplayerhq.hu/) in order to enable conversions. +You need [avconv](https://libav.org/avconv.html) +in order to enable conversions. If you don't want to enable conversions, you can disable it in `config.yml`. On Debian-based systems: ```bash -sudo apt-get install libav-tools rtmpdump +sudo apt-get install libav-tools ``` -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). +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 diff --git a/classes/Config.php b/classes/Config.php index 6226f26..e66a77d 100644 --- a/classes/Config.php +++ b/classes/Config.php @@ -54,13 +54,6 @@ class Config */ public $avconv = 'vendor/bin/ffmpeg'; - /** - * rtmpdump binary path. - * - * @var string - */ - public $rtmpdump = 'vendor/bin/rtmpdump'; - /** * Disable URL rewriting. * @@ -82,6 +75,21 @@ class Config */ public $remux = false; + /** + * MP3 bitrate when converting (in kbit/s). + * + * @var int + */ + public $audioBitrate = 128; + + /** + * avconv/ffmpeg logging level. + * Must be one of these: quiet, panic, fatal, error, warning, info, verbose, debug. + * + * @var string + */ + public $avconvVerbosity = 'error'; + /** * YAML config file path. * @@ -96,7 +104,6 @@ class Config * * youtubedl: youtube-dl binary path * * python: Python binary path * * avconv: avconv or ffmpeg binary path - * * rtmpdump: rtmpdump binary path * * params: Array of youtube-dl parameters * * convert: Enable conversion? * diff --git a/classes/Locale.php b/classes/Locale.php index 0914ab1..5392316 100644 --- a/classes/Locale.php +++ b/classes/Locale.php @@ -91,7 +91,7 @@ class Locale /** * Get country information from locale. * - * @return \Rinvex\Country\Country + * @return \Rinvex\Country\Country|array */ public function getCountry() { diff --git a/classes/LocaleManager.php b/classes/LocaleManager.php index 7e36e8c..a841079 100644 --- a/classes/LocaleManager.php +++ b/classes/LocaleManager.php @@ -5,7 +5,7 @@ namespace Alltube; -use Symfony\Component\Process\ProcessBuilder; +use Symfony\Component\Process\Process; /** * Class used to manage locales. @@ -42,7 +42,6 @@ class LocaleManager { $session_factory = new \Aura\Session\SessionFactory(); $session = $session_factory->newInstance($cookies); - $session->setCookieParams(['httponly' => true]); $this->sessionSegment = $session->getSegment('Alltube\LocaleManager'); $cookieLocale = $this->sessionSegment->get('locale'); if (isset($cookieLocale)) { @@ -58,8 +57,7 @@ class LocaleManager public function getSupportedLocales() { $return = []; - $builder = new ProcessBuilder(['locale', '-a']); - $process = $builder->getProcess(); + $process = new Process(['locale', '-a']); $process->run(); $installedLocales = explode(PHP_EOL, trim($process->getOutput())); foreach ($this->supportedLocales as $supportedLocale) { @@ -95,4 +93,13 @@ class LocaleManager $this->curLocale = $locale; $this->sessionSegment->set('locale', $locale); } + + /** + * Unset the current locale. + */ + public function unsetLocale() + { + $this->curLocale = null; + $this->sessionSegment->clear(); + } } diff --git a/classes/PlaylistArchiveStream.php b/classes/PlaylistArchiveStream.php index c97f6b8..6bf74b3 100644 --- a/classes/PlaylistArchiveStream.php +++ b/classes/PlaylistArchiveStream.php @@ -61,10 +61,10 @@ class PlaylistArchiveStream extends TarArchive /** * PlaylistArchiveStream constructor. */ - public function __construct() + public function __construct(Config $config = null) { $this->client = new \GuzzleHttp\Client(); - $this->download = new VideoDownload(); + $this->download = new VideoDownload($config); } /** @@ -78,7 +78,9 @@ class PlaylistArchiveStream extends TarArchive { $pos = ftell($this->buffer); fwrite($this->buffer, $data); - fseek($this->buffer, $pos); + if ($pos !== false) { + fseek($this->buffer, $pos); + } } /** @@ -91,7 +93,10 @@ class PlaylistArchiveStream extends TarArchive public function stream_open($path) { $this->format = ltrim(parse_url($path, PHP_URL_PATH), '/'); - $this->buffer = fopen('php://temp', 'r+'); + $buffer = fopen('php://temp', 'r+'); + if ($buffer !== false) { + $this->buffer = $buffer; + } foreach (explode(';', parse_url($path, PHP_URL_HOST)) as $url) { $this->files[] = [ 'url' => urldecode($url), @@ -131,7 +136,7 @@ class PlaylistArchiveStream extends TarArchive /** * Called when ftell() is used on the stream. * - * @return int + * @return int|false */ public function stream_tell() { @@ -171,7 +176,7 @@ class PlaylistArchiveStream extends TarArchive * * @param int $count Number of bytes to read * - * @return string + * @return string|false */ public function stream_read($count) { diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php index dfbbdb0..e72789c 100644 --- a/classes/VideoDownload.php +++ b/classes/VideoDownload.php @@ -5,8 +5,7 @@ namespace Alltube; -use Chain\Chain; -use Symfony\Component\Process\ProcessBuilder; +use Symfony\Component\Process\Process; /** * Extract info about videos. @@ -20,15 +19,11 @@ class VideoDownload */ private $config; - /** - * ProcessBuilder instance used to call Python. - * - * @var ProcessBuilder - */ - private $procBuilder; - /** * VideoDownload constructor. + * + * @throws \Exception If youtube-dl is missing + * @throws \Exception If Python is missing */ public function __construct(Config $config = null) { @@ -37,16 +32,27 @@ class VideoDownload } 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); - } elseif (!is_file($this->config->python)) { + } elseif (!$this->checkCommand([$this->config->python, '--version'])) { throw new \Exception("Can't find Python at ".$this->config->python); } - $this->procBuilder->setPrefix( + } + + /** + * Return a youtube-dl process with the specified arguments. + * + * @param string[] $arguments Arguments + * + * @return Process + */ + private function getProcess(array $arguments) + { + return new Process( array_merge( [$this->config->python, $this->config->youtubedl], - $this->config->params + $this->config->params, + $arguments ) ); } @@ -58,7 +64,7 @@ class VideoDownload * */ public function listExtractors() { - return explode(PHP_EOL, trim($this->getProp(null, null, 'list-extractors'))); + return explode("\n", trim($this->getProp(null, null, 'list-extractors'))); } /** @@ -69,24 +75,30 @@ class VideoDownload * @param string $prop Property * @param string $password Video password * + * @throws PasswordException If the video is protected by a password and no password was specified + * @throws \Exception If the password is wrong + * @throws \Exception If youtube-dl returns an error + * * @return string */ private function getProp($url, $format = null, $prop = 'dump-json', $password = null) { - $this->procBuilder->setArguments( - [ - '--'.$prop, - $url, - ] - ); + $arguments = [ + '--'.$prop, + $url, + ]; if (isset($format)) { - $this->procBuilder->add('-f '.$format); + $arguments[] = '-f '.$format; } if (isset($password)) { - $this->procBuilder->add('--video-password'); - $this->procBuilder->add($password); + $arguments[] = '--video-password'; + $arguments[] = $password; } - $process = $this->procBuilder->getProcess(); + + $process = $this->getProcess($arguments); + //This is needed by the openload extractor because it runs PhantomJS + $process->setEnv(['QT_QPA_PLATFORM'=>'offscreen']); + $process->inheritEnvironmentVariables(); $process->run(); if (!$process->isSuccessful()) { $errorOutput = trim($process->getErrorOutput()); @@ -131,7 +143,7 @@ class VideoDownload * */ public function getURL($url, $format = null, $password = null) { - return explode(PHP_EOL, $this->getProp($url, $format, 'get-url', $password)); + return explode("\n", $this->getProp($url, $format, 'get-url', $password)); } /** @@ -185,59 +197,38 @@ 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. + * Return arguments used to run rtmp for a specific video. * * @param object $video Video object returned by youtube-dl * - * @return \Symfony\Component\Process\Process Process + * @return array Arguments */ - private function getRtmpProcess(\stdClass $video) + private function getRtmpArguments(\stdClass $video) { - if (!$this->checkCommand([$this->config->rtmpdump, '--help'])) { - throw(new \Exception('Can\'t find rtmpdump')); - } - $builder = new ProcessBuilder( - [ - $this->config->rtmpdump, - '-q', - ] - ); - $builder = $this->addOptionsToRtmpProcess($builder, $video); - if (isset($video->rtmp_conn)) { - foreach ($video->rtmp_conn as $conn) { - $builder->add('--conn'); - $builder->add($conn); + $arguments = []; + + foreach ([ + 'url' => '-rtmp_tcurl', + 'webpage_url' => '-rtmp_pageurl', + 'player_url' => '-rtmp_swfverify', + 'flash_version' => '-rtmp_flashver', + 'play_path' => '-rtmp_playpath', + 'app' => '-rtmp_app', + ] as $property => $option) { + if (isset($video->{$property})) { + $arguments[] = $option; + $arguments[] = $video->{$property}; } } - return $builder->getProcess(); + if (isset($video->rtmp_conn)) { + foreach ($video->rtmp_conn as $conn) { + $arguments[] = '-rtmp_conn'; + $arguments[] = $conn; + } + } + + return $arguments; } /** @@ -249,8 +240,7 @@ class VideoDownload */ private function checkCommand(array $command) { - $builder = ProcessBuilder::create($command); - $process = $builder->getProcess(); + $process = new Process($command); $process->run(); return $process->isSuccessful(); @@ -259,30 +249,45 @@ class VideoDownload /** * Get a process that runs avconv in order to convert a video to MP3. * - * @param string $url URL of the video file + * @param object $url Video object returned by youtube-dl + * + * @throws \Exception If avconv/ffmpeg is missing * * @return \Symfony\Component\Process\Process Process */ - private function getAvconvMp3Process($url) + private function getAvconvMp3Process(\stdClass $video) { if (!$this->checkCommand([$this->config->avconv, '-version'])) { throw(new \Exception('Can\'t find avconv or ffmpeg')); } - $builder = ProcessBuilder::create( + if ($video->protocol == 'rtmp') { + $rtmpArguments = $this->getRtmpArguments($video); + } else { + $rtmpArguments = []; + } + + $arguments = array_merge( [ $this->config->avconv, - '-v', 'quiet', - //Vimeo needs a correct user-agent - '-user-agent', $this->getProp(null, null, 'dump-user-agent'), - '-i', $url, + '-v', $this->config->avconvVerbosity, + ], + $rtmpArguments, + [ + '-i', $video->url, '-f', 'mp3', + '-b:a', $this->config->audioBitrate.'k', '-vn', 'pipe:1', ] ); + if ($video->url != '-') { + //Vimeo needs a correct user-agent + $arguments[] = '-user_agent'; + $arguments[] = $this->getProp(null, null, 'dump-user-agent'); + } - return $builder->getProcess(); + return new Process($arguments); } /** @@ -292,6 +297,9 @@ class VideoDownload * @param string $format Format to use for the video * @param string $password Video password * + * @throws \Exception If your try to convert and M3U8 video + * @throws \Exception If the popen stream was not created correctly + * * @return resource popen stream */ public function getAudioStream($url, $format, $password = null) @@ -301,17 +309,15 @@ class VideoDownload throw(new \Exception('Conversion of M3U8 files is not supported.')); } - if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') { - $process = $this->getRtmpProcess($video); - $chain = new Chain($process); - $chain->add('|', $this->getAvconvMp3Process('-')); + $avconvProc = $this->getAvconvMp3Process($video); - return popen($chain->getProcess()->getCommandLine(), 'r'); - } else { - $avconvProc = $this->getAvconvMp3Process($video->url); + $stream = popen($avconvProc->getCommandLine(), 'r'); - return popen($avconvProc->getCommandLine(), 'r'); + if (!is_resource($stream)) { + throw new \Exception('Could not open popen stream.'); } + + return $stream; } /** @@ -319,6 +325,9 @@ class VideoDownload * * @param \stdClass $video Video object returned by getJSON * + * @throws \Exception If avconv/ffmpeg is missing + * @throws \Exception If the popen stream was not created correctly + * * @return resource popen stream */ public function getM3uStream(\stdClass $video) @@ -327,10 +336,10 @@ class VideoDownload throw(new \Exception('Can\'t find avconv or ffmpeg')); } - $procBuilder = ProcessBuilder::create( + $process = new Process( [ $this->config->avconv, - '-v', 'quiet', + '-v', $this->config->avconvVerbosity, '-i', $video->url, '-f', $video->ext, '-c', 'copy', @@ -340,7 +349,12 @@ class VideoDownload ] ); - return popen($procBuilder->getProcess()->getCommandLine(), 'r'); + $stream = popen($process->getCommandLine(), 'r'); + if (!is_resource($stream)) { + throw new \Exception('Could not open popen stream.'); + } + + return $stream; } /** @@ -348,14 +362,16 @@ class VideoDownload * * @param array $urls URLs of the video ($urls[0]) and audio ($urls[1]) files * + * @throws \Exception If the popen stream was not created correctly + * * @return resource popen stream */ public function getRemuxStream(array $urls) { - $procBuilder = ProcessBuilder::create( + $process = new Process( [ $this->config->avconv, - '-v', 'quiet', + '-v', $this->config->avconvVerbosity, '-i', $urls[0], '-i', $urls[1], '-c', 'copy', @@ -366,7 +382,12 @@ class VideoDownload ] ); - return popen($procBuilder->getProcess()->getCommandLine(), 'r'); + $stream = popen($process->getCommandLine(), 'r'); + if (!is_resource($stream)) { + throw new \Exception('Could not open popen stream.'); + } + + return $stream; } /** @@ -374,11 +395,32 @@ class VideoDownload * * @param \stdClass $video Video object returned by getJSON * + * @throws \Exception If the popen stream was not created correctly + * * @return resource popen stream */ public function getRtmpStream(\stdClass $video) { - return popen($this->getRtmpProcess($video)->getCommandLine(), 'r'); + $process = new Process( + array_merge( + [ + $this->config->avconv, + '-v', $this->config->avconvVerbosity, + ], + $this->getRtmpArguments($video), + [ + '-i', $video->url, + '-f', $video->ext, + 'pipe:1', + ] + ) + ); + $stream = popen($process->getCommandLine(), 'r'); + if (!is_resource($stream)) { + throw new \Exception('Could not open popen stream.'); + } + + return $stream; } /** @@ -387,7 +429,9 @@ class VideoDownload * @param object $video Video object returned by youtube-dl * @param string $format Requested format * - * @return Response HTTP response + * @throws \Exception If the popen stream was not created correctly + * + * @return resource */ public function getPlaylistArchiveStream(\stdClass $video, $format) { @@ -396,6 +440,9 @@ class VideoDownload $playlistItems[] = urlencode($entry->url); } $stream = fopen('playlist://'.implode(';', $playlistItems).'/'.$format, 'r'); + if (!is_resource($stream)) { + throw new \Exception('Could not fopen popen stream.'); + } return $stream; } diff --git a/classes/ViewFactory.php b/classes/ViewFactory.php index 5928efd..95503fc 100644 --- a/classes/ViewFactory.php +++ b/classes/ViewFactory.php @@ -18,8 +18,8 @@ class ViewFactory /** * Create Smarty view object. * - * @param Container $container Slim dependency container - * @param Request $request PSR-7 request + * @param ContainerInterface $container Slim dependency container + * @param Request $request PSR-7 request * * @return Smarty */ diff --git a/composer.json b/composer.json index a674423..a0cefd0 100644 --- a/composer.json +++ b/composer.json @@ -5,26 +5,25 @@ "homepage": "http://alltubedownload.net/", "type": "project", "require": { - "smarty/smarty": "~3.1.29", - "slim/slim": "~3.8.1", + "slim/slim": "~3.9.2", "mathmarques/smarty-view": "~1.1.0", - "symfony/yaml": "~3.3.9", - "symfony/process": "~3.3.9", - "ptachoire/process-builder-chain": "~1.2.0", + "symfony/yaml": "~3.4.1", + "symfony/process": "~3.4.1", "guzzlehttp/guzzle": "~6.3.0", "aura/session": "~2.1.0", "barracudanetworks/archivestream-php": "~1.0.5", "smarty-gettext/smarty-gettext": "~1.5.1", "zonuexe/http-accept-language": "~0.4.1", - "rinvex/country": "~2.0.0" + "rinvex/country": "~3.1.0", + "php-mock/php-mock-mockery": "~1.2.0" }, "require-dev": { - "symfony/var-dumper": "~3.3.9", - "squizlabs/php_codesniffer": "~3.1.0", - "phpunit/phpunit": "~5.7.2", - "ffmpeg/ffmpeg": "dev-release", - "rg3/youtube-dl": "~2017.10.20", - "rudloff/rtmpdump-bin": "~2.3.0", + "symfony/var-dumper": "~3.4.1", + "squizlabs/php_codesniffer": "~3.2.2", + "phpunit/phpunit": "~6.5.2", + "doctrine/instantiator": "~1.0.0", + "ffmpeg/ffmpeg": "3.4.1", + "rg3/youtube-dl": "2017.12.10", "heroku/heroku-buildpack-php": "*" }, "extra": { @@ -39,10 +38,10 @@ "type": "package", "package": { "name": "rg3/youtube-dl", - "version": "2017.10.20", + "version": "2017.12.10", "dist": { "type": "zip", - "url": "https://github.com/rg3/youtube-dl/archive/2017.10.20.zip" + "url": "https://github.com/rg3/youtube-dl/archive/2017.12.10.zip" } } }, @@ -50,9 +49,9 @@ "type": "package", "package": { "name": "ffmpeg/ffmpeg", - "version": "dev-release", + "version": "3.4.1", "dist": { - "url": "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz", + "url": "https://johnvansickle.com/ffmpeg/releases/ffmpeg-3.4.1-64bit-static.tar.xz", "type": "xz" }, "bin": [ @@ -78,11 +77,13 @@ "autoload": { "psr-4": { "Alltube\\": "classes/", - "Alltube\\Controller\\": "controllers/" + "Alltube\\Controller\\": "controllers/", + "Alltube\\Test\\": "tests/" } }, "scripts": { "compile": "composer install --ignore-platform-reqs", - "update-locales": "tsmarty2c.php templates > i18n/template.pot" + "update-locales": "tsmarty2c.php templates > i18n/template.pot", + "youtube-dl": "vendor/rg3/youtube-dl/youtube_dl/__main__.py" } } diff --git a/composer.lock b/composer.lock index 18d838d..a59306b 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" ], - "content-hash": "be0203be4eb5ef4d1b03fed10aa1b9f1", + "content-hash": "f9b0a5cf05f0e39a11f132701b9a95b4", "packages": [ { "name": "aura/session", @@ -320,6 +320,54 @@ ], "time": "2017-03-20T17:10:46+00:00" }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", + "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", + "shasum": "" + }, + "require": { + "php": "^5.3|^7.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "1.3.3", + "phpunit/phpunit": "~4.0", + "satooshi/php-coveralls": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "time": "2016-01-20T08:20:44+00:00" + }, { "name": "mathmarques/smarty-view", "version": "1.1.1", @@ -370,6 +418,71 @@ ], "time": "2016-08-25T19:04:49+00:00" }, + { + "name": "mockery/mockery", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1bac8c362b12f522fdd1f1fa3556284c91affa38" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1bac8c362b12f522fdd1f1fa3556284c91affa38", + "reference": "1bac8c362b12f522fdd1f1fa3556284c91affa38", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "~2.0", + "lib-pcre": ">=7.0", + "php": ">=5.6.0" + }, + "require-dev": { + "phpunit/phpunit": "~5.7|~6.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Mockery": "library/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "http://blog.astrumfutura.com" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "http://davedevelopment.co.uk" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework for use in unit testing with PHPUnit, PHPSpec or any other testing framework. Its core goal is to offer a test double framework with a succinct API capable of clearly defining all possible object operations and interactions using a human readable Domain Specific Language (DSL). Designed as a drop in alternative to PHPUnit's phpunit-mock-objects library, Mockery is easy to integrate with PHPUnit and can operate alongside phpunit-mock-objects without the World ending.", + "homepage": "http://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "time": "2017-10-06T16:20:43+00:00" + }, { "name": "nikic/fast-route", "version": "v1.2.0", @@ -413,6 +526,216 @@ ], "time": "2017-01-19T11:35:12+00:00" }, + { + "name": "php-mock/php-mock", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock.git", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/bfa2d17d64dbf129073a7ba2051a96ce52749570", + "reference": "bfa2d17d64dbf129073a7ba2051a96ce52749570", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpunit/php-text-template": "^1" + }, + "replace": { + "malkusch/php-mock": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "suggest": { + "php-mock/php-mock-mockery": "Allows using PHPMockery for Mockery integration", + "php-mock/php-mock-phpunit": "Allows integration into PHPUnit testcase with the trait PHPMock." + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\": [ + "classes/", + "tests/unit/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "PHP-Mock can mock built-in PHP functions (e.g. time()). PHP-Mock relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-11-11T22:37:09+00:00" + }, + { + "name": "php-mock/php-mock-integration", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-integration.git", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-integration/zipball/e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "reference": "e83fb65dd20cd3cf250d554cbd4682b96b684f4b", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "php-mock/php-mock": "^1", + "phpunit/php-text-template": "^1" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\integration\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Integration package for PHP-Mock", + "homepage": "https://github.com/php-mock/php-mock-integration", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "stub", + "test", + "test double" + ], + "time": "2015-10-26T21:21:42+00:00" + }, + { + "name": "php-mock/php-mock-mockery", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-mock/php-mock-mockery.git", + "reference": "f3d67a36558c6d1fb912ed8ba786fffaf94e0755" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-mock/php-mock-mockery/zipball/f3d67a36558c6d1fb912ed8ba786fffaf94e0755", + "reference": "f3d67a36558c6d1fb912ed8ba786fffaf94e0755", + "shasum": "" + }, + "require": { + "mockery/mockery": "^1", + "php": ">=5.6", + "php-mock/php-mock-integration": "^1" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpmock\\mockery\\": "classes/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "WTFPL" + ], + "authors": [ + { + "name": "Markus Malkusch", + "email": "markus@malkusch.de", + "homepage": "http://markus.malkusch.de", + "role": "Developer" + } + ], + "description": "Mock built-in PHP functions (e.g. time()) with Mockery. This package relies on PHP's namespace fallback policy. No further extension is needed.", + "homepage": "https://github.com/php-mock/php-mock-mockery", + "keywords": [ + "BDD", + "TDD", + "function", + "mock", + "mockery", + "stub", + "test", + "test double" + ], + "time": "2017-10-13T09:34:01+00:00" + }, + { + "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-21T13:50:34+00:00" + }, { "name": "pimple/pimple", "version": "v3.2.2", @@ -562,66 +885,30 @@ ], "time": "2016-08-06T14:39:51+00:00" }, - { - "name": "ptachoire/process-builder-chain", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/krichprollsch/process-builder-chain.git", - "reference": "465055dbcc3b5ef792a768df935571551de4781a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/krichprollsch/process-builder-chain/zipball/465055dbcc3b5ef792a768df935571551de4781a", - "reference": "465055dbcc3b5ef792a768df935571551de4781a", - "shasum": "" - }, - "require": { - "symfony/process": "~2.5 || ~3.0" - }, - "type": "library", - "autoload": { - "psr-0": { - "Chain": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Pierre Tachoire", - "email": "pierre.tachoire@gmail.com" - } - ], - "description": "Add ability to chain symfony processes", - "time": "2016-04-10T08:33:20+00:00" - }, { "name": "rinvex/country", - "version": "v2.0.0", + "version": "v3.1.0", "source": { "type": "git", "url": "https://github.com/rinvex/country.git", - "reference": "9405da035644bc76671bfba0c282fef8fd3408e1" + "reference": "e32228ef43f26d3b02296be9454f842c52d492f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rinvex/country/zipball/9405da035644bc76671bfba0c282fef8fd3408e1", - "reference": "9405da035644bc76671bfba0c282fef8fd3408e1", + "url": "https://api.github.com/repos/rinvex/country/zipball/e32228ef43f26d3b02296be9454f842c52d492f3", + "reference": "e32228ef43f26d3b02296be9454f842c52d492f3", "shasum": "" }, "require": { - "php": ">=5.5.9" + "php": "^7.0.0" }, "require-dev": { - "phpunit/phpunit": "^5.2.0" + "phpunit/phpunit": "^5.4.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -670,20 +957,20 @@ "rinvex", "svg" ], - "time": "2016-11-27T05:53:11+00:00" + "time": "2017-03-07T18:40:20+00:00" }, { "name": "slim/slim", - "version": "3.8.1", + "version": "3.9.2", "source": { "type": "git", "url": "https://github.com/slimphp/Slim.git", - "reference": "5385302707530b2bccee1769613ad769859b826d" + "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slimphp/Slim/zipball/5385302707530b2bccee1769613ad769859b826d", - "reference": "5385302707530b2bccee1769613ad769859b826d", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/4086d0106cf5a7135c69fce4161fe355a8feb118", + "reference": "4086d0106cf5a7135c69fce4161fe355a8feb118", "shasum": "" }, "require": { @@ -741,7 +1028,7 @@ "micro", "router" ], - "time": "2017-03-19T17:55:20+00:00" + "time": "2017-11-26T19:13:09+00:00" }, { "name": "smarty-gettext/smarty-gettext", @@ -852,16 +1139,16 @@ }, { "name": "symfony/process", - "version": "v3.3.10", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "fdf89e57a723a29baf536e288d6e232c059697b1" + "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/fdf89e57a723a29baf536e288d6e232c059697b1", - "reference": "fdf89e57a723a29baf536e288d6e232c059697b1", + "url": "https://api.github.com/repos/symfony/process/zipball/bb3ef65d493a6d57297cad6c560ee04e2a8f5098", + "reference": "bb3ef65d493a6d57297cad6c560ee04e2a8f5098", "shasum": "" }, "require": { @@ -870,7 +1157,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -897,27 +1184,30 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-12-14T19:40:10+00:00" }, { "name": "symfony/yaml", - "version": "v3.3.10", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46" + "reference": "afe0cd38486505c9703707707d91450cfc1bd536" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", - "reference": "8c7bf1e7d5d6b05a690b715729cb4cd0c0a99c46", + "url": "https://api.github.com/repos/symfony/yaml/zipball/afe0cd38486505c9703707707d91450cfc1bd536", + "reference": "afe0cd38486505c9703707707d91450cfc1bd536", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8" }, + "conflict": { + "symfony/console": "<3.4" + }, "require-dev": { - "symfony/console": "~2.8|~3.0" + "symfony/console": "~3.4|~4.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -925,7 +1215,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -952,7 +1242,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-10-05T14:43:42+00:00" + "time": "2017-12-11T20:38:23+00:00" }, { "name": "zonuexe/http-accept-language", @@ -1053,10 +1343,10 @@ }, { "name": "ffmpeg/ffmpeg", - "version": "dev-release", + "version": "3.4.1", "dist": { "type": "xz", - "url": "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz", + "url": "https://johnvansickle.com/ffmpeg/releases/ffmpeg-3.4.1-64bit-static.tar.xz", "reference": null, "shasum": null }, @@ -1067,16 +1357,16 @@ }, { "name": "heroku/heroku-buildpack-php", - "version": "v125", + "version": "v127", "source": { "type": "git", "url": "https://github.com/heroku/heroku-buildpack-php.git", - "reference": "880d625f715680aca2969562b8a5a69f4a289b7f" + "reference": "4428a20862137d682c9c15434c82a65c20541f97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/880d625f715680aca2969562b8a5a69f4a289b7f", - "reference": "880d625f715680aca2969562b8a5a69f4a289b7f", + "url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/4428a20862137d682c9c15434c82a65c20541f97", + "reference": "4428a20862137d682c9c15434c82a65c20541f97", "shasum": "" }, "bin": [ @@ -1107,7 +1397,7 @@ "nginx", "php" ], - "time": "2017-10-04T22:42:04+00:00" + "time": "2017-11-30T16:10:52+00:00" }, { "name": "myclabs/deep-copy", @@ -1154,6 +1444,108 @@ ], "time": "2017-10-19T19:58:43+00:00" }, + { + "name": "phar-io/manifest", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/2df402786ab5368a0169091f61a7c1e0eb6852d0", + "reference": "2df402786ab5368a0169091f61a7c1e0eb6852d0", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "phar-io/version": "^1.0.1", + "php": "^5.6 || ^7.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": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "time": "2017-03-05T18:14:27+00:00" + }, + { + "name": "phar-io/version", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/a70c0ced4be299a63d32fa96d9281d03e94041df", + "reference": "a70c0ced4be299a63d32fa96d9281d03e94041df", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "time": "2017-03-05T17:38:23+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "1.0.1", @@ -1210,29 +1602,35 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "4.1.1", + "version": "4.2.0", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2" + "reference": "66465776cfc249844bde6d117abff1d22e06c2da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2d3d238c433cf69caeb4842e97a3223a116f94b2", - "reference": "2d3d238c433cf69caeb4842e97a3223a116f94b2", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/66465776cfc249844bde6d117abff1d22e06c2da", + "reference": "66465776cfc249844bde6d117abff1d22e06c2da", "shasum": "" }, "require": { "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/reflection-common": "^1.0.0", "phpdocumentor/type-resolver": "^0.4.0", "webmozart/assert": "^1.0" }, "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^4.4" + "doctrine/instantiator": "~1.0.5", + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^6.4" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev" + } + }, "autoload": { "psr-4": { "phpDocumentor\\Reflection\\": [ @@ -1251,7 +1649,7 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-08-30T18:51:59+00:00" + "time": "2017-11-27T17:38:31+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -1302,16 +1700,16 @@ }, { "name": "phpspec/prophecy", - "version": "v1.7.2", + "version": "1.7.3", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6" + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", - "reference": "c9b8c6088acd19d769d4cc0ffa60a9fe34344bd6", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", + "reference": "e4ed002c67da8eceb0eb8ddb8b3847bb53c5c2bf", "shasum": "" }, "require": { @@ -1323,7 +1721,7 @@ }, "require-dev": { "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8 || ^5.6.5" + "phpunit/phpunit": "^4.8.35 || ^5.7" }, "type": "library", "extra": { @@ -1361,44 +1759,44 @@ "spy", "stub" ], - "time": "2017-09-04T11:05:03+00:00" + "time": "2017-11-24T13:59:53+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "4.0.8", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d" + "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ef7b2f56815df854e66ceaee8ebe9393ae36a40d", - "reference": "ef7b2f56815df854e66ceaee8ebe9393ae36a40d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/661f34d0bd3f1a7225ef491a70a020ad23a057a1", + "reference": "661f34d0bd3f1a7225ef491a70a020ad23a057a1", "shasum": "" }, "require": { "ext-dom": "*", "ext-xmlwriter": "*", - "php": "^5.6 || ^7.0", - "phpunit/php-file-iterator": "^1.3", - "phpunit/php-text-template": "^1.2", - "phpunit/php-token-stream": "^1.4.2 || ^2.0", - "sebastian/code-unit-reverse-lookup": "^1.0", - "sebastian/environment": "^1.3.2 || ^2.0", - "sebastian/version": "^1.0 || ^2.0" + "php": "^7.0", + "phpunit/php-file-iterator": "^1.4.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^2.0.1", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^3.0", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1" }, "require-dev": { - "ext-xdebug": "^2.1.4", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^6.0" }, "suggest": { - "ext-xdebug": "^2.5.1" + "ext-xdebug": "^2.5.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0.x-dev" + "dev-master": "5.3.x-dev" } }, "autoload": { @@ -1413,7 +1811,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1424,20 +1822,20 @@ "testing", "xunit" ], - "time": "2017-04-02T07:44:40+00:00" + "time": "2017-12-06T09:29:45+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.2", + "version": "1.4.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", - "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/730b01bc3e867237eaac355e06a36b85dd93a8b4", + "reference": "730b01bc3e867237eaac355e06a36b85dd93a8b4", "shasum": "" }, "require": { @@ -1471,48 +1869,7 @@ "filesystem", "iterator" ], - "time": "2016-10-03T07:40:28+00:00" - }, - { - "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-21T13:50:34+00:00" + "time": "2017-11-27T13:52:08+00:00" }, { "name": "phpunit/php-timer", @@ -1565,16 +1922,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0" + "reference": "791198a2c6254db10131eecfe8c06670700904db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/9a02332089ac48e704c70f6cefed30c224e3c0b0", - "reference": "9a02332089ac48e704c70f6cefed30c224e3c0b0", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/791198a2c6254db10131eecfe8c06670700904db", + "reference": "791198a2c6254db10131eecfe8c06670700904db", "shasum": "" }, "require": { @@ -1610,20 +1967,20 @@ "keywords": [ "tokenizer" ], - "time": "2017-08-20T05:47:52+00:00" + "time": "2017-11-27T05:48:46+00:00" }, { "name": "phpunit/phpunit", - "version": "5.7.23", + "version": "6.5.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "78532d5269d984660080d8e0f4c99c5c2ea65ffe" + "reference": "83d27937a310f2984fd575686138597147bdc7df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/78532d5269d984660080d8e0f4c99c5c2ea65ffe", - "reference": "78532d5269d984660080d8e0f4c99c5c2ea65ffe", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d27937a310f2984fd575686138597147bdc7df", + "reference": "83d27937a310f2984fd575686138597147bdc7df", "shasum": "" }, "require": { @@ -1632,33 +1989,35 @@ "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "~1.3", - "php": "^5.6 || ^7.0", - "phpspec/prophecy": "^1.6.2", - "phpunit/php-code-coverage": "^4.0.4", - "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.2.4", - "sebastian/diff": "^1.4.3", - "sebastian/environment": "^1.3.4 || ^2.0", - "sebastian/exporter": "~2.0", - "sebastian/global-state": "^1.1", - "sebastian/object-enumerator": "~2.0", - "sebastian/resource-operations": "~1.0", - "sebastian/version": "~1.0.3|~2.0", - "symfony/yaml": "~2.1|~3.0" + "myclabs/deep-copy": "^1.6.1", + "phar-io/manifest": "^1.0.1", + "phar-io/version": "^1.0", + "php": "^7.0", + "phpspec/prophecy": "^1.7", + "phpunit/php-code-coverage": "^5.3", + "phpunit/php-file-iterator": "^1.4.3", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^1.0.9", + "phpunit/phpunit-mock-objects": "^5.0.5", + "sebastian/comparator": "^2.1", + "sebastian/diff": "^2.0", + "sebastian/environment": "^3.1", + "sebastian/exporter": "^3.1", + "sebastian/global-state": "^2.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^1.0", + "sebastian/version": "^2.0.1" }, "conflict": { - "phpdocumentor/reflection-docblock": "3.0.2" + "phpdocumentor/reflection-docblock": "3.0.2", + "phpunit/dbunit": "<3.0" }, "require-dev": { "ext-pdo": "*" }, "suggest": { "ext-xdebug": "*", - "phpunit/php-invoker": "~1.1" + "phpunit/php-invoker": "^1.1" }, "bin": [ "phpunit" @@ -1666,7 +2025,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.7.x-dev" + "dev-master": "6.5.x-dev" } }, "autoload": { @@ -1692,33 +2051,33 @@ "testing", "xunit" ], - "time": "2017-10-15T06:13:55+00:00" + "time": "2017-12-17T06:31:19+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "3.4.4", + "version": "5.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118" + "reference": "283b9f4f670e3a6fd6c4ff95c51a952eb5c75933" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/a23b761686d50a560cc56233b9ecf49597cc9118", - "reference": "a23b761686d50a560cc56233b9ecf49597cc9118", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/283b9f4f670e3a6fd6c4ff95c51a952eb5c75933", + "reference": "283b9f4f670e3a6fd6c4ff95c51a952eb5c75933", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.6 || ^7.0", - "phpunit/php-text-template": "^1.2", - "sebastian/exporter": "^1.2 || ^2.0" + "doctrine/instantiator": "^1.0.5", + "php": "^7.0", + "phpunit/php-text-template": "^1.2.1", + "sebastian/exporter": "^3.1" }, "conflict": { - "phpunit/phpunit": "<5.4.0" + "phpunit/phpunit": "<6.0" }, "require-dev": { - "phpunit/phpunit": "^5.4" + "phpunit/phpunit": "^6.5" }, "suggest": { "ext-soap": "*" @@ -1726,7 +2085,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.2.x-dev" + "dev-master": "5.0.x-dev" } }, "autoload": { @@ -1741,7 +2100,7 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", + "email": "sebastian@phpunit.de", "role": "lead" } ], @@ -1751,47 +2110,19 @@ "mock", "xunit" ], - "time": "2017-06-30T09:13:00+00:00" + "time": "2017-12-10T08:01:53+00:00" }, { "name": "rg3/youtube-dl", - "version": "2017.10.20", + "version": "2017.12.10", "dist": { "type": "zip", - "url": "https://github.com/rg3/youtube-dl/archive/2017.10.20.zip", + "url": "https://github.com/rg3/youtube-dl/archive/2017.12.10.zip", "reference": null, "shasum": null }, "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-12T19:17:32+00:00" - }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -1839,30 +2170,30 @@ }, { "name": "sebastian/comparator", - "version": "1.2.4", + "version": "2.1.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", - "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b11c729f95109b56a0fe9650c6a63a0fcd8c439f", + "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2 || ~2.0" + "php": "^7.0", + "sebastian/diff": "^2.0", + "sebastian/exporter": "^3.1" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.1.x-dev" } }, "autoload": { @@ -1893,38 +2224,38 @@ } ], "description": "Provides the functionality to compare PHP values for equality", - "homepage": "http://www.github.com/sebastianbergmann/comparator", + "homepage": "https://github.com/sebastianbergmann/comparator", "keywords": [ "comparator", "compare", "equality" ], - "time": "2017-01-29T09:50:25+00:00" + "time": "2017-12-22T14:50:35+00:00" }, { "name": "sebastian/diff", - "version": "1.4.3", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", - "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", + "reference": "347c1d8b49c5c3ee30c7040ea6fc446790e6bddd", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + "phpunit/phpunit": "^6.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1951,32 +2282,32 @@ "keywords": [ "diff" ], - "time": "2017-05-22T07:24:03+00:00" + "time": "2017-08-03T08:09:46+00:00" }, { "name": "sebastian/environment", - "version": "2.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", - "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/cd0871b3975fb7fc44d11314fd1ee20925fce4f5", + "reference": "cd0871b3975fb7fc44d11314fd1ee20925fce4f5", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "^5.0" + "phpunit/phpunit": "^6.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -2001,34 +2332,34 @@ "environment", "hhvm" ], - "time": "2016-11-26T07:53:53+00:00" + "time": "2017-07-01T08:51:00+00:00" }, { "name": "sebastian/exporter", - "version": "2.0.0", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", - "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", + "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", "shasum": "" }, "require": { - "php": ">=5.3.3", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/recursion-context": "^3.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.1.x-dev" } }, "autoload": { @@ -2068,27 +2399,27 @@ "export", "exporter" ], - "time": "2016-11-19T08:54:04+00:00" + "time": "2017-04-03T13:19:02+00:00" }, { "name": "sebastian/global-state", - "version": "1.1.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", - "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.2" + "phpunit/phpunit": "^6.0" }, "suggest": { "ext-uopz": "*" @@ -2096,7 +2427,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -2119,33 +2450,34 @@ "keywords": [ "global state" ], - "time": "2015-10-12T03:26:01+00:00" + "time": "2017-04-27T15:39:26+00:00" }, { "name": "sebastian/object-enumerator", - "version": "2.0.1", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7" + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1311872ac850040a79c3c058bea3e22d0f09cbb7", - "reference": "1311872ac850040a79c3c058bea3e22d0f09cbb7", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", "shasum": "" }, "require": { - "php": ">=5.6", - "sebastian/recursion-context": "~2.0" + "php": "^7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" }, "require-dev": { - "phpunit/phpunit": "~5" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -2165,32 +2497,77 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-02-18T15:18:39+00:00" + "time": "2017-08-03T12:35:26+00:00" }, { - "name": "sebastian/recursion-context", - "version": "2.0.0", + "name": "sebastian/object-reflector", + "version": "1.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "773f97c67f28de00d397be301821b06708fca0be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", - "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", + "reference": "773f97c67f28de00d397be301821b06708fca0be", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "time": "2017-03-29T09:07:27+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" } }, "autoload": { @@ -2218,7 +2595,7 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2016-11-19T07:33:16+00:00" + "time": "2017-03-03T06:23:57+00:00" }, { "name": "sebastian/resource-operations", @@ -2307,16 +2684,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.1.1", + "version": "3.2.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "d667e245d5dcd4d7bf80f26f2c947d476b66213e" + "reference": "d7c00c3000ac0ce79c96fcbfef86b49a71158cd1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d667e245d5dcd4d7bf80f26f2c947d476b66213e", - "reference": "d667e245d5dcd4d7bf80f26f2c947d476b66213e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7c00c3000ac0ce79c96fcbfef86b49a71158cd1", + "reference": "d7c00c3000ac0ce79c96fcbfef86b49a71158cd1", "shasum": "" }, "require": { @@ -2354,7 +2731,7 @@ "phpcs", "standards" ], - "time": "2017-10-16T22:40:25+00:00" + "time": "2017-12-19T21:44:46+00:00" }, { "name": "symfony/polyfill-mbstring", @@ -2417,16 +2794,16 @@ }, { "name": "symfony/var-dumper", - "version": "v3.3.10", + "version": "v3.4.2", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "03e3693a36701f1c581dd24a6d6eea2eba2113f6" + "reference": "757074cf71b952ce9e75b557538948811c2bf006" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/03e3693a36701f1c581dd24a6d6eea2eba2113f6", - "reference": "03e3693a36701f1c581dd24a6d6eea2eba2113f6", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/757074cf71b952ce9e75b557538948811c2bf006", + "reference": "757074cf71b952ce9e75b557538948811c2bf006", "shasum": "" }, "require": { @@ -2442,12 +2819,13 @@ }, "suggest": { "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", "ext-symfony_debug": "" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.3-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -2481,7 +2859,47 @@ "debug", "dump" ], - "time": "2017-10-02T06:42:24+00:00" + "time": "2017-12-11T22:06:16+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "time": "2017-04-07T12:08:54+00:00" }, { "name": "webmozart/assert", @@ -2536,9 +2954,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "ffmpeg/ffmpeg": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/config/config.example.yml b/config/config.example.yml index 9470464..25d0469 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -7,10 +7,10 @@ python: /usr/bin/python # An array of parameters to pass to youtube-dl params: - - --no-playlist - --no-warnings - - --playlist-end - - 1 + - --ignore-errors + - --flat-playlist + - --restrict-filenames # True to enable audio conversion convert: false @@ -18,11 +18,14 @@ convert: false # Path to your avconv or ffmpeg binary avconv: vendor/bin/ffmpeg -# Path to your rtmpdump binary -rtmpdump: vendor/bin/rtmpdump +# avconv/ffmpeg logging level. +avconvVerbosity: error # True to disable URL rewriting uglyUrls: false # True to stream videos through server stream: false + +# MP3 bitrate when converting (in kbit/s) +audioBitrate: 128 diff --git a/config/config_test.yml b/config/config_test.yml index 8968c0f..99b704b 100644 --- a/config/config_test.yml +++ b/config/config_test.yml @@ -1,2 +1,3 @@ --- convert: false +avconvVerbosity: fatal diff --git a/config/config_test_windows.yml b/config/config_test_windows.yml new file mode 100644 index 0000000..1098072 --- /dev/null +++ b/config/config_test_windows.yml @@ -0,0 +1,12 @@ +--- +convert: false +python: C:\Python36\python.exe +avconv: C:\ProgramData\chocolatey\bin\ffmpeg.exe +avconvVerbosity: fatal +youtubedl: C:\Python36\Lib\site-packages\youtube_dl\__main__.py +params: + - --no-warnings + - --ignore-errors + - --flat-playlist + - --restrict-filenames + - --no-check-certificate diff --git a/controllers/FrontController.php b/controllers/FrontController.php index 87d8b02..711f474 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -7,6 +7,7 @@ namespace Alltube\Controller; use Alltube\Config; use Alltube\Locale; +use Alltube\LocaleManager; use Alltube\PasswordException; use Alltube\VideoDownload; use Psr\Container\ContainerInterface; @@ -83,7 +84,7 @@ class FrontController } else { $this->config = Config::getInstance(); } - $this->download = new VideoDownload(); + $this->download = new VideoDownload($this->config); $this->container = $container; $this->view = $this->container->get('view'); $this->localeManager = $this->container->get('locale'); @@ -360,7 +361,7 @@ class FrontController $stream = $this->download->getRtmpStream($video); $response = $response->withHeader('Content-Type', 'video/'.$video->ext); $body = new Stream($stream); - } elseif ($video->protocol == 'm3u8') { + } elseif ($video->protocol == 'm3u8' || $video->protocol == 'm3u8_native') { $stream = $this->download->getM3uStream($video); $response = $response->withHeader('Content-Type', 'video/'.$video->ext); $body = new Stream($stream); diff --git a/package.json b/package.json index 41adff1..a5491a6 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,32 @@ { "name": "alltube", "description": "HTML GUI for youtube-dl", - "version": "0.10.2", + "version": "0.11.0", "author": "Pierre Rudloff", "bugs": "https://github.com/Rudloff/alltube/issues", "dependencies": { "grunt": "~1.0.1", - "grunt-contrib-csslint": "~2.0.0", "grunt-contrib-cssmin": "~2.2.1", - "grunt-contrib-uglify": "~3.1.0", + "grunt-contrib-uglify": "~3.2.1", "grunt-potomo": "~3.5.0", "open-sans-fontface": "~1.4.0" }, "devDependencies": { "grunt-contrib-compress": "~1.4.1", + "grunt-contrib-csslint": "~2.0.0", "grunt-contrib-watch": "~1.0.0", "grunt-fixpack": "~0.1.0", "grunt-githash": "~0.1.3", "grunt-jslint": "~1.1.15", "grunt-jsonlint": "~1.1.0", + "grunt-markdownlint": "~1.0.43", "grunt-phpcs": "~0.4.0", "grunt-phpdocumentor": "~0.4.1", "grunt-phpunit": "~0.3.6" }, "engines": { - "yarn": ">= 1.0.0" + "npm": "~3", + "yarn": "~1" }, "homepage": "https://www.alltubedownload.net/", "keywords": [ @@ -34,7 +36,7 @@ "youtube" ], "license": "GPL-3.0", - "main": "index.php", + "main": "Gruntfile.js", "repository": { "type": "git", "url": "https://github.com/Rudloff/alltube.git" diff --git a/resources/FAQ.md b/resources/FAQ.md index d09652b..4aa3a35 100644 --- a/resources/FAQ.md +++ b/resources/FAQ.md @@ -4,7 +4,8 @@ ## 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. +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? @@ -17,7 +18,6 @@ Here are the parameters that you can set: * `params`: an array of parameters to pass to youtube-dl * `convert`: true to enable audio conversion * `avconv`: path to your avconv or ffmpeg binary -* `rtmpdump`: path to your rtmpdump binary * `remux`: enable remux mode (experimental) See [`config.example.yml`](../config/config.example.yml) for default values. @@ -56,13 +56,16 @@ Then push the code to Heroku and it should work out of the box. ## Why can't I download videos from some websites (e.g. Dailymotion) -Some websites generate an unique video URL for each IP address. When using Alltube, the URL is generated for our server's IP address and your computer is not allowed to use it. +Some websites generate an unique video URL for each IP address. +When using Alltube, the URL is generated for our server's IP address +and your computer is not allowed to use it. There are two known workarounds: * You can run Alltube locally on your computer. * You can enable streaming videos through the server (see below). - Please note that this can use a lot of resources on the server (which is why we won't enable it on alltubedownload.net). + 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 @@ -74,7 +77,8 @@ You need to either: ## I get a 404 error on every page except the index -This is probably because your server does not have mod_rewrite or AllowOverride is disabled. +This is probably because your server does not have mod_rewrite +or AllowOverride is disabled. You can work around this by adding this to your `config.yml` file: ```yaml @@ -101,7 +105,8 @@ Alltube can rename videos automatically if you enable streaming (see above). ## I want to download a video that isn't available in my country -If the video is available in the server's country, you can download it if you enable streaming (see above). +If the video is available in the server's country, +you can download it if you enable streaming (see above). ## How do I run the Docker image? @@ -114,7 +119,9 @@ docker run -p 8080:80 rudloff/alltube You should be able to use `heroku local` like this: ```bash -sudo APACHE_LOCK_DIR=. APACHE_PID_FILE=./pid APACHE_RUN_USER=www-data APACHE_RUN_GROUP=www-data APACHE_LOG_DIR=. heroku local +sudo APACHE_LOCK_DIR=. APACHE_PID_FILE=./pid APACHE_RUN_USER=www-data \ + APACHE_RUN_GROUP=www-data APACHE_LOG_DIR=. \ + heroku local ``` You might need to create some symlinks before that: @@ -124,7 +131,8 @@ ln -s /usr/sbin/apache2 /usr/sbin/httpd ln -s /usr/sbin/php-fpm7.0 /usr/sbin/php-fpm ``` -And you probably need to run this in another terminal after `heroku local` has finished launching `php-fpm`: +And you probably need to run this in another terminal +after `heroku local` has finished launching `php-fpm`: ```bash chmod 0667 /tmp/heroku.fcgi.5000.sock @@ -137,4 +145,5 @@ So Alltube will offer you video-only and audio-only formats in the format list. You then need to merge them together with a tool like ffmpeg. -You can also enable the experimental remux mode that will merge the best video and the best audio format on the fly. +You can also enable the experimental remux mode +that will merge the best video and the best audio format on the fly. diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index f37935c..b9223f6 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -6,11 +6,12 @@ namespace Alltube\Test; use Alltube\Config; +use PHPUnit\Framework\TestCase; /** * Unit tests for the Config class. */ -class ConfigTest extends \PHPUnit_Framework_TestCase +class ConfigTest extends TestCase { /** * Config class instance. @@ -45,11 +46,27 @@ class ConfigTest extends \PHPUnit_Framework_TestCase public function testGetInstance() { $this->assertEquals($this->config->convert, false); - $this->assertInternalType('array', $this->config->params); - $this->assertInternalType('string', $this->config->youtubedl); - $this->assertInternalType('string', $this->config->python); - $this->assertInternalType('string', $this->config->avconv); - $this->assertInternalType('string', $this->config->rtmpdump); + $this->assertConfig($this->config); + } + + /** + * Assert that a Config object is correctly instantiated. + * + * @param Config $config Config class instance. + * + * @return void + */ + private function assertConfig(Config $config) + { + $this->assertInternalType('array', $config->params); + $this->assertInternalType('string', $config->youtubedl); + $this->assertInternalType('string', $config->python); + $this->assertInternalType('string', $config->avconv); + $this->assertInternalType('bool', $config->convert); + $this->assertInternalType('bool', $config->uglyUrls); + $this->assertInternalType('bool', $config->stream); + $this->assertInternalType('bool', $config->remux); + $this->assertInternalType('int', $config->audioBitrate); } /** @@ -64,13 +81,14 @@ class ConfigTest extends \PHPUnit_Framework_TestCase } /** - * Test the getInstance function with aen empty filename. + * Test the getInstance function with an empty filename. * * @return void */ public function testGetInstanceWithEmptyFile() { - Config::getInstance(''); + $config = Config::getInstance(''); + $this->assertConfig($config); } /** diff --git a/tests/FrontControllerTest.php b/tests/FrontControllerTest.php index d14e5f6..2390798 100644 --- a/tests/FrontControllerTest.php +++ b/tests/FrontControllerTest.php @@ -9,6 +9,7 @@ use Alltube\Config; use Alltube\Controller\FrontController; use Alltube\LocaleManager; use Alltube\ViewFactory; +use PHPUnit\Framework\TestCase; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -17,7 +18,7 @@ use Slim\Http\Response; /** * Unit tests for the FrontController class. */ -class FrontControllerTest extends \PHPUnit_Framework_TestCase +class FrontControllerTest extends TestCase { /** * Slim dependency container. @@ -47,6 +48,13 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ private $controller; + /** + * Config class instance. + * + * @var Config + */ + private $config; + /** * Prepare tests. */ @@ -57,7 +65,15 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase $this->response = new Response(); $this->container['view'] = ViewFactory::create($this->container, $this->request); $this->container['locale'] = new LocaleManager(); - $this->controller = new FrontController($this->container, Config::getInstance('config/config_test.yml')); + + if (PHP_OS == 'WINNT') { + $configFile = 'config_test_windows.yml'; + } else { + $configFile = 'config_test.yml'; + } + $this->config = Config::getInstance('config/'.$configFile); + $this->controller = new FrontController($this->container, $this->config); + $this->container['router']->map(['GET'], '/', [$this->controller, 'index']) ->setName('index'); $this->container['router']->map(['GET'], '/video', [$this->controller, 'video']) @@ -149,6 +165,18 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase * @return void */ public function testConstructor() + { + $controller = new FrontController($this->container, $this->config); + $this->assertInstanceOf(FrontController::class, $controller); + } + + /** + * Test the constructor with a default config. + * + * @return void + * @requires OS Linux + */ + public function testConstructorWithDefaultConfig() { $controller = new FrontController($this->container); $this->assertInstanceOf(FrontController::class, $controller); @@ -161,7 +189,8 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testConstructorWithStream() { - $controller = new FrontController($this->container, new Config(['stream' => true])); + $this->config->stream = true; + $controller = new FrontController($this->container, $this->config); $this->assertInstanceOf(FrontController::class, $controller); } @@ -231,17 +260,6 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase $this->assertRequestIsOk('video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU']); } - /** - * Test the video() function with a video that does not have a title. - * - * @return void - */ - public function testVideoWithoutTitle() - { - $this->markTestSkipped('This URL triggers a curl SSL error on Travis'); - $this->assertRequestIsOk('video', ['url' => 'http://html5demos.com/video']); - } - /** * Test the video() function with audio conversion. * @@ -261,7 +279,10 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase { $this->assertRequestIsRedirect( 'video', - ['url' => 'https://2080.bandcamp.com/track/cygnus-x-the-orange-theme-2080-faulty-chip-cover', 'audio' => true] + [ + 'url' => 'https://2080.bandcamp.com/track/cygnus-x-the-orange-theme-2080-faulty-chip-cover', + 'audio' => true, + ] ); } @@ -298,12 +319,12 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testVideoWithStream() { - $config = new Config(['stream' => true]); - $this->assertRequestIsOk('video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU'], $config); + $this->config->stream = true; + $this->assertRequestIsOk('video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU'], $this->config); $this->assertRequestIsOk( 'video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'audio' => true], - $config + $this->config ); } @@ -371,10 +392,11 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testRedirectWithStream() { + $this->config->stream = true; $this->assertRequestIsOk( 'redirect', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU'], - new Config(['stream' => true]) + $this->config ); } @@ -385,10 +407,14 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testRedirectWithM3uStream() { + $this->config->stream = true; $this->assertRequestIsOk( 'redirect', - ['url' => 'https://twitter.com/verge/status/813055465324056576/video/1'], - new Config(['stream' => true]) + [ + 'url' => 'https://twitter.com/verge/status/813055465324056576/video/1', + 'format' => 'hls-2176', + ], + $this->config ); } @@ -399,10 +425,11 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testRedirectWithRtmpStream() { + $this->config->stream = true; $this->assertRequestIsOk( 'redirect', ['url' => 'http://www.canalc2.tv/video/12163', 'format' => 'rtmp'], - new Config(['stream' => true]) + $this->config ); } @@ -413,13 +440,14 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase */ public function testRedirectWithRemux() { + $this->config->remux = true; $this->assertRequestIsOk( 'redirect', [ 'url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'format' => 'bestvideo+bestaudio', ], - new Config(['remux' => true]) + $this->config ); } @@ -477,13 +505,15 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase * Test the redirect() function with a playlist stream. * * @return void + * @requires OS Linux */ public function testRedirectWithPlaylist() { + $this->config->stream = true; $this->assertRequestIsOk( 'redirect', ['url' => 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC'], - new Config(['stream' => true]) + $this->config ); } diff --git a/tests/LocaleManagerTest.php b/tests/LocaleManagerTest.php index 693346f..ae9cb14 100644 --- a/tests/LocaleManagerTest.php +++ b/tests/LocaleManagerTest.php @@ -7,11 +7,12 @@ namespace Alltube\Test; use Alltube\Locale; use Alltube\LocaleManager; +use PHPUnit\Framework\TestCase; /** * Unit tests for the Config class. */ -class LocaleManagerTest extends \PHPUnit_Framework_TestCase +class LocaleManagerTest extends TestCase { /** * LocaleManager class instance. @@ -26,6 +27,7 @@ class LocaleManagerTest extends \PHPUnit_Framework_TestCase protected function setUp() { $this->localeManager = new LocaleManager(); + $_SESSION['Alltube\LocaleManager']['locale'] = 'foo_BAR'; } /** @@ -35,7 +37,6 @@ class LocaleManagerTest extends \PHPUnit_Framework_TestCase */ public function testConstructorWithCookies() { - $_SESSION['Alltube\LocaleManager']['locale'] = 'foo_BAR'; $localeManager = new LocaleManager([]); $this->assertEquals('foo_BAR', (string) $localeManager->getLocale()); } @@ -59,7 +60,7 @@ class LocaleManagerTest extends \PHPUnit_Framework_TestCase */ public function testGetLocale() { - $this->assertNull($this->localeManager->getLocale()); + $this->assertEquals(new Locale('foo_BAR'), $this->localeManager->getLocale()); } /** @@ -74,4 +75,26 @@ class LocaleManagerTest extends \PHPUnit_Framework_TestCase $this->assertInstanceOf(Locale::class, $locale); $this->assertEquals('foo_BAR', (string) $locale); } + + /** + * Test the unsetLocale function. + * + * @return void + */ + public function testUnsetLocale() + { + $this->localeManager->unsetLocale(); + $this->assertNull($this->localeManager->getLocale()); + } + + /** + * Test that the environment is correctly set up. + * + * @return void + */ + public function testEnv() + { + $this->localeManager->setLocale(new Locale('foo_BAR')); + $this->assertEquals('foo_BAR', getenv('LANG')); + } } diff --git a/tests/LocaleMiddlewareTest.php b/tests/LocaleMiddlewareTest.php index 930455b..f7455fd 100644 --- a/tests/LocaleMiddlewareTest.php +++ b/tests/LocaleMiddlewareTest.php @@ -5,8 +5,10 @@ namespace Alltube\Test; +use Alltube\Locale; use Alltube\LocaleManager; use Alltube\LocaleMiddleware; +use PHPUnit\Framework\TestCase; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -15,7 +17,7 @@ use Slim\Http\Response; /** * Unit tests for the FrontController class. */ -class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase +class LocaleMiddlewareTest extends TestCase { /** * LocaleMiddleware instance. @@ -24,29 +26,46 @@ class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase */ private $middleware; + /** + * Slim dependency container. + * + * @var Container + */ + private $container; + /** * Prepare tests. */ protected function setUp() { - $container = new Container(); - $container['locale'] = new LocaleManager(); - $this->middleware = new LocaleMiddleware($container); + $this->container = new Container(); + $this->container['locale'] = new LocaleManager(); + $this->middleware = new LocaleMiddleware($this->container); + } + + /** + * Unset locale cookie after each test. + * + * @return void + */ + protected function tearDown() + { + $this->container['locale']->unsetLocale(); } /** * Test the testLocale() function. * * @return void + * @requires OS Linux */ public function testTestLocale() { - $this->markTestSkipped('For some reason, this test fails on Travis even if the fr_FR locale is installed.'); $locale = [ - 'language' => 'fr', - 'region' => 'FR', + 'language' => 'en', + 'region' => 'US', ]; - $this->assertEquals('fr_FR', $this->middleware->testLocale($locale)); + $this->assertEquals('en_US', $this->middleware->testLocale($locale)); } /** @@ -65,12 +84,29 @@ class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase } /** - * Mock function that does nothing. + * Check that the request contains an Accept-Language header. + * + * @param Request $request PSR-7 request * * @return void */ - public function nothing() + public function assertHeader(Request $request) { + $header = $request->getHeader('Accept-Language'); + $this->assertEquals('foo-BAR', $header[0]); + } + + /** + * Check that the request contains no Accept-Language header. + * + * @param Request $request PSR-7 request + * + * @return void + */ + public function assertNoHeader(Request $request) + { + $header = $request->getHeader('Accept-Language'); + $this->assertEmpty($header); } /** @@ -82,14 +118,14 @@ class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase { $request = Request::createFromEnvironment(Environment::mock()); $this->middleware->__invoke( - $request->withHeader('Accept-Language', 'fr-FR'), + $request->withHeader('Accept-Language', 'foo-BAR'), new Response(), - [$this, 'nothing'] + [$this, 'assertHeader'] ); } /** - * Test the __invoke() function withot the Accept-Language header. + * Test the __invoke() function without the Accept-Language header. * * @return void */ @@ -99,17 +135,7 @@ class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase $this->middleware->__invoke( $request->withoutHeader('Accept-Language'), new Response(), - [$this, 'nothing'] + [$this, 'assertNoHeader'] ); } - - /** - * Test that the environment is correctly set up. - * - * @return void - */ - public function testEnv() - { - $this->markTestIncomplete('We need to find a way to reliably test LC_ALL and LANG values'); - } } diff --git a/tests/LocaleTest.php b/tests/LocaleTest.php index 9581248..3651b22 100644 --- a/tests/LocaleTest.php +++ b/tests/LocaleTest.php @@ -6,25 +6,26 @@ namespace Alltube\Test; use Alltube\Locale; +use PHPUnit\Framework\TestCase; /** * Unit tests for the Config class. */ -class LocaleTest extends \PHPUnit_Framework_TestCase +class LocaleTest extends TestCase { /** * Locale class instance. * * @var Locale */ - private $locale; + private $localeObject; /** * Prepare tests. */ protected function setUp() { - $this->locale = new Locale('fr_FR'); + $this->localeObject = new Locale('fr_FR'); } /** @@ -34,7 +35,7 @@ class LocaleTest extends \PHPUnit_Framework_TestCase */ public function testGetToString() { - $this->assertEquals('fr_FR', $this->locale->__toString()); + $this->assertEquals('fr_FR', $this->localeObject->__toString()); } /** @@ -44,7 +45,7 @@ class LocaleTest extends \PHPUnit_Framework_TestCase */ public function testGetFullName() { - $this->assertEquals('français (France)', $this->locale->getFullName()); + $this->assertEquals('français (France)', $this->localeObject->getFullName()); } /** @@ -54,7 +55,7 @@ class LocaleTest extends \PHPUnit_Framework_TestCase */ public function testGetIso15897() { - $this->assertEquals('fr_FR', $this->locale->getIso15897()); + $this->assertEquals('fr_FR', $this->localeObject->getIso15897()); } /** @@ -64,7 +65,7 @@ class LocaleTest extends \PHPUnit_Framework_TestCase */ public function testGetBcp47() { - $this->assertEquals('fr-FR', $this->locale->getBcp47()); + $this->assertEquals('fr-FR', $this->localeObject->getBcp47()); } /** @@ -74,6 +75,6 @@ class LocaleTest extends \PHPUnit_Framework_TestCase */ public function testGetIso3166() { - $this->assertEquals('fr', $this->locale->getIso3166()); + $this->assertEquals('fr', $this->localeObject->getIso3166()); } } diff --git a/tests/PlaylistArchiveStreamTest.php b/tests/PlaylistArchiveStreamTest.php index 349f98a..fde76c6 100644 --- a/tests/PlaylistArchiveStreamTest.php +++ b/tests/PlaylistArchiveStreamTest.php @@ -5,12 +5,14 @@ namespace Alltube\Test; +use Alltube\Config; use Alltube\PlaylistArchiveStream; +use PHPUnit\Framework\TestCase; /** * Unit tests for the ViewFactory class. */ -class PlaylistArchiveStreamTest extends \PHPUnit_Framework_TestCase +class PlaylistArchiveStreamTest extends TestCase { /** * PlaylistArchiveStream instance. @@ -24,7 +26,12 @@ class PlaylistArchiveStreamTest extends \PHPUnit_Framework_TestCase */ protected function setUp() { - $this->stream = new PlaylistArchiveStream(); + if (PHP_OS == 'WINNT') { + $configFile = 'config_test_windows.yml'; + } else { + $configFile = 'config_test.yml'; + } + $this->stream = new PlaylistArchiveStream(Config::getInstance('config/'.$configFile)); } /** @@ -88,7 +95,11 @@ class PlaylistArchiveStreamTest extends \PHPUnit_Framework_TestCase { $this->stream->stream_open('playlist://BaW_jenozKc;BaW_jenozKc/worst'); while (!$this->stream->stream_eof()) { - $this->assertLessThanOrEqual(8192, strlen($this->stream->stream_read(8192))); + $result = $this->stream->stream_read(8192); + $this->assertInternalType('string', $result); + if (is_string($result)) { + $this->assertLessThanOrEqual(8192, strlen($result)); + } } } diff --git a/tests/UglyRouterTest.php b/tests/UglyRouterTest.php index 4d21b3e..541b78d 100644 --- a/tests/UglyRouterTest.php +++ b/tests/UglyRouterTest.php @@ -6,13 +6,14 @@ namespace Alltube\Test; use Alltube\UglyRouter; +use PHPUnit\Framework\TestCase; use Slim\Http\Environment; use Slim\Http\Request; /** * Unit tests for the UglyRouter class. */ -class UglyRouterTest extends \PHPUnit_Framework_TestCase +class UglyRouterTest extends TestCase { /** * UglyRouter instance. diff --git a/tests/VideoDownloadStubsTest.php b/tests/VideoDownloadStubsTest.php new file mode 100644 index 0000000..8db9d0b --- /dev/null +++ b/tests/VideoDownloadStubsTest.php @@ -0,0 +1,127 @@ +config = Config::getInstance('config/'.$configFile); + $this->download = new VideoDownload($this->config); + $this->url = 'https://www.youtube.com/watch?v=XJC9_JkzugE'; + } + + /** + * Remove stubs. + * + * @return void + */ + protected function tearDown() + { + Mockery::close(); + } + + /** + * Test getAudioStream function with a buggy popen. + * + * @return void + * @expectedException Exception + */ + public function testGetAudioStreamWithPopenError() + { + $this->download->getAudioStream($this->url, 'best'); + } + + /** + * Test getM3uStream function with a buggy popen. + * + * @return void + * @expectedException Exception + */ + public function testGetM3uStreamWithPopenError() + { + $this->download->getM3uStream($this->download->getJSON($this->url, 'best')); + } + + /** + * Test getRtmpStream function with a buggy popen. + * + * @return void + * @expectedException Exception + */ + public function testGetRtmpStreamWithPopenError() + { + $this->download->getRtmpStream($this->download->getJSON($this->url, 'best')); + } + + /** + * Test getRemuxStream function with a buggy popen. + * + * @return void + * @expectedException Exception + */ + public function testGetRemuxStreamWithPopenError() + { + $this->download->getRemuxStream([$this->url, $this->url]); + } + + /** + * Test getPlaylistArchiveStream function with a buggy popen. + * + * @return void + * @expectedException Exception + */ + public function testGetPlaylistArchiveStreamWithPopenError() + { + $video = $this->download->getJSON( + 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC', + 'best' + ); + $this->download->getPlaylistArchiveStream($video, 'best'); + } +} diff --git a/tests/VideoDownloadTest.php b/tests/VideoDownloadTest.php index c0c62f9..b4e6767 100644 --- a/tests/VideoDownloadTest.php +++ b/tests/VideoDownloadTest.php @@ -7,11 +7,12 @@ namespace Alltube\Test; use Alltube\Config; use Alltube\VideoDownload; +use PHPUnit\Framework\TestCase; /** * Unit tests for the VideoDownload class. */ -class VideoDownloadTest extends \PHPUnit_Framework_TestCase +class VideoDownloadTest extends TestCase { /** * VideoDownload instance. @@ -20,12 +21,25 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ private $download; + /** + * Config class instance. + * + * @var Config + */ + private $config; + /** * Initialize properties used by test. */ protected function setUp() { - $this->download = new VideoDownload(Config::getInstance('config/config_test.yml')); + if (PHP_OS == 'WINNT') { + $configFile = 'config_test_windows.yml'; + } else { + $configFile = 'config_test.yml'; + } + $this->config = Config::getInstance('config/'.$configFile); + $this->download = new VideoDownload($this->config); } /** @@ -44,9 +58,8 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testConstructorWithMissingYoutubedl() { - new VideoDownload( - new Config(['youtubedl' => 'foo']) - ); + $this->config->youtubedl = 'foo'; + new VideoDownload($this->config); } /** @@ -57,9 +70,8 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testConstructorWithMissingPython() { - new VideoDownload( - new Config(['python' => 'foo']) - ); + $this->config->python = 'foo'; + new VideoDownload($this->config); } /** @@ -88,8 +100,13 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase * @dataProvider rtmpUrlProvider * @dataProvider remuxUrlProvider */ - public function testGetURL($url, $format, $filename, $extension, $domain) - { + public function testGetURL( + $url, + $format, + /* @scrutinizer ignore-unused */ $filename, + /* @scrutinizer ignore-unused */ $extension, + $domain + ) { $videoURL = $this->download->getURL($url, $format); $this->assertContains($domain, $videoURL[0]); } @@ -209,7 +226,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase { return [ [ - 'https://twitter.com/verge/status/813055465324056576/video/1', 'best', + 'https://twitter.com/verge/status/813055465324056576/video/1', 'hls-2176', 'The_Verge_-_This_tiny_origami_robot_can_self-fold_and_complete_tasks-813055465324056576', 'mp4', 'video.twimg.com', @@ -363,23 +380,8 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetAudioStreamAvconvError($url, $format) { - $download = new VideoDownload(new Config(['avconv' => 'foobar'])); - $download->getAudioStream($url, $format); - } - - /** - * Test getAudioStream function without curl or rtmpdump. - * - * @param string $url URL - * @param string $format Format - * - * @return void - * @expectedException Exception - * @dataProvider rtmpUrlProvider - */ - public function testGetAudioStreamRtmpError($url, $format) - { - $download = new VideoDownload(new Config(['rtmpdump' => 'foobar'])); + $this->config->avconv = 'foobar'; + $download = new VideoDownload($this->config); $download->getAudioStream($url, $format); } @@ -476,7 +478,8 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase */ public function testGetM3uStreamAvconvError($url, $format) { - $download = new VideoDownload(new Config(['avconv' => 'foobar'])); + $this->config->avconv = 'foobar'; + $download = new VideoDownload($this->config); $video = $download->getJSON($url, $format); $download->getM3uStream($video); } @@ -485,6 +488,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase * Test getPlaylistArchiveStream function without avconv. * * @return void + * @requires OS Linux */ public function testGetPlaylistArchiveStream() { diff --git a/tests/ViewFactoryTest.php b/tests/ViewFactoryTest.php index 552ed9f..285340f 100644 --- a/tests/ViewFactoryTest.php +++ b/tests/ViewFactoryTest.php @@ -6,6 +6,7 @@ namespace Alltube\Test; use Alltube\ViewFactory; +use PHPUnit\Framework\TestCase; use Slim\Container; use Slim\Http\Environment; use Slim\Http\Request; @@ -14,7 +15,7 @@ use Slim\Views\Smarty; /** * Unit tests for the ViewFactory class. */ -class ViewFactoryTest extends \PHPUnit_Framework_TestCase +class ViewFactoryTest extends TestCase { /** * Test the create() function. diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 634e02a..4f64daf 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -3,12 +3,21 @@ * File used to bootstrap tests. */ use Alltube\PlaylistArchiveStream; +use phpmock\mockery\PHPMockery; /** * Composer autoload. */ require_once __DIR__.'/../vendor/autoload.php'; +ini_set('session.use_cookies', 0); +session_cache_limiter(''); session_start(); stream_wrapper_register('playlist', PlaylistArchiveStream::class); + +/* + * @see https://bugs.php.net/bug.php?id=68541 + */ +PHPMockery::define('Alltube', 'popen'); +PHPMockery::define('Alltube', 'fopen'); diff --git a/yarn.lock b/yarn.lock index d7a5009..b71c9f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11,13 +11,13 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" ajv@^5.1.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" + version "5.3.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" - json-stable-stringify "^1.0.1" alce@1.0.0: version "1.0.0" @@ -74,7 +74,7 @@ are-we-there-yet@~1.1.2: delegates "^1.0.0" readable-stream "^2.0.6" -argparse@^1.0.2: +argparse@^1.0.2, argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: @@ -269,9 +269,9 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -commander@~2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" +commander@~2.12.1: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" compress-commons@^1.2.0: version "1.2.2" @@ -403,6 +403,10 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" +entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + error-ex@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" @@ -453,6 +457,10 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + faye-websocket@~0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -636,13 +644,13 @@ grunt-contrib-cssmin@~2.2.1: clean-css "~4.1.1" maxmin "^2.1.0" -grunt-contrib-uglify@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/grunt-contrib-uglify/-/grunt-contrib-uglify-3.1.0.tgz#10d1e4849210ec92bf0b08247e24186354d5e9ee" +grunt-contrib-uglify@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/grunt-contrib-uglify/-/grunt-contrib-uglify-3.2.1.tgz#8458943eb6053badff829b6f0c9126b1ea624c4a" dependencies: chalk "^1.0.0" maxmin "^1.1.0" - uglify-js "~3.0.4" + uglify-js "~3.2.0" uri-path "^1.0.0" grunt-contrib-watch@~1.0.0: @@ -713,6 +721,12 @@ grunt-legacy-util@~1.0.0: underscore.string "~3.2.3" which "~1.2.1" +grunt-markdownlint@~1.0.43: + version "1.0.43" + resolved "https://registry.yarnpkg.com/grunt-markdownlint/-/grunt-markdownlint-1.0.43.tgz#afcd3bbab5a5a293bf0050010a7fa9fdea38eca6" + dependencies: + markdownlint "^0.6.1" + grunt-phpcs@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/grunt-phpcs/-/grunt-phpcs-0.4.0.tgz#a08d625fc64465e453b2bd93f810b2a81e94bdaa" @@ -942,20 +956,10 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - dependencies: - jsonify "~0.0.0" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - jsonlint@1.6.2: version "1.6.2" resolved "https://registry.yarnpkg.com/jsonlint/-/jsonlint-1.6.2.tgz#5737045085f55eb455c68b1ff4ebc01bd50e8830" @@ -978,6 +982,12 @@ lazystream@^1.0.0: dependencies: readable-stream "^2.0.5" +linkify-it@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + dependencies: + uc.micro "^1.0.1" + livereload-js@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" @@ -1015,6 +1025,22 @@ map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" +markdown-it@8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.2.tgz#df4b86530d17c3bc9beec3b68d770b92ea17ae96" + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.3" + +markdownlint@^0.6.1: + version "0.6.4" + resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.6.4.tgz#7fa77e0d8c1b1c3ed7978761ce664bd23e7328ef" + dependencies: + markdown-it "8.3.2" + maxmin@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/maxmin/-/maxmin-1.1.0.tgz#71365e84a99dd8f8b3f7d5fde2f00d1e7f73be61" @@ -1033,6 +1059,10 @@ maxmin@^2.1.0: gzip-size "^3.0.0" pretty-bytes "^3.0.0" +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -1095,8 +1125,10 @@ nan@^2.6.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" node-abi@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.1.tgz#c9cda256ec8aa99bcab2f6446db38af143338b2a" + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" + dependencies: + semver "^5.4.1" node-gyp@^3.6.2: version "3.6.2" @@ -1437,8 +1469,8 @@ request@2: uuid "^3.1.0" resolve@^1.1.6: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" @@ -1460,7 +1492,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -"semver@2 || 3 || 4 || 5": +"semver@2 || 3 || 4 || 5", semver@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -1493,15 +1525,19 @@ simple-get@^1.4.2: xtend "^4.0.0" sntp@2.x.x: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b" + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" dependencies: hoek "4.x.x" -source-map@0.5.x, source-map@~0.5.1: +source-map@0.5.x: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" +source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + spdx-correct@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" @@ -1535,8 +1571,8 @@ sshpk@^1.7.0: tweetnacl "~0.14.0" statuses@1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" stream-buffers@^2.1.0: version "2.2.0" @@ -1666,12 +1702,16 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -uglify-js@~3.0.4: - version "3.0.28" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.28.tgz#96b8495f0272944787b5843a1679aa326640d5f7" +uc.micro@^1.0.1, uc.micro@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + +uglify-js@~3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.2.2.tgz#870e4b34ed733d179284f9998efd3293f7fd73f6" dependencies: - commander "~2.11.0" - source-map "~0.5.1" + commander "~2.12.1" + source-map "~0.6.1" underscore.string@~3.2.3: version "3.2.3"