Merge branch 'develop' into feature/stream

Conflicts:
	composer.json
	composer.lock
	controllers/FrontController.php
This commit is contained in:
Pierre Rudloff 2016-12-26 13:06:55 +01:00
commit 342dad38e6
21 changed files with 713 additions and 366 deletions

View file

@ -1,7 +1,22 @@
language: php
php:
- 5.6
- 7
install:
- composer install --no-dev
- composer install
before_install:
- composer selfupdate
- npm install -g npm@3
after_success:
- bash <(curl -s https://codecov.io/bash)
before_deploy:
- npm install
- ./node_modules/.bin/grunt doc
deploy:
provider: surge
project: ./docs/
domain: alltube.surge.sh
skip_cleanup: true
env:
global:
- SURGE_LOGIN=contact@rudloff.pro
- secure: Icw8UqAilq0+neZsdXn7pny5OrDin1tTN0H3HGPFDBawHWBEffettRsURljnBlm0IcAE8HPvl0DlaGFMedM3ZlYjvp7OqMqe84p7dY22JMvirV4MsMz546FKEYI+g3txawAMDFPCorE+fgkDrL1eUoozGVJxc5c4w4nBVm84QvjxRvCvEKbfevd4giaie1Xuo927lKAwTaVFZryYNotPyJVB2pBBndxfl2EJczJ4DXQc3VczFXkTmuE/QLa2tQVJm5vnVPwOi1xmvgh6g1ChEOw0zAks1Mf5+UvxtVV7qTicVAWK0fVVBL9mHPpNzSNb4pPqHPWQjhAPdCW+WPn6+DhqS5BHeSfQit/OtLMpUWO1IceVDRwU3jkXmMgnKwz1t9yDh6VBZRvGPkXfU3cjQ9SFpmnnu/4JLgwA/zSU2Pzl7/+gsHQBazkXh8HYAbOjF2w1IBXOpZ8Yv7D5axRIDduS/TUQ6oNK3KYmRMBcg8ZzVzIdz+55NchaDtihcp5akaHhKxR7GMPrfi66b+wARSw3OsYmCGLNFF8zj/6zo3/zB02+oVMlXXySOAKKi0A2OvH9xV4W4Jl0TGua/27XOWr9c5btrZrykk3PXfKe5YgT46Q8CtK8yN97bDKbwbAp6gNEyMFFatdHKlEndZYsVDQ16htd0b/303SZfXYMvO0=

View file

@ -1,15 +1,16 @@
FROM php:5.6-apache
RUN apt-get update
RUN apt-get install -y libicu-dev xz-utils git zlib1g-dev python npm nodejs-legacy
RUN curl -sL https://deb.nodesource.com/setup_6.x | bash -
RUN apt-get install -y libicu-dev xz-utils git zlib1g-dev python nodejs
RUN docker-php-ext-install mbstring
RUN docker-php-ext-install intl
RUN docker-php-ext-install zip
RUN npm install -g bower grunt-cli
RUN a2enmod rewrite
RUN curl -sS https://getcomposer.org/installer | php
COPY php.ini /usr/local/etc/php/
COPY . /var/www/html/
RUN curl -sS https://getcomposer.org/installer | php
RUN php composer.phar install
RUN php composer.phar install --prefer-dist
RUN npm install
RUN bower --allow-root install
RUN grunt

8
FAQ.md
View file

@ -55,3 +55,11 @@ There are two known workarounds:
* You can run Alltube locally on your computer.
* You can use the experimental `feature/stream` branch which streams the video through the server in order to bypass IP restrictions.
Please note that this can use a lot of resources on the server (which is why we won't enable it on alltubedownload.net).
## CSS and JavaScript files are missing
You probably don't have the minified files (in the `dist` folder).
You need to either:
* Use a [release package](https://github.com/Rudloff/alltube/releases)
* Run `npm install` (see detailed instructions in the [README](README.md#from-git))

View file

@ -68,7 +68,7 @@ module.exports = function (grunt) {
options: {
archive: 'alltube-<%= githash.main.tag %>.zip'
},
src: ['*.php', '!config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg']
src: ['*.php', '!config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg', '!vendor/phpunit/**', '!vendor/squizlabs/**']
}
},
phpdocumentor: {

View file

@ -110,12 +110,6 @@ server {
}
```
## License
This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html).
Please __use a different name and logo__ if you run it on a public server.
## Other dependencies
You need [avconv](https://libav.org/avconv.html), [rtmpdump](http://rtmpdump.mplayerhq.hu/) and [curl](https://curl.haxx.se/) in order to enable conversions.
@ -129,6 +123,45 @@ sudo apt-get install libav-tools rtmpdump curl
You also probably need to edit the `avconv` variable in `config.yml` so that it points to your ffmpeg/avconv binary (`/usr/bin/avconv` on Debian/Ubuntu).
## Use as library
Alltube can also be used as a library to extract a video URL from a webpage.
You can install it with:
```bash
composer require rudloff/alltube
```
You can then use it in your PHP code:
```php
use Alltube\Config;
use Alltube\VideoDownload;
require_once __DIR__.'/vendor/autoload.php';
$downloader = new VideoDownload(
new Config(
[
'youtubedl' => '/usr/local/bin/youtube-dl',
]
)
);
$downloader->getURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
```
The library documentation is available on [alltube.surge.sh](https://alltube.surge.sh/classes/Alltube.VideoDownload.html).
You can also have a look at this [example project](https://github.com/Rudloff/alltube-example-project).
## FAQ
Please read the [FAQ](FAQ.md) before reporting any issue.
## License
This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html).
Please __use a different name and logo__ if you run it on a public server.

View file

@ -2,6 +2,7 @@
/**
* Config class.
*/
namespace Alltube;
use Symfony\Component\Yaml\Yaml;
@ -84,28 +85,37 @@ class Config
/**
* Config constructor.
*
* @param string $yamlfile YAML config file path
* Available options:
* * youtubedl: youtube-dl binary path
* * python: Python binary path
* * avconv: avconv or ffmpeg binary path
* * rtmpdump: rtmpdump binary path
* * curl: curl binary path
* * params: Array of youtube-dl parameters
* * curl_params: Array of curl parameters
* * convert: Enable conversion?
*
* @param array $options Options
*/
private function __construct($yamlfile)
public function __construct(array $options)
{
$this->file = $yamlfile;
if (is_file($yamlfile)) {
$yaml = Yaml::parse(file_get_contents($yamlfile));
if (isset($yaml) && is_array($yaml)) {
foreach ($yaml as $param => $value) {
if (isset($this->$param) && isset($value)) {
$this->$param = $value;
}
if (isset($options) && is_array($options)) {
foreach ($options as $option => $value) {
if (isset($this->$option) && isset($value)) {
$this->$option = $value;
}
}
}
if (getenv('CONVERT')) {
$this->convert = (bool) getenv('CONVERT');
}
if (getenv('PYTHON')) {
$this->python = getenv('PYTHON');
}
}
/**
* Get singleton instance.
* Get Config singleton instance from YAML config file.
*
* @param string $yamlfile YAML config file name
*
@ -113,9 +123,21 @@ class Config
*/
public static function getInstance($yamlfile = 'config.yml')
{
$yamlfile = __DIR__.'/../'.$yamlfile;
$yamlPath = __DIR__.'/../'.$yamlfile;
if (is_null(self::$instance) || self::$instance->file != $yamlfile) {
self::$instance = new self($yamlfile);
if (is_file($yamlfile)) {
$options = Yaml::parse(file_get_contents($yamlPath));
} elseif ($yamlfile == 'config.yml') {
/*
Allow for the default file to be missing in order to
not surprise users that did not create a config file
*/
$options = [];
} else {
throw new \Exception("Can't find config file at ".$yamlPath);
}
self::$instance = new self($options);
self::$instance->file = $yamlfile;
}
return self::$instance;

View file

@ -0,0 +1,13 @@
<?php
/**
* PasswordException class.
*/
namespace Alltube;
/**
* Exception thrown when a video requires a password.
*/
class PasswordException extends \Exception
{
}

View file

@ -2,6 +2,7 @@
/**
* VideoDownload class.
*/
namespace Alltube;
use Chain\Chain;
@ -29,10 +30,19 @@ class VideoDownload
/**
* VideoDownload constructor.
*/
public function __construct()
public function __construct(Config $config = null)
{
$this->config = Config::getInstance();
if (isset($config)) {
$this->config = $config;
} else {
$this->config = Config::getInstance();
}
$this->procBuilder = new ProcessBuilder();
if (!is_file($this->config->youtubedl)) {
throw new \Exception("Can't find youtube-dl at ".$this->config->youtubedl);
} elseif (!is_file($this->config->python)) {
throw new \Exception("Can't find Python at ".$this->config->python);
}
$this->procBuilder->setPrefix(
array_merge(
[$this->config->python, $this->config->youtubedl],
@ -48,27 +58,20 @@ class VideoDownload
* */
public function listExtractors()
{
$this->procBuilder->setArguments(
[
'--list-extractors',
]
);
$process = $this->procBuilder->getProcess();
$process->run();
return explode(PHP_EOL, trim($process->getOutput()));
return explode(PHP_EOL, trim($this->getProp(null, null, 'list-extractors')));
}
/**
* Get a property from youtube-dl.
*
* @param string $url URL to parse
* @param string $format Format
* @param string $prop Property
* @param string $url URL to parse
* @param string $format Format
* @param string $prop Property
* @param string $password Video password
*
* @return string
*/
private function getProp($url, $format = null, $prop = 'dump-json')
private function getProp($url, $format = null, $prop = 'dump-json', $password = null)
{
$this->procBuilder->setArguments(
[
@ -79,10 +82,21 @@ class VideoDownload
if (isset($format)) {
$this->procBuilder->add('-f '.$format);
}
if (isset($password)) {
$this->procBuilder->add('--video-password');
$this->procBuilder->add($password);
}
$process = $this->procBuilder->getProcess();
$process->run();
if (!$process->isSuccessful()) {
throw new \Exception($process->getErrorOutput());
$errorOutput = trim($process->getErrorOutput());
if ($errorOutput == 'ERROR: This video is protected by a password, use the --video-password option') {
throw new PasswordException($errorOutput);
} elseif (substr($errorOutput, 0, 21) == 'ERROR: Wrong password') {
throw new \Exception('Wrong password');
} else {
throw new \Exception($errorOutput);
}
} else {
return $process->getOutput();
}
@ -91,55 +105,59 @@ class VideoDownload
/**
* Get all information about a video.
*
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $password Video password
*
* @return object Decoded JSON
* */
public function getJSON($url, $format = null)
public function getJSON($url, $format = null, $password = null)
{
return json_decode($this->getProp($url, $format, 'dump-json'));
return json_decode($this->getProp($url, $format, 'dump-json', $password));
}
/**
* Get URL of video from URL of page.
*
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $password Video password
*
* @return string URL of video
* */
public function getURL($url, $format = null)
public function getURL($url, $format = null, $password = null)
{
return $this->getProp($url, $format, 'get-url');
return $this->getProp($url, $format, 'get-url', $password);
}
/**
* Get filename of video file from URL of page.
*
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $password Video password
*
* @return string Filename of extracted video
* */
public function getFilename($url, $format = null)
public function getFilename($url, $format = null, $password = null)
{
return trim($this->getProp($url, $format, 'get-filename'));
return trim($this->getProp($url, $format, 'get-filename', $password));
}
/**
* Get filename of audio from URL of page.
*
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $password Video password
*
* @return string Filename of converted audio file
* */
public function getAudioFilename($url, $format = null)
public function getAudioFilename($url, $format = null, $password = null)
{
return html_entity_decode(
pathinfo(
$this->getFilename($url, $format),
$this->getFilename($url, $format, $password),
PATHINFO_FILENAME
).'.mp3',
ENT_COMPAT,
@ -147,21 +165,106 @@ 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.
*
* @param object $video Video object returned by youtube-dl
*
* @return \Symfony\Component\Process\Process Process
*/
private function getRtmpProcess($video)
{
if (!shell_exec('which '.$this->config->rtmpdump)) {
throw(new \Exception('Can\'t find rtmpdump'));
}
$builder = new ProcessBuilder(
[
$this->config->rtmpdump,
'-q',
]
);
$builder = $this->addOptionsToRtmpProcess($builder, $video);
if (isset($video->rtmp_conn)) {
foreach ($video->rtmp_conn as $conn) {
$builder->add('--conn');
$builder->add($conn);
}
}
return $builder->getProcess();
}
/**
* Get a process that runs curl in order to download a video.
*
* @param object $video Video object returned by youtube-dl
*
* @return \Symfony\Component\Process\Process Process
*/
private function getCurlProcess($video)
{
if (!shell_exec('which '.$this->config->curl)) {
throw(new \Exception('Can\'t find curl'));
}
$builder = ProcessBuilder::create(
array_merge(
[
$this->config->curl,
'--silent',
'--location',
'--user-agent', $video->http_headers->{'User-Agent'},
$video->url,
],
$this->config->curl_params
)
);
return $builder->getProcess();
}
/**
* Get audio stream of converted video.
*
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $url URL of page
* @param string $format Format to use for the video
* @param string $password Video password
*
* @return resource popen stream
*/
public function getAudioStream($url, $format)
public function getAudioStream($url, $format, $password = null)
{
if (!shell_exec('which '.$this->config->avconv)) {
throw(new \Exception('Can\'t find avconv or ffmpeg'));
}
$video = $this->getJSON($url, $format);
$video = $this->getJSON($url, $format, $password);
//Vimeo needs a correct user-agent
ini_set(
@ -180,62 +283,12 @@ class VideoDownload
);
if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') {
if (!shell_exec('which '.$this->config->rtmpdump)) {
throw(new \Exception('Can\'t find rtmpdump'));
}
$builder = new ProcessBuilder(
[
$this->config->rtmpdump,
'-q',
'-r',
$video->url,
'--pageUrl', $video->webpage_url,
]
);
if (isset($video->player_url)) {
$builder->add('--swfVfy');
$builder->add($video->player_url);
}
if (isset($video->flash_version)) {
$builder->add('--flashVer');
$builder->add($video->flash_version);
}
if (isset($video->play_path)) {
$builder->add('--playpath');
$builder->add($video->play_path);
}
if (isset($video->rtmp_conn)) {
foreach ($video->rtmp_conn as $conn) {
$builder->add('--conn');
$builder->add($conn);
}
}
if (isset($video->app)) {
$builder->add('--app');
$builder->add($video->app);
}
$chain = new Chain($builder->getProcess());
$chain->add('|', $avconvProc);
$process = $this->getRtmpProcess($video);
} else {
if (!shell_exec('which '.$this->config->curl)) {
throw(new \Exception('Can\'t find curl'));
}
$chain = new Chain(
ProcessBuilder::create(
array_merge(
[
$this->config->curl,
'--silent',
'--location',
'--user-agent', $video->http_headers->{'User-Agent'},
$video->url,
],
$this->config->curl_params
)
)
);
$chain->add('|', $avconvProc);
$process = $this->getCurlProcess($video);
}
$chain = new Chain($process);
$chain->add('|', $avconvProc);
return popen($chain->getProcess()->getCommandLine(), 'r');
}

View file

@ -6,21 +6,23 @@
"type": "project",
"require": {
"smarty/smarty": "~3.1.29",
"rg3/youtube-dl": "~2016.09.08",
"slim/slim": "~3.5.0",
"slim/slim": "~3.6.0",
"mathmarques/smarty-view": "~1.1.0",
"symfony/yaml": "~3.1.0",
"symfony/process": "~3.1.0",
"symfony/yaml": "~3.2.0",
"symfony/process": "~3.2.0",
"ptachoire/process-builder-chain": "~1.2.0",
"ffmpeg/ffmpeg": "dev-release",
"rudloff/smarty-plugin-noscheme": "~0.1.0",
"guzzlehttp/guzzle": "~6.2.0",
"rudloff/rtmpdump-bin": "~2.3"
"rudloff/rtmpdump-bin": "~2.3",
"aura/session": "~2.1.0"
},
"require-dev": {
"symfony/var-dumper": "~3.1.0",
"symfony/var-dumper": "~3.2.0",
"squizlabs/php_codesniffer": "~2.7.0",
"phpunit/phpunit": "~5.5.2"
"phpunit/phpunit": "~5.7.2",
"ffmpeg/ffmpeg": "dev-release",
"rg3/youtube-dl": "~2016.12.20",
"rudloff/rtmpdump-bin": "~2.3"
},
"extra": {
"paas": {
@ -34,11 +36,10 @@
"type": "package",
"package": {
"name": "rg3/youtube-dl",
"version": "2016.09.08",
"source": {
"url": "https://github.com/rg3/youtube-dl.git",
"type": "git",
"reference": "2016.09.08"
"version": "2016.12.20",
"dist": {
"type": "zip",
"url": "https://github.com/rg3/youtube-dl/archive/2016.12.20.zip"
}
}
},
@ -79,5 +80,8 @@
},
"config": {
"secure-http": false
},
"scripts": {
"compile": "composer install --dev"
}
}

415
composer.lock generated
View file

@ -4,9 +4,71 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "619ed10d49b90725061dfd851d994432",
"content-hash": "dac044b232222cd1af6f62f3ad24d231",
"hash": "a4497d475262ef7fa88f43d6bd18b3db",
"content-hash": "f553e8eeebb1466397549b8304eccece",
"packages": [
{
"name": "aura/session",
"version": "2.1.0",
"source": {
"type": "git",
"url": "https://github.com/auraphp/Aura.Session.git",
"reference": "7d2f7d41ad693970b5b6b83facca0961d3378883"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/auraphp/Aura.Session/zipball/7d2f7d41ad693970b5b6b83facca0961d3378883",
"reference": "7d2f7d41ad693970b5b6b83facca0961d3378883",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"aura/di": "~2.0"
},
"suggest": {
"ext-mcrypt": "Mcrypt generates the next best secure CSRF tokens.",
"ext-openssl": "OpenSSL generates the best secure CSRF tokens.",
"ircmaxell/random-lib": "A Library For Generating Secure Random Numbers",
"paragonie/random_compat": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7"
},
"type": "library",
"extra": {
"aura": {
"type": "library",
"config": {
"common": "Aura\\Session\\_Config\\Common"
}
}
},
"autoload": {
"psr-4": {
"Aura\\Session\\": "src/",
"Aura\\Session\\_Config\\": "config/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Aura.Session Contributors",
"homepage": "https://github.com/auraphp/Aura.Session/contributors"
}
],
"description": "Provides session management functionality, including lazy session starting, session segments, next-request-only (\"flash\") values, and CSRF tools.",
"homepage": "https://github.com/auraphp/Aura.Session",
"keywords": [
"csrf",
"flash",
"flash message",
"session",
"sessions"
],
"time": "2016-10-03 20:28:32"
},
{
"name": "container-interop/container-interop",
"version": "1.1.0",
@ -34,20 +96,6 @@
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"time": "2014-12-30 15:22:37"
},
{
"name": "ffmpeg/ffmpeg",
"version": "dev-release",
"dist": {
"type": "xz",
"url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz",
"reference": null,
"shasum": null
},
"bin": [
"ffmpeg"
],
"type": "library"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.2.2",
@ -112,28 +160,28 @@
},
{
"name": "guzzlehttp/promises",
"version": "1.2.0",
"version": "v1.3.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579"
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/c10d860e2a9595f8883527fa0021c7da9e65f579",
"reference": "c10d860e2a9595f8883527fa0021c7da9e65f579",
"url": "https://api.github.com/repos/guzzle/promises/zipball/a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"reference": "a59da6cf61d80060647ff4d3eb2c03a2bc694646",
"shasum": ""
},
"require": {
"php": ">=5.5.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
"phpunit/phpunit": "^4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
"dev-master": "1.4-dev"
}
},
"autoload": {
@ -159,7 +207,7 @@
"keywords": [
"promise"
],
"time": "2016-05-18 16:56:05"
"time": "2016-12-20 10:07:11"
},
{
"name": "guzzlehttp/psr7",
@ -570,16 +618,6 @@
"description": "Add ability to chain symfony processes",
"time": "2016-04-10 08:33:20"
},
{
"name": "rg3/youtube-dl",
"version": "2016.09.08",
"source": {
"type": "git",
"url": "https://github.com/rg3/youtube-dl.git",
"reference": "2016.09.08"
},
"type": "library"
},
{
"name": "rudloff/rtmpdump-bin",
"version": "2.3",
@ -651,16 +689,16 @@
},
{
"name": "slim/slim",
"version": "3.5.0",
"version": "3.6.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "184352bc1913d7ba552ab4131d62f4730ddb0893"
"reference": "a685fe91a9435e1432e8eeb7cf516e2f5cee7f64"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/184352bc1913d7ba552ab4131d62f4730ddb0893",
"reference": "184352bc1913d7ba552ab4131d62f4730ddb0893",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/a685fe91a9435e1432e8eeb7cf516e2f5cee7f64",
"reference": "a685fe91a9435e1432e8eeb7cf516e2f5cee7f64",
"shasum": ""
},
"require": {
@ -717,20 +755,20 @@
"micro",
"router"
],
"time": "2016-07-26 15:12:13"
"time": "2016-11-20 20:48:49"
},
{
"name": "smarty/smarty",
"version": "v3.1.30",
"version": "v3.1.31",
"source": {
"type": "git",
"url": "https://github.com/smarty-php/smarty.git",
"reference": "ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e"
"reference": "c7d42e4a327c402897dd587871434888fde1e7a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e",
"reference": "ed2b7f1146cfda13df1eea8a5f707a1b771b6e7e",
"url": "https://api.github.com/repos/smarty-php/smarty/zipball/c7d42e4a327c402897dd587871434888fde1e7a9",
"reference": "c7d42e4a327c402897dd587871434888fde1e7a9",
"shasum": ""
},
"require": {
@ -743,10 +781,8 @@
}
},
"autoload": {
"classmap": [
"libs/Smarty.class.php",
"libs/SmartyBC.class.php",
"libs/sysplugins/"
"files": [
"libs/bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@ -772,20 +808,20 @@
"keywords": [
"templating"
],
"time": "2016-08-07 18:46:49"
"time": "2016-12-14 21:57:25"
},
{
"name": "symfony/process",
"version": "v3.1.5",
"version": "v3.2.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "66de154ae86b1a07001da9fbffd620206e4faf94"
"reference": "02ea84847aad71be7e32056408bb19f3a616cdd3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/66de154ae86b1a07001da9fbffd620206e4faf94",
"reference": "66de154ae86b1a07001da9fbffd620206e4faf94",
"url": "https://api.github.com/repos/symfony/process/zipball/02ea84847aad71be7e32056408bb19f3a616cdd3",
"reference": "02ea84847aad71be7e32056408bb19f3a616cdd3",
"shasum": ""
},
"require": {
@ -794,7 +830,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -821,29 +857,35 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"time": "2016-09-29 14:13:09"
"time": "2016-11-24 10:40:28"
},
{
"name": "symfony/yaml",
"version": "v3.1.5",
"version": "v3.2.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3"
"reference": "a7095af4b97a0955f85c8989106c249fa649011f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/368b9738d4033c8b93454cb0dbd45d305135a6d3",
"reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3",
"url": "https://api.github.com/repos/symfony/yaml/zipball/a7095af4b97a0955f85c8989106c249fa649011f",
"reference": "a7095af4b97a0955f85c8989106c249fa649011f",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/console": "~2.8|~3.0"
},
"suggest": {
"symfony/console": "For validating YAML files using the lint command"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -870,7 +912,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2016-09-25 08:27:07"
"time": "2016-12-10 10:07:06"
}
],
"packages-dev": [
@ -928,18 +970,32 @@
],
"time": "2015-06-14 21:17:01"
},
{
"name": "ffmpeg/ffmpeg",
"version": "dev-release",
"dist": {
"type": "xz",
"url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz",
"reference": null,
"shasum": null
},
"bin": [
"ffmpeg"
],
"type": "library"
},
{
"name": "myclabs/deep-copy",
"version": "1.5.4",
"version": "1.5.5",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f"
"reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
"reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108",
"reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108",
"shasum": ""
},
"require": {
@ -968,7 +1024,7 @@
"object",
"object graph"
],
"time": "2016-09-16 13:37:59"
"time": "2016-10-31 17:19:45"
},
{
"name": "phpdocumentor/reflection-common",
@ -1071,16 +1127,16 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "0.2",
"version": "0.2.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443"
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443",
"reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
"reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb",
"shasum": ""
},
"require": {
@ -1114,20 +1170,20 @@
"email": "me@mikevanriel.com"
}
],
"time": "2016-06-10 07:14:17"
"time": "2016-11-25 06:54:22"
},
{
"name": "phpspec/prophecy",
"version": "v1.6.1",
"version": "v1.6.2",
"source": {
"type": "git",
"url": "https://github.com/phpspec/prophecy.git",
"reference": "58a8137754bc24b25740d4281399a4a3596058e0"
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0",
"reference": "58a8137754bc24b25740d4281399a4a3596058e0",
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb",
"reference": "6c52c2722f8460122f96f86346600e1077ce22cb",
"shasum": ""
},
"require": {
@ -1135,10 +1191,11 @@
"php": "^5.3|^7.0",
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2",
"sebastian/comparator": "^1.1",
"sebastian/recursion-context": "^1.0"
"sebastian/recursion-context": "^1.0|^2.0"
},
"require-dev": {
"phpspec/phpspec": "^2.0"
"phpspec/phpspec": "^2.0",
"phpunit/phpunit": "^4.8 || ^5.6.5"
},
"type": "library",
"extra": {
@ -1176,20 +1233,20 @@
"spy",
"stub"
],
"time": "2016-06-07 08:13:47"
"time": "2016-11-21 14:58:47"
},
{
"name": "phpunit/php-code-coverage",
"version": "4.0.1",
"version": "4.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3"
"reference": "c14196e64a78570034afd0b7a9f3757ba71c2a0a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/5f3f7e736d6319d5f1fc402aff8b026da26709a3",
"reference": "5f3f7e736d6319d5f1fc402aff8b026da26709a3",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c14196e64a78570034afd0b7a9f3757ba71c2a0a",
"reference": "c14196e64a78570034afd0b7a9f3757ba71c2a0a",
"shasum": ""
},
"require": {
@ -1239,20 +1296,20 @@
"testing",
"xunit"
],
"time": "2016-07-26 14:39:29"
"time": "2016-12-20 15:22:42"
},
{
"name": "phpunit/php-file-iterator",
"version": "1.4.1",
"version": "1.4.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0"
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0",
"url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5",
"shasum": ""
},
"require": {
@ -1286,7 +1343,7 @@
"filesystem",
"iterator"
],
"time": "2015-06-21 13:08:43"
"time": "2016-10-03 07:40:28"
},
{
"name": "phpunit/php-text-template",
@ -1375,16 +1432,16 @@
},
{
"name": "phpunit/php-token-stream",
"version": "1.4.8",
"version": "1.4.9",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-token-stream.git",
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da"
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
"reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da",
"url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b",
"reference": "3b402f65a4cc90abf6e1104e388b896ce209631b",
"shasum": ""
},
"require": {
@ -1420,20 +1477,20 @@
"keywords": [
"tokenizer"
],
"time": "2015-09-15 10:49:45"
"time": "2016-11-15 14:06:22"
},
{
"name": "phpunit/phpunit",
"version": "5.5.7",
"version": "5.7.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3f67cee782c9abfaee5e32fd2f57cdd54bc257ba"
"reference": "af91da3f2671006ff5d0628023de3b7ac4d1ef09"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3f67cee782c9abfaee5e32fd2f57cdd54bc257ba",
"reference": "3f67cee782c9abfaee5e32fd2f57cdd54bc257ba",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/af91da3f2671006ff5d0628023de3b7ac4d1ef09",
"reference": "af91da3f2671006ff5d0628023de3b7ac4d1ef09",
"shasum": ""
},
"require": {
@ -1444,18 +1501,18 @@
"ext-xml": "*",
"myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1",
"phpunit/php-code-coverage": "^4.0.1",
"phpspec/prophecy": "^1.6.2",
"phpunit/php-code-coverage": "^4.0.3",
"phpunit/php-file-iterator": "~1.4",
"phpunit/php-text-template": "~1.2",
"phpunit/php-timer": "^1.0.6",
"phpunit/phpunit-mock-objects": "^3.2",
"sebastian/comparator": "~1.1",
"sebastian/comparator": "~1.2.2",
"sebastian/diff": "~1.2",
"sebastian/environment": "^1.3 || ^2.0",
"sebastian/exporter": "~1.2",
"sebastian/global-state": "~1.0",
"sebastian/object-enumerator": "~1.0",
"sebastian/environment": "^1.3.4 || ^2.0",
"sebastian/exporter": "~2.0",
"sebastian/global-state": "^1.0 || ^2.0",
"sebastian/object-enumerator": "~2.0",
"sebastian/resource-operations": "~1.0",
"sebastian/version": "~1.0|~2.0",
"symfony/yaml": "~2.1|~3.0"
@ -1467,7 +1524,6 @@
"ext-pdo": "*"
},
"suggest": {
"ext-tidy": "*",
"ext-xdebug": "*",
"phpunit/php-invoker": "~1.1"
},
@ -1477,7 +1533,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.5.x-dev"
"dev-master": "5.7.x-dev"
}
},
"autoload": {
@ -1503,27 +1559,27 @@
"testing",
"xunit"
],
"time": "2016-10-03 13:04:15"
"time": "2016-12-13 16:19:44"
},
{
"name": "phpunit/phpunit-mock-objects",
"version": "3.4.0",
"version": "3.4.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2"
"reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/238d7a2723bce689c79eeac9c7d5e1d623bb9dc2",
"reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
"reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24",
"shasum": ""
},
"require": {
"doctrine/instantiator": "^1.0.2",
"php": "^5.6 || ^7.0",
"phpunit/php-text-template": "^1.2",
"sebastian/exporter": "^1.2"
"sebastian/exporter": "^1.2 || ^2.0"
},
"conflict": {
"phpunit/phpunit": "<5.4.0"
@ -1562,7 +1618,18 @@
"mock",
"xunit"
],
"time": "2016-10-09 07:01:45"
"time": "2016-12-08 20:27:08"
},
{
"name": "rg3/youtube-dl",
"version": "2016.12.20",
"dist": {
"type": "zip",
"url": "https://github.com/rg3/youtube-dl/archive/2016.12.20.zip",
"reference": null,
"shasum": null
},
"type": "library"
},
{
"name": "sebastian/code-unit-reverse-lookup",
@ -1611,22 +1678,22 @@
},
{
"name": "sebastian/comparator",
"version": "1.2.0",
"version": "1.2.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22"
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22",
"reference": "937efb279bd37a375bcadf584dec0726f84dbf22",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/diff": "~1.2",
"sebastian/exporter": "~1.2"
"sebastian/exporter": "~1.2 || ~2.0"
},
"require-dev": {
"phpunit/phpunit": "~4.4"
@ -1671,7 +1738,7 @@
"compare",
"equality"
],
"time": "2015-07-26 15:48:44"
"time": "2016-11-19 09:18:40"
},
{
"name": "sebastian/diff",
@ -1727,28 +1794,28 @@
},
{
"name": "sebastian/environment",
"version": "1.3.8",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea"
"reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea",
"url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
"reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
"php": "^5.6 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8 || ^5.0"
"phpunit/phpunit": "^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -1773,25 +1840,25 @@
"environment",
"hhvm"
],
"time": "2016-08-18 05:49:44"
"time": "2016-11-26 07:53:53"
},
{
"name": "sebastian/exporter",
"version": "1.2.2",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4"
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4",
"reference": "42c4c2eec485ee3e159ec9884f95b431287edde4",
"url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
"reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4",
"shasum": ""
},
"require": {
"php": ">=5.3.3",
"sebastian/recursion-context": "~1.0"
"sebastian/recursion-context": "~2.0"
},
"require-dev": {
"ext-mbstring": "*",
@ -1800,7 +1867,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.3.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -1840,7 +1907,7 @@
"export",
"exporter"
],
"time": "2016-06-17 09:04:28"
"time": "2016-11-19 08:54:04"
},
{
"name": "sebastian/global-state",
@ -1895,21 +1962,21 @@
},
{
"name": "sebastian/object-enumerator",
"version": "1.0.0",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26"
"reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/d4ca2fb70344987502567bc50081c03e6192fb26",
"reference": "d4ca2fb70344987502567bc50081c03e6192fb26",
"url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35",
"reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35",
"shasum": ""
},
"require": {
"php": ">=5.6",
"sebastian/recursion-context": "~1.0"
"sebastian/recursion-context": "~2.0"
},
"require-dev": {
"phpunit/phpunit": "~5"
@ -1917,7 +1984,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -1937,20 +2004,20 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"time": "2016-01-28 13:25:10"
"time": "2016-11-19 07:35:10"
},
{
"name": "sebastian/recursion-context",
"version": "1.0.2",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
"reference": "913401df809e99e4f47b27cdd781f4a258d58791"
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791",
"reference": "913401df809e99e4f47b27cdd781f4a258d58791",
"url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a",
"reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a",
"shasum": ""
},
"require": {
@ -1962,7 +2029,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "2.0.x-dev"
}
},
"autoload": {
@ -1990,7 +2057,7 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"time": "2015-11-11 19:50:13"
"time": "2016-11-19 07:33:16"
},
{
"name": "sebastian/resource-operations",
@ -2036,16 +2103,16 @@
},
{
"name": "sebastian/version",
"version": "2.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
"reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5"
"reference": "99732be0ddb3361e16ad77b68ba41efc8e979019"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
"reference": "c829badbd8fdf16a0bad8aa7fa7971c029f1b9c5",
"url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019",
"reference": "99732be0ddb3361e16ad77b68ba41efc8e979019",
"shasum": ""
},
"require": {
@ -2075,20 +2142,20 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"time": "2016-02-04 12:56:52"
"time": "2016-10-03 07:35:21"
},
{
"name": "squizlabs/php_codesniffer",
"version": "2.7.0",
"version": "2.7.1",
"source": {
"type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed"
"reference": "9b324f3a1132459a7274a0ace2e1b766ba80930f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
"reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/9b324f3a1132459a7274a0ace2e1b766ba80930f",
"reference": "9b324f3a1132459a7274a0ace2e1b766ba80930f",
"shasum": ""
},
"require": {
@ -2153,20 +2220,20 @@
"phpcs",
"standards"
],
"time": "2016-09-01 23:53:02"
"time": "2016-11-30 04:02:31"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.2.0",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "dff51f72b0706335131b00a7f49606168c582594"
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
"reference": "dff51f72b0706335131b00a7f49606168c582594",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4",
"reference": "e79d363049d1c2128f133a2667e4f4190904f7f4",
"shasum": ""
},
"require": {
@ -2178,7 +2245,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@ -2212,20 +2279,20 @@
"portable",
"shim"
],
"time": "2016-05-18 14:26:46"
"time": "2016-11-14 01:06:16"
},
{
"name": "symfony/var-dumper",
"version": "v3.1.5",
"version": "v3.2.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "70bfe927b86ba9999aeebd829715b0bb2cd39a10"
"reference": "f722532b0966e9b6fc631e682143c07b2cf583a0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/70bfe927b86ba9999aeebd829715b0bb2cd39a10",
"reference": "70bfe927b86ba9999aeebd829715b0bb2cd39a10",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/f722532b0966e9b6fc631e682143c07b2cf583a0",
"reference": "f722532b0966e9b6fc631e682143c07b2cf583a0",
"shasum": ""
},
"require": {
@ -2241,7 +2308,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.1-dev"
"dev-master": "3.2-dev"
}
},
"autoload": {
@ -2275,24 +2342,24 @@
"debug",
"dump"
],
"time": "2016-09-29 14:13:09"
"time": "2016-12-11 14:34:22"
},
{
"name": "webmozart/assert",
"version": "1.1.0",
"version": "1.2.0",
"source": {
"type": "git",
"url": "https://github.com/webmozart/assert.git",
"reference": "bb2d123231c095735130cc8f6d31385a44c7b308"
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/webmozart/assert/zipball/bb2d123231c095735130cc8f6d31385a44c7b308",
"reference": "bb2d123231c095735130cc8f6d31385a44c7b308",
"url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f",
"reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f",
"shasum": ""
},
"require": {
"php": "^5.3.3|^7.0"
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"phpunit/phpunit": "^4.6",
@ -2301,7 +2368,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.2-dev"
"dev-master": "1.3-dev"
}
},
"autoload": {
@ -2325,7 +2392,7 @@
"check",
"validate"
],
"time": "2016-08-09 15:02:57"
"time": "2016-11-23 20:04:58"
}
],
"aliases": [],

View file

@ -2,9 +2,11 @@
/**
* FrontController class.
*/
namespace Alltube\Controller;
use Alltube\Config;
use Alltube\PasswordException;
use Alltube\VideoDownload;
use Interop\Container\ContainerInterface;
use Slim\Container;
@ -38,6 +40,20 @@ class FrontController
*/
private $container;
/**
* Session segment used to store session variables.
*
* @var \Aura\Session\Segment
*/
private $sessionSegment;
/**
* Smarty view.
*
* @var \Slim\Views\Smarty
*/
private $view;
/**
* FrontController constructor.
*
@ -48,6 +64,10 @@ class FrontController
$this->config = Config::getInstance();
$this->download = new VideoDownload();
$this->container = $container;
$this->view = $this->container->get('view');
$session_factory = new \Aura\Session\SessionFactory();
$session = $session_factory->newInstance($_COOKIE);
$this->sessionSegment = $session->getSegment('Alltube\Controller\FrontController');
}
/**
@ -60,17 +80,15 @@ class FrontController
*/
public function index(Request $request, Response $response)
{
if ($this->container instanceof Container) {
$this->container->view->render(
$response,
'index.tpl',
[
'convert' => $this->config->convert,
'class' => 'index',
'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.',
]
);
}
$this->view->render(
$response,
'index.tpl',
[
'convert' => $this->config->convert,
'class' => 'index',
'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.',
]
);
}
/**
@ -83,19 +101,38 @@ class FrontController
*/
public function extractors(Request $request, Response $response)
{
if ($this->container instanceof Container) {
$this->container->view->render(
$response,
'extractors.tpl',
[
'extractors' => $this->download->listExtractors(),
'class' => 'extractors',
'title' => 'Supported websites',
'description' => 'List of all supported websites from which Alltube Download '.
'can extract video or audio files',
]
);
}
$this->view->render(
$response,
'extractors.tpl',
[
'extractors' => $this->download->listExtractors(),
'class' => 'extractors',
'title' => 'Supported websites',
'description' => 'List of all supported websites from which Alltube Download '.
'can extract video or audio files',
]
);
}
/**
* Display a password prompt.
*
* @param Request $request PSR-7 request
* @param Response $response PSR-7 response
*
* @return Response HTTP response
*/
public function password(Request $request, Response $response)
{
$this->view->render(
$response,
'password.tpl',
[
'class' => 'password',
'title' => 'Password prompt',
'description' => 'You need a password in order to download this video with Alltube Download',
]
);
}
/**
@ -109,40 +146,47 @@ class FrontController
public function video(Request $request, Response $response)
{
$params = $request->getQueryParams();
$this->config = Config::getInstance();
if (isset($params['url'])) {
$password = $request->getParam('password');
if (isset($password)) {
$this->sessionSegment->setFlash($params['url'], $password);
}
if (isset($params['audio'])) {
try {
return $this->getStream($params['url'], 'mp3[protocol^=http]', $response, $request);
} catch (PasswordException $e) {
return $this->password($request, $response);
} catch (\Exception $e) {
$response = $response->withHeader(
'Content-Disposition',
'attachment; filename="'.
$this->download->getAudioFilename($params['url'], 'bestaudio/best').'"'
$this->download->getAudioFilename($params['url'], 'bestaudio/best', $password).'"'
);
$response = $response->withHeader('Content-Type', 'audio/mpeg');
if ($request->isGet()) {
$process = $this->download->getAudioStream($params['url'], 'bestaudio/best');
if ($request->isGet() || $request->isPost()) {
$process = $this->download->getAudioStream($params['url'], 'bestaudio/best', $password);
$response = $response->withBody(new Stream($process));
}
return $response;
}
} else {
$video = $this->download->getJSON($params['url']);
if ($this->container instanceof Container) {
$this->container->view->render(
$response,
'video.tpl',
[
'video' => $video,
'class' => 'video',
'title' => $video->title,
'description' => 'Download "'.$video->title.'" from '.$video->extractor_key,
]
);
try {
$video = $this->download->getJSON($params['url'], null, $password);
} catch (PasswordException $e) {
return $this->password($request, $response);
}
$this->view->render(
$response,
'video.tpl',
[
'video' => $video,
'class' => 'video',
'title' => $video->title,
'description' => 'Download "'.$video->title.'" from '.$video->extractor_key,
]
);
}
} else {
return $response->withRedirect($this->container->get('router')->pathFor('index'));
@ -160,17 +204,15 @@ class FrontController
*/
public function error(Request $request, Response $response, \Exception $exception)
{
if ($this->container instanceof Container) {
$this->container->view->render(
$response,
'error.tpl',
[
'errors' => $exception->getMessage(),
'class' => 'video',
'title' => 'Error',
]
);
}
$this->view->render(
$response,
'error.tpl',
[
'errors' => $exception->getMessage(),
'class' => 'video',
'title' => 'Error',
]
);
return $response->withStatus(500);
}
@ -207,6 +249,10 @@ class FrontController
if (isset($params['url'])) {
try {
return $this->getStream($params['url'], $params['format'], $response, $request);
} catch (PasswordException $e) {
return $response->withRedirect(
$this->container->get('router')->pathFor('video').'?url='.urlencode($params['url'])
);
} catch (\Exception $e) {
$response->getBody()->write($e->getMessage());

View file

@ -1,6 +1,7 @@
body {
text-align:center;
background-color: #EBEBEB;
background-image:url('../img/fond.jpg');
font-family: 'Open Sans', sans-serif;
font-weight:400;

View file

@ -3,7 +3,7 @@
require_once __DIR__.'/vendor/autoload.php';
use Alltube\Controller\FrontController;
if (strpos($_SERVER['REQUEST_URI'], '/index.php') !== false) {
if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '/index.php') !== false) {
header('Location: '.str_ireplace('/index.php', '/', $_SERVER['REQUEST_URI']));
die;
}
@ -19,7 +19,6 @@ $container['view'] = function ($c) {
$view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme');
return $view;
};
@ -35,7 +34,7 @@ $app->get(
'/extractors',
[$controller, 'extractors']
)->setName('extractors');
$app->get(
$app->any(
'/video',
[$controller, 'video']
)->setName('video');

View file

@ -33,5 +33,6 @@
"lang": "en",
"start_url": "./",
"theme_color": "#4F4F4F",
"background_color": "#EBEBEB",
"orientation": "portrait"
}

View file

@ -1,13 +1,12 @@
{
"name": "alltube",
"description": "HTML GUI for youtube-dl",
"version": "0.5.2",
"version": "0.7.0",
"author": "Pierre Rudloff",
"bugs": "https://github.com/Rudloff/alltube/issues",
"dependencies": {
"bower": "~1.7.1",
"bower": "~1.8.0",
"grunt": "~1.0.1",
"grunt-cli": "~1.2.0",
"grunt-contrib-cssmin": "~1.0.0",
"grunt-contrib-uglify": "~2.0.0"
},
@ -39,6 +38,6 @@
"url": "https://github.com/Rudloff/alltube.git"
},
"scripts": {
"postinstall": "node node_modules/bower/bin/bower install && node node_modules/grunt-cli/bin/grunt"
"postinstall": "node node_modules/.bin/bower install && node node_modules/.bin/grunt"
}
}

4
phpdoc.xml Normal file
View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdoc>
<title>Alltube Download library documentation</title>
</phpdoc>

0
requirements.txt Normal file
View file

13
templates/password.tpl Normal file
View file

@ -0,0 +1,13 @@
{include file='inc/head.tpl'}
<div class="wrapper">
<div class="main">
{include file="inc/logo.tpl"}
<h2>This video is protected</h2>
<p>You need a password in order to download this video.</p>
<form action="" method="POST">
<input class="URLinput" type="password" name="password" title="Video password" />
<br/><br/>
<input class="downloadBtn" type="submit" value="Download" />
</form>
</div>
{include file='inc/footer.tpl'}

View file

@ -28,11 +28,7 @@
<optgroup label="Generic formats">
<option value="best[protocol^=http]">
{strip}
Best ({$video->ext}
{if isset($video->filesize)}
{$video->filesize}
{/if}
)
Best ({$video->ext})
{/strip}
</option>
<option value="worst[protocol^=http]">

View file

@ -2,6 +2,7 @@
/**
* ConfigTest class.
*/
namespace Alltube\Test;
use Alltube\Config;
@ -42,6 +43,17 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$this->assertInternalType('string', $this->config->rtmpdump);
}
/**
* Test the getInstance function with a missing config file.
*
* @return void
* @expectedException Exception
*/
public function testGetInstanceWithMissingFile()
{
Config::getInstance('foo');
}
/**
* Test the getInstance function with the CONVERT environment variable.
*

View file

@ -2,8 +2,10 @@
/**
* VideoDownloadTest class.
*/
namespace Alltube\Test;
use Alltube\Config;
use Alltube\VideoDownload;
/**
@ -31,7 +33,33 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/
protected function tearDown()
{
\Alltube\Config::destroyInstance();
Config::destroyInstance();
}
/**
* Test VideoDownload constructor with wrong youtube-dl path.
*
* @return void
* @expectedException Exception
*/
public function testConstructorWithMissingYoutubedl()
{
new VideoDownload(
new Config(['youtubedl' => 'foo'])
);
}
/**
* Test VideoDownload constructor with wrong Python path.
*
* @return void
* @expectedException Exception
*/
public function testConstructorWithMissingPython()
{
new VideoDownload(
new Config(['python' => 'foo'])
);
}
/**
@ -62,6 +90,38 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
$this->assertContains($domain, $videoURL);
}
/**
* Test getURL function with a protected video.
*
* @return void
*/
public function testGetURLWithPassword()
{
$this->assertContains('vimeocdn.com', $this->download->getURL('http://vimeo.com/68375962', null, 'youtube-dl'));
}
/**
* Test getURL function with a protected video and no password.
*
* @return void
* @expectedException \Alltube\PasswordException
*/
public function testGetURLWithMissingPassword()
{
$this->download->getURL('http://vimeo.com/68375962');
}
/**
* Test getURL function with a protected video and a wrong password.
*
* @return void
* @expectedException Exception
*/
public function testGetURLWithWrongPassword()
{
$this->download->getURL('http://vimeo.com/68375962', null, 'foo');
}
/**
* Test getURL function errors.
*