Merge branch 'release-0.6.0'

This commit is contained in:
Pierre Rudloff 2016-10-19 18:34:05 +02:00
commit 51ee3526fc
14 changed files with 511 additions and 282 deletions

View file

@ -1,7 +1,22 @@
language: php language: php
php:
- 5.6
install: install:
- composer install --no-dev - composer install
before_install: before_install:
- composer selfupdate - composer selfupdate
- npm install -g npm@3
after_success: after_success:
- bash <(curl -s https://codecov.io/bash) - 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=

36
FAQ.md
View file

@ -1,12 +1,17 @@
# Frequently asked questions # Frequently asked questions
<!-- markdownlint-disable MD026 -->
## My browser plays the video. How do I download it? ## 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*. You can ususally download the video by doing *File > Save to* or *ctrl + S*.
## How do I change config parameters? ## How do I change config parameters?
You need to create a YAML file called `config.yml` at the root of your project. You need to create a YAML file called `config.yml` at the root of your project.
Here are the parameters that you can set: Here are the parameters that you can set:
* youtubedl: path to your youtube-dl binary * youtubedl: path to your youtube-dl binary
* python: path to your python binary * python: path to your python binary
* params: an array of parameters to pass to youtube-dl * params: an array of parameters to pass to youtube-dl
@ -18,12 +23,43 @@ Here are the parameters that you can set:
See [config.example.yml](config.example.yml) for default values. See [config.example.yml](config.example.yml) for default values.
## How do I enable audio conversion? ## How do I enable audio conversion?
In order to enable audio conversion, you need to add this to your `config.yml` file: In order to enable audio conversion, you need to add this to your `config.yml` file:
```yaml ```yaml
convert: true convert: true
avconv: path/to/avconv avconv: path/to/avconv
``` ```
You will also need to install `avconv` and `curl` on your server: You will also need to install `avconv` and `curl` on your server:
```bash ```bash
sudo apt-get install libav-tools curl sudo apt-get install libav-tools curl
``` ```
## How do I deploy Alltube on Heroku?
Create a dyno with the following buildpacks:
* `heroku/php`
* `https://github.com/heroku/heroku-buildpack-nodejs`
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.
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: { options: {
archive: 'alltube-<%= githash.main.tag %>.zip' 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: { phpdocumentor: {

View file

@ -1,19 +1,21 @@
Alltube Download # Alltube Download
=======
HTML GUI for youtube-dl (http://alltubedownload.net/) HTML GUI for youtube-dl ([alltubedownload.net](http://alltubedownload.net/))
![Screenshot](img/screenshot.png "Alltube GUI screenshot") ![Screenshot](img/screenshot.png "Alltube GUI screenshot")
## Setup ## Setup
### From a release package ### From a release package
You can download the latest release package [here](https://github.com/Rudloff/alltube/releases). You can download the latest release package [here](https://github.com/Rudloff/alltube/releases).
You just have to unzip it on your server and it should be ready to use. You just have to unzip it on your server and it should be ready to use.
### From Git ### From Git
In order to get AllTube working, you need to use [npm](https://www.npmjs.com/) and [Composer](https://getcomposer.org/): In order to get AllTube working, you need to use [npm](https://www.npmjs.com/) and [Composer](https://getcomposer.org/):
```bash ```bash
npm install npm install
composer install composer install
@ -24,6 +26,7 @@ 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: You should also ensure that the *templates_c* folder has the right permissions:
```bash ```bash
chmod 777 templates_c/ chmod 777 templates_c/
``` ```
@ -33,19 +36,33 @@ If your web server is Apache, you need to set the `AllowOverride` setting to `Al
## Config ## Config
If you want to use a custom config, you need to create a config file: If you want to use a custom config, you need to create a config file:
```bash ```bash
cp config.example.yml config.yml cp config.example.yml config.yml
``` ```
## PHP requirements
You will need PHP 5.5 (or higher) and the following PHP modules:
* fileinfo
* intl
* mbstring
* curl
## Web server configuration ## Web server configuration
### Apache ### Apache
You will need the following modules: You will need the following modules:
* mod_mime * mod_mime
* mod_rewrite * mod_rewrite
### Nginx ### Nginx
Here is an exemple Nginx configuration: Here is an exemple Nginx configuration:
```nginx ```nginx
server { server {
server_name localhost; server_name localhost;
@ -93,17 +110,58 @@ 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 ## 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. You need [avconv](https://libav.org/avconv.html), [rtmpdump](http://rtmpdump.mplayerhq.hu/) and [curl](https://curl.haxx.se/) in order to enable conversions.
If you don't want to enable conversions, you can disable it in *config.yml*. If you don't want to enable conversions, you can disable it in `config.yml`.
On Debian-based systems: On Debian-based systems:
```bash ```bash
sudo apt-get install libav-tools rtmpdump curl 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).
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

@ -84,28 +84,34 @@ class Config
/** /**
* Config constructor. * 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 (isset($options) && is_array($options)) {
if (is_file($yamlfile)) { foreach ($options as $option => $value) {
$yaml = Yaml::parse(file_get_contents($yamlfile)); if (isset($this->$option) && isset($value)) {
if (isset($yaml) && is_array($yaml)) { $this->$option = $value;
foreach ($yaml as $param => $value) {
if (isset($this->$param) && isset($value)) {
$this->$param = $value;
}
} }
} }
} }
if (getenv('CONVERT')) { if (getenv('CONVERT')) {
$this->convert = getenv('CONVERT'); $this->convert = (bool) getenv('CONVERT');
} }
} }
/** /**
* Get singleton instance. * Get Config singleton instance from YAML config file.
* *
* @param string $yamlfile YAML config file name * @param string $yamlfile YAML config file name
* *
@ -113,9 +119,21 @@ class Config
*/ */
public static function getInstance($yamlfile = 'config.yml') public static function getInstance($yamlfile = 'config.yml')
{ {
$yamlfile = __DIR__.'/../'.$yamlfile; $yamlPath = __DIR__.'/../'.$yamlfile;
if (is_null(self::$instance) || self::$instance->file != $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; return self::$instance;

View file

@ -12,13 +12,36 @@ use Symfony\Component\Process\ProcessBuilder;
*/ */
class VideoDownload class VideoDownload
{ {
/**
* Config instance.
*
* @var Config
*/
private $config;
/**
* ProcessBuilder instance used to call Python.
*
* @var ProcessBuilder
*/
private $procBuilder;
/** /**
* VideoDownload constructor. * 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(); $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( $this->procBuilder->setPrefix(
array_merge( array_merge(
[$this->config->python, $this->config->youtubedl], [$this->config->python, $this->config->youtubedl],
@ -46,46 +69,19 @@ class VideoDownload
} }
/** /**
* Get all information about a video. * Get a property from youtube-dl.
* *
* @param string $url URL of page * @param string $url URL to parse
* @param string $format Format to use for the video * @param string $format Format
* @param string $prop Property
* *
* @return object Decoded JSON * @return string
* */ */
public function getJSON($url, $format = null) private function getProp($url, $format = null, $prop = 'dump-json')
{ {
$this->procBuilder->setArguments( $this->procBuilder->setArguments(
[ [
'--dump-json', '--'.$prop,
$url,
]
);
if (isset($format)) {
$this->procBuilder->add('-f '.$format);
}
$process = $this->procBuilder->getProcess();
$process->run();
if (!$process->isSuccessful()) {
throw new \Exception($process->getErrorOutput());
} else {
return json_decode($process->getOutput());
}
}
/**
* Get URL of video from URL of page.
*
* @param string $url URL of page
* @param string $format Format to use for the video
*
* @return string URL of video
* */
public function getURL($url, $format = null)
{
$this->procBuilder->setArguments(
[
'--get-url',
$url, $url,
] ]
); );
@ -101,6 +97,32 @@ class VideoDownload
} }
} }
/**
* Get all information about a video.
*
* @param string $url URL of page
* @param string $format Format to use for the video
*
* @return object Decoded JSON
* */
public function getJSON($url, $format = null)
{
return json_decode($this->getProp($url, $format, 'dump-json'));
}
/**
* Get URL of video from URL of page.
*
* @param string $url URL of page
* @param string $format Format to use for the video
*
* @return string URL of video
* */
public function getURL($url, $format = null)
{
return $this->getProp($url, $format, 'get-url');
}
/** /**
* Get filename of video file from URL of page. * Get filename of video file from URL of page.
* *
@ -111,22 +133,7 @@ class VideoDownload
* */ * */
public function getFilename($url, $format = null) public function getFilename($url, $format = null)
{ {
$this->procBuilder->setArguments( return trim($this->getProp($url, $format, 'get-filename'));
[
'--get-filename',
$url,
]
);
if (isset($format)) {
$this->procBuilder->add('-f '.$format);
}
$process = $this->procBuilder->getProcess();
$process->run();
if (!$process->isSuccessful()) {
throw new \Exception($process->getErrorOutput());
} else {
return trim($process->getOutput());
}
} }
/** /**
@ -149,6 +156,90 @@ 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. * Get audio stream of converted video.
* *
@ -182,62 +273,12 @@ class VideoDownload
); );
if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') { if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') {
if (!shell_exec('which '.$this->config->rtmpdump)) { $process = $this->getRtmpProcess($video);
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);
} else { } else {
if (!shell_exec('which '.$this->config->curl)) { $process = $this->getCurlProcess($video);
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);
} }
$chain = new Chain($process);
$chain->add('|', $avconvProc);
return popen($chain->getProcess()->getCommandLine(), 'r'); return popen($chain->getProcess()->getCommandLine(), 'r');
} }

View file

@ -6,20 +6,20 @@
"type": "project", "type": "project",
"require": { "require": {
"smarty/smarty": "~3.1.29", "smarty/smarty": "~3.1.29",
"rg3/youtube-dl": "~2016.09.08",
"slim/slim": "~3.5.0", "slim/slim": "~3.5.0",
"mathmarques/smarty-view": "~1.1.0", "mathmarques/smarty-view": "~1.1.0",
"symfony/yaml": "~3.1.0", "symfony/yaml": "~3.1.0",
"symfony/process": "~3.1.0", "symfony/process": "~3.1.0",
"ptachoire/process-builder-chain": "~1.2.0", "ptachoire/process-builder-chain": "~1.2.0",
"ffmpeg/ffmpeg": "dev-release", "rudloff/smarty-plugin-noscheme": "~0.1.0"
"rudloff/smarty-plugin-noscheme": "~0.1.0",
"rudloff/rtmpdump-bin": "~2.3"
}, },
"require-dev": { "require-dev": {
"symfony/var-dumper": "~3.1.0", "symfony/var-dumper": "~3.1.0",
"squizlabs/php_codesniffer": "~2.6.2", "squizlabs/php_codesniffer": "~2.7.0",
"phpunit/phpunit": "~5.5.2" "phpunit/phpunit": "~5.5.2",
"ffmpeg/ffmpeg": "dev-release",
"rg3/youtube-dl": "~2016.09.08",
"rudloff/rtmpdump-bin": "~2.3"
}, },
"extra": { "extra": {
"paas": { "paas": {

199
composer.lock generated
View file

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "a0f80c6bc52ec374622802fb83f64122", "hash": "d0a06c9bc6164cc788eb8ad3d2a9291c",
"content-hash": "8d944e2e3dfabcc3c311c954932321f1", "content-hash": "91057608d6f29b8de8a9761bb419f19c",
"packages": [ "packages": [
{ {
"name": "container-interop/container-interop", "name": "container-interop/container-interop",
@ -34,20 +34,6 @@
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)", "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"time": "2014-12-30 15:22:37" "time": "2014-12-30 15:22:37"
}, },
{
"name": "ffmpeg/ffmpeg",
"version": "dev-release",
"dist": {
"type": "xz",
"url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz",
"reference": null,
"shasum": null
},
"bin": [
"ffmpeg"
],
"type": "library"
},
{ {
"name": "jeremykendall/php-domain-parser", "name": "jeremykendall/php-domain-parser",
"version": "3.0.0", "version": "3.0.0",
@ -399,44 +385,6 @@
"description": "Add ability to chain symfony processes", "description": "Add ability to chain symfony processes",
"time": "2016-04-10 08:33:20" "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",
"source": {
"type": "git",
"url": "https://github.com/Rudloff/rtmpdump-bin.git",
"reference": "133cdd80e3bab66593e88a5276158596383afd97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97",
"reference": "133cdd80e3bab66593e88a5276158596383afd97",
"shasum": ""
},
"require-dev": {
"rtmpdump/rtmpdump": "2.3"
},
"bin": [
"rtmpdump"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0"
],
"description": "rtmpdump binary for Linux 64 bit",
"time": "2016-04-12 19:17:32"
},
{ {
"name": "rudloff/smarty-plugin-noscheme", "name": "rudloff/smarty-plugin-noscheme",
"version": "0.1.1", "version": "0.1.1",
@ -605,16 +553,16 @@
}, },
{ {
"name": "symfony/process", "name": "symfony/process",
"version": "v3.1.4", "version": "v3.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/process.git", "url": "https://github.com/symfony/process.git",
"reference": "e64e93041c80e77197ace5ab9385dedb5a143697" "reference": "66de154ae86b1a07001da9fbffd620206e4faf94"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/e64e93041c80e77197ace5ab9385dedb5a143697", "url": "https://api.github.com/repos/symfony/process/zipball/66de154ae86b1a07001da9fbffd620206e4faf94",
"reference": "e64e93041c80e77197ace5ab9385dedb5a143697", "reference": "66de154ae86b1a07001da9fbffd620206e4faf94",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -650,20 +598,20 @@
], ],
"description": "Symfony Process Component", "description": "Symfony Process Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-08-16 14:58:24" "time": "2016-09-29 14:13:09"
}, },
{ {
"name": "symfony/yaml", "name": "symfony/yaml",
"version": "v3.1.4", "version": "v3.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/yaml.git", "url": "https://github.com/symfony/yaml.git",
"reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d" "reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/f291ed25eb1435bddbe8a96caaef16469c2a092d", "url": "https://api.github.com/repos/symfony/yaml/zipball/368b9738d4033c8b93454cb0dbd45d305135a6d3",
"reference": "f291ed25eb1435bddbe8a96caaef16469c2a092d", "reference": "368b9738d4033c8b93454cb0dbd45d305135a6d3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -699,7 +647,7 @@
], ],
"description": "Symfony Yaml Component", "description": "Symfony Yaml Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"time": "2016-09-02 02:12:52" "time": "2016-09-25 08:27:07"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -757,18 +705,32 @@
], ],
"time": "2015-06-14 21:17:01" "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", "name": "myclabs/deep-copy",
"version": "1.5.2", "version": "1.5.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "da8529775f14f4fdae33f916eb0cf65f6afbddbc" "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/da8529775f14f4fdae33f916eb0cf65f6afbddbc", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
"reference": "da8529775f14f4fdae33f916eb0cf65f6afbddbc", "reference": "ea74994a3dc7f8d2f65a06009348f2d63c81e61f",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -797,7 +759,7 @@
"object", "object",
"object graph" "object graph"
], ],
"time": "2016-09-06 16:07:05" "time": "2016-09-16 13:37:59"
}, },
{ {
"name": "phpdocumentor/reflection-common", "name": "phpdocumentor/reflection-common",
@ -855,16 +817,16 @@
}, },
{ {
"name": "phpdocumentor/reflection-docblock", "name": "phpdocumentor/reflection-docblock",
"version": "3.1.0", "version": "3.1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd" "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e",
"reference": "9270140b940ff02e58ec577c237274e92cd40cdd", "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -896,7 +858,7 @@
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"time": "2016-06-10 09:48:41" "time": "2016-09-30 07:12:33"
}, },
{ {
"name": "phpdocumentor/type-resolver", "name": "phpdocumentor/type-resolver",
@ -1253,24 +1215,24 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "5.5.4", "version": "5.5.7",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "3e6e88e56c912133de6e99b87728cca7ed70c5f5" "reference": "3f67cee782c9abfaee5e32fd2f57cdd54bc257ba"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6e88e56c912133de6e99b87728cca7ed70c5f5", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3f67cee782c9abfaee5e32fd2f57cdd54bc257ba",
"reference": "3e6e88e56c912133de6e99b87728cca7ed70c5f5", "reference": "3f67cee782c9abfaee5e32fd2f57cdd54bc257ba",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-pcre": "*", "ext-libxml": "*",
"ext-reflection": "*", "ext-mbstring": "*",
"ext-spl": "*", "ext-xml": "*",
"myclabs/deep-copy": "~1.3", "myclabs/deep-copy": "~1.3",
"php": "^5.6 || ^7.0", "php": "^5.6 || ^7.0",
"phpspec/prophecy": "^1.3.1", "phpspec/prophecy": "^1.3.1",
@ -1292,7 +1254,12 @@
"conflict": { "conflict": {
"phpdocumentor/reflection-docblock": "3.0.2" "phpdocumentor/reflection-docblock": "3.0.2"
}, },
"require-dev": {
"ext-pdo": "*"
},
"suggest": { "suggest": {
"ext-tidy": "*",
"ext-xdebug": "*",
"phpunit/php-invoker": "~1.1" "phpunit/php-invoker": "~1.1"
}, },
"bin": [ "bin": [
@ -1327,20 +1294,20 @@
"testing", "testing",
"xunit" "xunit"
], ],
"time": "2016-08-26 07:11:44" "time": "2016-10-03 13:04:15"
}, },
{ {
"name": "phpunit/phpunit-mock-objects", "name": "phpunit/phpunit-mock-objects",
"version": "3.2.7", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git",
"reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a" "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/546898a2c0c356ef2891b39dd7d07f5d82c8ed0a", "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/238d7a2723bce689c79eeac9c7d5e1d623bb9dc2",
"reference": "546898a2c0c356ef2891b39dd7d07f5d82c8ed0a", "reference": "238d7a2723bce689c79eeac9c7d5e1d623bb9dc2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1386,7 +1353,45 @@
"mock", "mock",
"xunit" "xunit"
], ],
"time": "2016-09-06 16:07:45" "time": "2016-10-09 07:01:45"
},
{
"name": "rg3/youtube-dl",
"version": "2016.09.08",
"source": {
"type": "git",
"url": "https://github.com/rg3/youtube-dl.git",
"reference": "2016.09.08"
},
"type": "library"
},
{
"name": "rudloff/rtmpdump-bin",
"version": "2.3",
"source": {
"type": "git",
"url": "https://github.com/Rudloff/rtmpdump-bin.git",
"reference": "133cdd80e3bab66593e88a5276158596383afd97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97",
"reference": "133cdd80e3bab66593e88a5276158596383afd97",
"shasum": ""
},
"require-dev": {
"rtmpdump/rtmpdump": "2.3"
},
"bin": [
"rtmpdump"
],
"type": "library",
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0"
],
"description": "rtmpdump binary for Linux 64 bit",
"time": "2016-04-12 19:17:32"
}, },
{ {
"name": "sebastian/code-unit-reverse-lookup", "name": "sebastian/code-unit-reverse-lookup",
@ -1903,16 +1908,16 @@
}, },
{ {
"name": "squizlabs/php_codesniffer", "name": "squizlabs/php_codesniffer",
"version": "2.6.2", "version": "2.7.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
"reference": "4edb770cb853def6e60c93abb088ad5ac2010c83" "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/4edb770cb853def6e60c93abb088ad5ac2010c83", "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
"reference": "4edb770cb853def6e60c93abb088ad5ac2010c83", "reference": "571e27b6348e5b3a637b2abc82ac0d01e6d7bbed",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1977,7 +1982,7 @@
"phpcs", "phpcs",
"standards" "standards"
], ],
"time": "2016-07-13 23:29:13" "time": "2016-09-01 23:53:02"
}, },
{ {
"name": "symfony/polyfill-mbstring", "name": "symfony/polyfill-mbstring",
@ -2040,16 +2045,16 @@
}, },
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v3.1.4", "version": "v3.1.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "62ee73706c421654a4c840028954510277f7dfc8" "reference": "70bfe927b86ba9999aeebd829715b0bb2cd39a10"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/62ee73706c421654a4c840028954510277f7dfc8", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/70bfe927b86ba9999aeebd829715b0bb2cd39a10",
"reference": "62ee73706c421654a4c840028954510277f7dfc8", "reference": "70bfe927b86ba9999aeebd829715b0bb2cd39a10",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2099,7 +2104,7 @@
"debug", "debug",
"dump" "dump"
], ],
"time": "2016-08-31 09:05:42" "time": "2016-09-29 14:13:09"
}, },
{ {
"name": "webmozart/assert", "name": "webmozart/assert",

View file

@ -6,6 +6,7 @@ namespace Alltube\Controller;
use Alltube\Config; use Alltube\Config;
use Alltube\VideoDownload; use Alltube\VideoDownload;
use Interop\Container\ContainerInterface;
use Slim\Container; use Slim\Container;
use Slim\Http\Request; use Slim\Http\Request;
use Slim\Http\Response; use Slim\Http\Response;
@ -33,7 +34,7 @@ class FrontController
/** /**
* Slim dependency container. * Slim dependency container.
* *
* @var Container * @var ContainerInterface
*/ */
private $container; private $container;
@ -42,7 +43,7 @@ class FrontController
* *
* @param Container $container Slim dependency container * @param Container $container Slim dependency container
*/ */
public function __construct(Container $container) public function __construct(ContainerInterface $container)
{ {
$this->config = Config::getInstance(); $this->config = Config::getInstance();
$this->download = new VideoDownload(); $this->download = new VideoDownload();
@ -59,15 +60,17 @@ class FrontController
*/ */
public function index(Request $request, Response $response) public function index(Request $request, Response $response)
{ {
$this->container->view->render( if ($this->container instanceof Container) {
$response, $this->container->view->render(
'index.tpl', $response,
[ 'index.tpl',
'convert' => $this->config->convert, [
'class' => 'index', 'convert' => $this->config->convert,
'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.', 'class' => 'index',
] 'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.',
); ]
);
}
} }
/** /**
@ -80,17 +83,19 @@ class FrontController
*/ */
public function extractors(Request $request, Response $response) public function extractors(Request $request, Response $response)
{ {
$this->container->view->render( if ($this->container instanceof Container) {
$response, $this->container->view->render(
'extractors.tpl', $response,
[ 'extractors.tpl',
'extractors' => $this->download->listExtractors(), [
'class' => 'extractors', 'extractors' => $this->download->listExtractors(),
'title' => 'Supported websites', 'class' => 'extractors',
'description' => 'List of all supported websites from which Alltube Download '. 'title' => 'Supported websites',
'can extract video or audio files', 'description' => 'List of all supported websites from which Alltube Download '.
] 'can extract video or audio files',
); ]
);
}
} }
/** /**
@ -128,16 +133,18 @@ class FrontController
} }
} else { } else {
$video = $this->download->getJSON($params['url']); $video = $this->download->getJSON($params['url']);
$this->container->view->render( if ($this->container instanceof Container) {
$response, $this->container->view->render(
'video.tpl', $response,
[ 'video.tpl',
'video' => $video, [
'class' => 'video', 'video' => $video,
'title' => $video->title, 'class' => 'video',
'description' => 'Download "'.$video->title.'" from '.$video->extractor_key, 'title' => $video->title,
] 'description' => 'Download "'.$video->title.'" from '.$video->extractor_key,
); ]
);
}
} }
} else { } else {
return $response->withRedirect($this->container->get('router')->pathFor('index')); return $response->withRedirect($this->container->get('router')->pathFor('index'));
@ -155,15 +162,17 @@ class FrontController
*/ */
public function error(Request $request, Response $response, \Exception $exception) public function error(Request $request, Response $response, \Exception $exception)
{ {
$this->container->view->render( if ($this->container instanceof Container) {
$response, $this->container->view->render(
'error.tpl', $response,
[ 'error.tpl',
'errors' => $exception->getMessage(), [
'class' => 'video', 'errors' => $exception->getMessage(),
'title' => 'Error', 'class' => 'video',
] 'title' => 'Error',
); ]
);
}
return $response->withStatus(500); return $response->withStatus(500);
} }

View file

@ -13,7 +13,10 @@ $container = $app->getContainer();
$container['view'] = function ($c) { $container['view'] = function ($c) {
$view = new \Slim\Views\Smarty(__DIR__.'/templates/'); $view = new \Slim\Views\Smarty(__DIR__.'/templates/');
$view->addSlimPlugins($c['router'], $c['request']->getUri()); $smartyPlugins = new \Slim\Views\SmartyPlugins($c['router'], $c['request']->getUri());
$view->registerPlugin('function', 'path_for', [$smartyPlugins, 'pathFor']);
$view->registerPlugin('function', 'base_url', [$smartyPlugins, 'baseUrl']);
$view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme'); $view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme');

View file

@ -1,13 +1,12 @@
{ {
"name": "alltube", "name": "alltube",
"description": "HTML GUI for youtube-dl", "description": "HTML GUI for youtube-dl",
"version": "0.5.2", "version": "0.6.0",
"author": "Pierre Rudloff", "author": "Pierre Rudloff",
"bugs": "https://github.com/Rudloff/alltube/issues", "bugs": "https://github.com/Rudloff/alltube/issues",
"dependencies": { "dependencies": {
"bower": "~1.7.1", "bower": "~1.7.1",
"grunt": "~1.0.1", "grunt": "~1.0.1",
"grunt-cli": "~1.2.0",
"grunt-contrib-cssmin": "~1.0.0", "grunt-contrib-cssmin": "~1.0.0",
"grunt-contrib-uglify": "~2.0.0" "grunt-contrib-uglify": "~2.0.0"
}, },
@ -22,6 +21,9 @@
"grunt-phpdocumentor": "~0.4.1", "grunt-phpdocumentor": "~0.4.1",
"grunt-phpunit": "~0.3.6" "grunt-phpunit": "~0.3.6"
}, },
"engines": {
"npm": "~3"
},
"homepage": "https://www.alltubedownload.net/", "homepage": "https://www.alltubedownload.net/",
"keywords": [ "keywords": [
"alltube", "alltube",
@ -36,6 +38,6 @@
"url": "https://github.com/Rudloff/alltube.git" "url": "https://github.com/Rudloff/alltube.git"
}, },
"scripts": { "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>

View file

@ -42,6 +42,17 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
$this->assertInternalType('string', $this->config->rtmpdump); $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. * Test the getInstance function with the CONVERT environment variable.
* *

View file

@ -4,6 +4,7 @@
*/ */
namespace Alltube\Test; namespace Alltube\Test;
use Alltube\Config;
use Alltube\VideoDownload; use Alltube\VideoDownload;
/** /**
@ -31,7 +32,33 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
*/ */
protected function tearDown() 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'])
);
} }
/** /**