diff --git a/.gitignore b/.gitignore
index 0fb6d93..af93b59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@ vendor/
templates_c/
ffmpeg.tar.xz
ffmpeg-*/
-alltube-release.zip
+alltube-*.zip
coverage/
bower_components/
config.yml
diff --git a/.htaccess b/.htaccess
index 83d9799..8fc5b69 100644
--- a/.htaccess
+++ b/.htaccess
@@ -1,4 +1,6 @@
AddType application/x-web-app-manifest+json .webapp
+Addtype font/truetype .ttf
+
ExpiresActive On
ExpiresByType application/javascript "access plus 1 week"
@@ -6,11 +8,20 @@ AddType application/x-web-app-manifest+json .webapp
ExpiresByType image/png "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 week"
ExpiresByType image/svg+xml "access plus 1 week"
+ ExpiresByType font/truetype "access plus 1 week"
+
FileETag None
+
RewriteEngine On
+
+RewriteCond %{HTTP_HOST} ^alltube\.herokuapp\.com$ [NC]
+RewriteRule ^(.*)$ https://www.alltubedownload.net/$1 [R=301,L]
+
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
Redirect permanent /api.php /video
Redirect permanent /extractors.php /extractors
+
+AddOutputFilterByType DEFLATE text/css text/html application/javascript
diff --git a/Dockerfile b/Dockerfile
index 74e03bb..5dbf4fd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM php:apache
+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 docker-php-ext-install mbstring
diff --git a/Gruntfile.js b/Gruntfile.js
index 9998185..e18273a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -3,6 +3,11 @@ module.exports = function (grunt) {
'use strict';
grunt.initConfig(
{
+ githash: {
+ main: {
+ options: {}
+ }
+ },
uglify: {
combine: {
files: {
@@ -28,12 +33,17 @@ module.exports = function (grunt) {
}
},
phpcs: {
+ options: {
+ standard: 'PSR2'
+ },
php: {
src: ['*.php', 'classes/*.php', 'controllers/*.php']
},
tests: {
src: ['tests/*.php']
- },
+ }
+ },
+ jslint: {
js: {
src: ['js/*.js']
},
@@ -49,7 +59,7 @@ module.exports = function (grunt) {
compress: {
release: {
options: {
- archive: 'alltube-release.zip'
+ archive: 'alltube-<%= githash.main.tag %>.zip'
},
src: ['*.php', '!config.yml', 'dist/**', 'fonts/**', '.htaccess', 'img/**', 'js/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg']
}
@@ -57,15 +67,17 @@ module.exports = function (grunt) {
}
);
+ grunt.loadNpmTasks('grunt-githash');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-phpcs');
grunt.loadNpmTasks('grunt-phpunit');
grunt.loadNpmTasks('grunt-contrib-compress');
+ grunt.loadNpmTasks('grunt-jslint');
grunt.registerTask('default', ['uglify', 'cssmin']);
- grunt.registerTask('lint', ['phpcs']);
+ grunt.registerTask('lint', ['phpcs', 'jslint']);
grunt.registerTask('test', ['phpunit']);
- grunt.registerTask('release', ['default', 'compress']);
+ grunt.registerTask('release', ['default', 'githash', 'compress']);
};
diff --git a/README.md b/README.md
index 32071af..d1c767d 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,13 @@ HTML GUI for youtube-dl (http://alltubedownload.net/)
![Screenshot](img/screenshot.png "Alltube GUI screenshot")
##Setup
+
+### From a release package
+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.
+
+### From Git
In order to get AllTube working, you need to use [npm](https://www.npmjs.com/) and [Composer](https://getcomposer.org/):
npm install
@@ -27,6 +34,61 @@ If you want to use a custom config, you need to create a config file:
cp config.example.yml config.yml
+##Web server configuration
+###Apache
+You will need the following modules:
+
+* mod_mime
+* mod_rewrite
+
+###Nginx
+Here is an exemple Nginx configuration:
+
+ server {
+ server_name localhost;
+ listen 443 ssl;
+
+ root /var/www/path/to/alltube;
+ index index.php;
+
+ access_log /var/log/nginx/alltube.access.log;
+ error_log /var/log/nginx/alltube.error.log;
+
+ types {
+ text/html html htm shtml;
+ text/css css;
+ text/xml xml;
+ application/x-web-app-manifest+json webapp;
+ }
+
+ # Deny access to dotfiles
+ location ~ /\. {
+ deny all;
+ }
+
+ location / {
+ try_files $uri /index.php?$args;
+ }
+
+ location ~ \.php$ {
+ try_files $uri /index.php?$args;
+
+ fastcgi_param PATH_INFO $fastcgi_path_info;
+ fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+
+ fastcgi_pass unix:/var/run/php5-fpm.sock;
+ fastcgi_index index.php;
+ fastcgi_split_path_info ^(.+\.php)(/.+)$;
+ fastcgi_intercept_errors off;
+
+ fastcgi_buffer_size 16k;
+ fastcgi_buffers 4 16k;
+
+ include fastcgi_params;
+ }
+ }
+
##License
This software is available under the [GNU General Public License](http://www.gnu.org/licenses/gpl.html).
@@ -34,11 +96,11 @@ This software is available under the [GNU General Public License](http://www.gnu
__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) and [rtmpdump](http://rtmpdump.mplayerhq.hu/) 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*.
On Debian-based systems:
- sudo apt-get install libav-tools rtmpdump
+ sudo apt-get install libav-tools rtmpdump curl
You also probably need to edit the *avconv* variable in *config.yml* so that it points to your ffmpeg/avconv binary (*/usr/bin/avconv* on Debian/Ubuntu).
diff --git a/classes/Config.php b/classes/Config.php
index 2e2bf11..cd8dea1 100644
--- a/classes/Config.php
+++ b/classes/Config.php
@@ -11,7 +11,9 @@
* @link http://rudloff.pro
* */
namespace Alltube;
+
use Symfony\Component\Yaml\Yaml;
+
/**
* Class to manage config parameters
*
@@ -23,16 +25,17 @@ use Symfony\Component\Yaml\Yaml;
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
* @link http://rudloff.pro
* */
-Class Config
+class Config
{
- private static $_instance;
+ private static $instance;
public $youtubedl = 'vendor/rg3/youtube-dl/youtube_dl/__main__.py';
public $python = '/usr/bin/python';
- public $params = '--no-playlist --no-warnings -f best';
+ public $params = array('--no-playlist', '--no-warnings', '-f best[protocol^=http]', '--playlist-end', 1);
public $convert = false;
public $avconv = 'vendor/bin/ffmpeg';
- public $curl_params = '';
+ public $rtmpdump = 'vendor/bin/rtmpdump';
+ public $curl_params = array();
/**
* Config constructor
@@ -43,7 +46,7 @@ Class Config
if (is_file($yamlfile)) {
$yaml = Yaml::parse(file_get_contents($yamlfile));
if (isset($yaml) && is_array($yaml)) {
- foreach ($yaml as $param=>$value) {
+ foreach ($yaml as $param => $value) {
if (isset($this->$param)) {
$this->$param = $value;
}
@@ -62,9 +65,9 @@ Class Config
*/
public static function getInstance()
{
- if (is_null(self::$_instance)) {
- self::$_instance = new Config();
+ if (is_null(self::$instance)) {
+ self::$instance = new Config();
}
- return self::$_instance;
+ return self::$instance;
}
}
diff --git a/classes/VideoDownload.php b/classes/VideoDownload.php
index 9e2b435..22033cc 100644
--- a/classes/VideoDownload.php
+++ b/classes/VideoDownload.php
@@ -11,6 +11,10 @@
* @link http://rudloff.pro
* */
namespace Alltube;
+
+use Symfony\Component\Process\Process;
+use Symfony\Component\Process\ProcessBuilder;
+
/**
* Main class
*
@@ -22,25 +26,18 @@ namespace Alltube;
* @license GNU General Public License http://www.gnu.org/licenses/gpl.html
* @link http://rudloff.pro
* */
-Class VideoDownload
+class VideoDownload
{
- /**
- * Get the user agent used youtube-dl
- *
- * @return string UA
- * */
- static function getUA()
+ public function __construct()
{
- $config = Config::getInstance();
- $cmd = escapeshellcmd(
- $config->python.' '.escapeshellarg($config->youtubedl).
- ' '.$config->params
+ $this->config = Config::getInstance();
+ $this->procBuilder = new ProcessBuilder();
+ $this->procBuilder->setPrefix(
+ array_merge(
+ array($this->config->python, $this->config->youtubedl),
+ $this->config->params
+ )
);
- exec(
- $cmd.' --dump-user-agent',
- $version
- );
- return $version[0];
}
/**
@@ -48,44 +45,16 @@ Class VideoDownload
*
* @return array Extractors
* */
- static function listExtractors()
+ public function listExtractors()
{
- $config = Config::getInstance();
- $cmd = escapeshellcmd(
- $config->python.' '.escapeshellarg($config->youtubedl).
- ' '.$config->params
+ $this->procBuilder->setArguments(
+ array(
+ '--list-extractors'
+ )
);
- exec(
- $cmd.' --list-extractors',
- $extractors
- );
- return $extractors;
- }
-
- /**
- * Get filename of video
- *
- * @param string $url URL of page
- * @param string $format Format to use for the video
- *
- * @return string Filename
- * */
- static function getFilename($url, $format=null)
- {
- $config = Config::getInstance();
- $cmd = escapeshellcmd(
- $config->python.' '.escapeshellarg($config->youtubedl).
- ' '.$config->params
- );
- if (isset($format)) {
- $cmd .= ' -f '.escapeshellarg($format);
- }
- $cmd .=' --get-filename '.escapeshellarg($url)." 2>&1";
- exec(
- $cmd,
- $filename
- );
- return end($filename);
+ $process = $this->procBuilder->getProcess();
+ $process->run();
+ return explode(PHP_EOL, $process->getOutput());
}
/**
@@ -94,26 +63,25 @@ Class VideoDownload
* @param string $url URL of page
* @param string $format Format to use for the video
*
- * @return string JSON
+ * @return object Decoded JSON
* */
- static function getJSON($url, $format=null)
+ public function getJSON($url, $format = null)
{
- $config = Config::getInstance();
- $cmd = escapeshellcmd(
- $config->python.' '.escapeshellarg($config->youtubedl).
- ' '.$config->params
+ $this->procBuilder->setArguments(
+ array(
+ '--dump-json',
+ $url
+ )
);
if (isset($format)) {
- $cmd .= ' -f '.escapeshellarg($format);
+ $this->procBuilder->add('-f '.$format);
}
- $cmd .=' --dump-json '.escapeshellarg($url)." 2>&1";
- exec(
- $cmd, $result, $code
- );
- if ($code>0) {
- throw new \Exception(implode(PHP_EOL, $result));
+ $process = $this->procBuilder->getProcess();
+ $process->run();
+ if (!$process->isSuccessful()) {
+ throw new \Exception($process->getErrorOutput());
} else {
- return json_decode($result[0]);
+ return json_decode($process->getOutput());
}
}
@@ -125,24 +93,23 @@ Class VideoDownload
*
* @return string URL of video
* */
- static function getURL($url, $format=null)
+ public function getURL($url, $format = null)
{
- $config = Config::getInstance();
- $cmd = escapeshellcmd(
- $config->python.' '.escapeshellarg($config->youtubedl).
- ' '.$config->params
+ $this->procBuilder->setArguments(
+ array(
+ '--get-url',
+ $url
+ )
);
if (isset($format)) {
- $cmd .= ' -f '.escapeshellarg($format);
+ $this->procBuilder->add('-f '.$format);
}
- $cmd .=' -g '.escapeshellarg($url)." 2>&1";
- exec(
- $cmd, $result, $code
- );
- if ($code>0) {
- throw new \Exception(implode(PHP_EOL, $result));
+ $process = $this->procBuilder->getProcess();
+ $process->run();
+ if (!$process->isSuccessful()) {
+ throw new \Exception($process->getErrorOutput());
} else {
- return array('success'=>true, 'url'=>end($result));
+ return $process->getOutput();
}
}
diff --git a/composer.json b/composer.json
index dc5d1cf..56be992 100644
--- a/composer.json
+++ b/composer.json
@@ -6,15 +6,18 @@
"type": "project",
"require": {
"smarty/smarty": "~3.1.29",
- "rg3/youtube-dl": "2016.03.14",
- "slim/slim": "~2.6.2",
- "slim/views": "~0.1.3",
+ "rg3/youtube-dl": "~2016.07.26",
+ "slim/slim": "~3.5.0",
+ "mathmarques/smarty-view": "~1.1.0",
+ "symfony/yaml": "~3.1.0",
+ "symfony/process": "~3.1.0",
+ "ptachoire/process-builder-chain": "~1.2.0",
+ "ffmpeg/ffmpeg": "dev-release",
"rudloff/smarty-plugin-noscheme": "~0.1.0",
- "symfony/yaml": "~3.0.0",
- "ffmpeg/ffmpeg": "~2.8.2"
+ "rudloff/rtmpdump-bin": "~2.3"
},
"require-dev": {
- "symfony/var-dumper": "~3.0.0"
+ "symfony/var-dumper": "~3.1.0"
},
"extra": {
"paas": {
@@ -27,18 +30,18 @@
"type": "package",
"package": {
"name": "rg3/youtube-dl",
- "version": "2016.03.14",
+ "version": "2016.07.26",
"source": {
"url": "https://github.com/rg3/youtube-dl.git",
"type": "git",
- "reference": "2016.03.14"
+ "reference": "2016.07.26"
}
}
}, {
"type": "package",
"package": {
"name": "ffmpeg/ffmpeg",
- "version": "2.8.4",
+ "version": "dev-release",
"dist": {
"url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz",
"type": "xz"
diff --git a/composer.lock b/composer.lock
index d4fa979..17a3e32 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,12 +4,39 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "d4b9e76dbda3af97316a38bfe163ac00",
- "content-hash": "6eb27104cc39af34f798d35fb3f381ac",
+ "hash": "2afe3e4c1f053ce8a1dc13887ea3aa8c",
+ "content-hash": "2c86697f5f04b91631cd33dbedce3179",
"packages": [
+ {
+ "name": "container-interop/container-interop",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/container-interop/container-interop.git",
+ "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
+ "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
+ "shasum": ""
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Interop\\Container\\": "src/Interop/Container/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
+ "time": "2014-12-30 15:22:37"
+ },
{
"name": "ffmpeg/ffmpeg",
- "version": "2.8.4",
+ "version": "dev-release",
"dist": {
"type": "xz",
"url": "http://johnvansickle.com/ffmpeg/releases/ffmpeg-release-64bit-static.tar.xz",
@@ -85,16 +112,16 @@
},
{
"name": "league/uri",
- "version": "4.1.0",
+ "version": "4.1.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/uri.git",
- "reference": "a4f0ea3323745214c955af2f6451d7743f30a076"
+ "reference": "0cbce9fe7d9808690ebda67b110ad96bcae9daee"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/thephpleague/uri/zipball/a4f0ea3323745214c955af2f6451d7743f30a076",
- "reference": "a4f0ea3323745214c955af2f6451d7743f30a076",
+ "url": "https://api.github.com/repos/thephpleague/uri/zipball/0cbce9fe7d9808690ebda67b110ad96bcae9daee",
+ "reference": "0cbce9fe7d9808690ebda67b110ad96bcae9daee",
"shasum": ""
},
"require": {
@@ -145,7 +172,146 @@
"url",
"ws"
],
- "time": "2016-02-18 14:46:01"
+ "time": "2016-03-24 08:38:29"
+ },
+ {
+ "name": "mathmarques/smarty-view",
+ "version": "1.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mathmarques/Smarty-View.git",
+ "reference": "66f4d28c564c0363eda18d3f5b85a4241b1c4ad1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mathmarques/Smarty-View/zipball/66f4d28c564c0363eda18d3f5b85a4241b1c4ad1",
+ "reference": "66f4d28c564c0363eda18d3f5b85a4241b1c4ad1",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.0",
+ "slim/slim": "^3.0",
+ "smarty/smarty": "~3.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Slim\\Views\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Matheus Marques",
+ "email": "matheusocmarques@gmail.com",
+ "homepage": "http://matheusmarques.com"
+ }
+ ],
+ "description": "Slim Framework 3 view helper built on top of the Smarty templating component",
+ "keywords": [
+ "framework",
+ "slim",
+ "slim 3",
+ "smarty",
+ "template",
+ "view"
+ ],
+ "time": "2016-03-31 00:41:59"
+ },
+ {
+ "name": "nikic/fast-route",
+ "version": "v1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/FastRoute.git",
+ "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/FastRoute/zipball/8ea928195fa9b907f0d6e48312d323c1a13cc2af",
+ "reference": "8ea928195fa9b907f0d6e48312d323c1a13cc2af",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "FastRoute\\": "src/"
+ },
+ "files": [
+ "src/functions.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov",
+ "email": "nikic@php.net"
+ }
+ ],
+ "description": "Fast request router for PHP",
+ "keywords": [
+ "router",
+ "routing"
+ ],
+ "time": "2016-06-12 19:08:51"
+ },
+ {
+ "name": "pimple/pimple",
+ "version": "v3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/silexphp/Pimple.git",
+ "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
+ "reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "Pimple": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ }
+ ],
+ "description": "Pimple, a simple Dependency Injection Container",
+ "homepage": "http://pimple.sensiolabs.org",
+ "keywords": [
+ "container",
+ "dependency injection"
+ ],
+ "time": "2015-09-11 15:10:35"
},
{
"name": "psr/http-message",
@@ -196,37 +362,106 @@
],
"time": "2015-05-04 20:22:00"
},
+ {
+ "name": "ptachoire/process-builder-chain",
+ "version": "1.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/krichprollsch/process-builder-chain.git",
+ "reference": "465055dbcc3b5ef792a768df935571551de4781a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/krichprollsch/process-builder-chain/zipball/465055dbcc3b5ef792a768df935571551de4781a",
+ "reference": "465055dbcc3b5ef792a768df935571551de4781a",
+ "shasum": ""
+ },
+ "require": {
+ "symfony/process": "~2.5 || ~3.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Chain": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Pierre Tachoire",
+ "email": "pierre.tachoire@gmail.com"
+ }
+ ],
+ "description": "Add ability to chain symfony processes",
+ "time": "2016-04-10 08:33:20"
+ },
{
"name": "rg3/youtube-dl",
- "version": "2016.03.14",
+ "version": "2016.07.26",
"source": {
"type": "git",
"url": "https://github.com/rg3/youtube-dl.git",
- "reference": "2016.03.14"
+ "reference": "2016.07.26"
},
"type": "library"
},
{
- "name": "rudloff/smarty-plugin-noscheme",
- "version": "0.1.0",
+ "name": "rudloff/rtmpdump-bin",
+ "version": "2.3",
"source": {
"type": "git",
- "url": "https://github.com/Rudloff/smarty-plugin-noscheme.git",
- "reference": "537bcb2f7576252af70d8f9f817bfe050d873072"
+ "url": "https://github.com/Rudloff/rtmpdump-bin.git",
+ "reference": "133cdd80e3bab66593e88a5276158596383afd97"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Rudloff/smarty-plugin-noscheme/zipball/537bcb2f7576252af70d8f9f817bfe050d873072",
- "reference": "537bcb2f7576252af70d8f9f817bfe050d873072",
+ "url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97",
+ "reference": "133cdd80e3bab66593e88a5276158596383afd97",
+ "shasum": ""
+ },
+ "require-dev": {
+ "rtmpdump/rtmpdump": "2.3"
+ },
+ "bin": [
+ "rtmpdump"
+ ],
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0"
+ ],
+ "description": "rtmpdump binary for Linux 64 bit",
+ "time": "2016-04-12 19:17:32"
+ },
+ {
+ "name": "rudloff/smarty-plugin-noscheme",
+ "version": "0.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Rudloff/smarty-plugin-noscheme.git",
+ "reference": "7b64350bd255690e44db497e50bb5edc5e87d5e6"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Rudloff/smarty-plugin-noscheme/zipball/7b64350bd255690e44db497e50bb5edc5e87d5e6",
+ "reference": "7b64350bd255690e44db497e50bb5edc5e87d5e6",
"shasum": ""
},
"require": {
- "league/uri": "~4.0"
+ "league/uri": "~4.1.1"
},
"require-dev": {
- "symfony/var-dumper": "~2.7.6"
+ "symfony/var-dumper": "~3.0.1"
},
"type": "library",
+ "autoload": {
+ "files": [
+ "modifier.noscheme.php"
+ ]
+ },
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-3.0"
@@ -240,80 +475,40 @@
}
],
"description": "Smarty modifier that removes the scheme in URLs",
- "time": "2015-10-31 10:25:47"
+ "time": "2016-04-09 00:40:13"
},
{
"name": "slim/slim",
- "version": "2.6.2",
+ "version": "3.5.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
- "reference": "20a02782f76830b67ae56a5c08eb1f563c351a37"
+ "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim/zipball/20a02782f76830b67ae56a5c08eb1f563c351a37",
- "reference": "20a02782f76830b67ae56a5c08eb1f563c351a37",
+ "url": "https://api.github.com/repos/slimphp/Slim/zipball/184352bc1913d7ba552ab4131d62f4730ddb0893",
+ "reference": "184352bc1913d7ba552ab4131d62f4730ddb0893",
"shasum": ""
},
"require": {
- "php": ">=5.3.0"
+ "container-interop/container-interop": "^1.1",
+ "nikic/fast-route": "^1.0",
+ "php": ">=5.5.0",
+ "pimple/pimple": "^3.0",
+ "psr/http-message": "^1.0"
},
- "suggest": {
- "ext-mcrypt": "Required for HTTP cookie encryption"
+ "provide": {
+ "psr/http-message-implementation": "1.0"
},
- "type": "library",
- "autoload": {
- "psr-0": {
- "Slim": "."
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Josh Lockhart",
- "email": "info@joshlockhart.com",
- "homepage": "http://www.joshlockhart.com/"
- }
- ],
- "description": "Slim Framework, a PHP micro framework",
- "homepage": "http://github.com/codeguy/Slim",
- "keywords": [
- "microframework",
- "rest",
- "router"
- ],
- "time": "2015-03-08 18:41:17"
- },
- {
- "name": "slim/views",
- "version": "0.1.3",
- "source": {
- "type": "git",
- "url": "https://github.com/slimphp/Slim-Views.git",
- "reference": "8561c785e55a39df6cb6f95c3aba3281a60ed5b0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/slimphp/Slim-Views/zipball/8561c785e55a39df6cb6f95c3aba3281a60ed5b0",
- "reference": "8561c785e55a39df6cb6f95c3aba3281a60ed5b0",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0",
- "slim/slim": ">=2.4.0"
- },
- "suggest": {
- "smarty/smarty": "Smarty templating system",
- "twig/twig": "Twig templating system"
+ "require-dev": {
+ "phpunit/phpunit": "^4.0",
+ "squizlabs/php_codesniffer": "^2.5"
},
"type": "library",
"autoload": {
"psr-4": {
- "Slim\\Views\\": "./"
+ "Slim\\": "Slim"
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -321,25 +516,36 @@
"MIT"
],
"authors": [
+ {
+ "name": "Rob Allen",
+ "email": "rob@akrabat.com",
+ "homepage": "http://akrabat.com"
+ },
{
"name": "Josh Lockhart",
- "email": "info@joshlockhart.com",
- "homepage": "http://www.joshlockhart.com/"
+ "email": "hello@joshlockhart.com",
+ "homepage": "https://joshlockhart.com"
+ },
+ {
+ "name": "Gabriel Manricks",
+ "email": "gmanricks@me.com",
+ "homepage": "http://gabrielmanricks.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
- "homepage": "http://thoughts.silentworks.co.uk/"
+ "homepage": "http://silentworks.co.uk"
}
],
- "description": "Smarty and Twig View Parser package for the Slim Framework",
- "homepage": "http://github.com/codeguy/Slim-Views",
+ "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
+ "homepage": "http://slimframework.com",
"keywords": [
- "extensions",
- "slimphp",
- "templating"
+ "api",
+ "framework",
+ "micro",
+ "router"
],
- "time": "2014-12-09 23:48:51"
+ "time": "2016-07-26 15:12:13"
},
{
"name": "smarty/smarty",
@@ -397,17 +603,17 @@
"time": "2015-12-21 01:57:06"
},
{
- "name": "symfony/yaml",
- "version": "v3.0.3",
+ "name": "symfony/process",
+ "version": "v3.1.2",
"source": {
"type": "git",
- "url": "https://github.com/symfony/yaml.git",
- "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c"
+ "url": "https://github.com/symfony/process.git",
+ "reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/yaml/zipball/b5ba64cd67ecd6887f63868fa781ca094bd1377c",
- "reference": "b5ba64cd67ecd6887f63868fa781ca094bd1377c",
+ "url": "https://api.github.com/repos/symfony/process/zipball/5c11a1a4d4016662eeaf0f8757958c7de069f9a0",
+ "reference": "5c11a1a4d4016662eeaf0f8757958c7de069f9a0",
"shasum": ""
},
"require": {
@@ -416,7 +622,56 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Process\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony Process Component",
+ "homepage": "https://symfony.com",
+ "time": "2016-06-29 05:42:25"
+ },
+ {
+ "name": "symfony/yaml",
+ "version": "v3.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/yaml.git",
+ "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/yaml/zipball/2884c26ce4c1d61aebf423a8b912950fe7c764de",
+ "reference": "2884c26ce4c1d61aebf423a8b912950fe7c764de",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5.9"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -443,22 +698,22 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
- "time": "2016-02-23 15:16:06"
+ "time": "2016-06-29 05:41:56"
}
],
"packages-dev": [
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.1.1",
+ "version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "1289d16209491b584839022f29257ad859b8532d"
+ "reference": "dff51f72b0706335131b00a7f49606168c582594"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d",
- "reference": "1289d16209491b584839022f29257ad859b8532d",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594",
+ "reference": "dff51f72b0706335131b00a7f49606168c582594",
"shasum": ""
},
"require": {
@@ -470,7 +725,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.1-dev"
+ "dev-master": "1.2-dev"
}
},
"autoload": {
@@ -504,20 +759,20 @@
"portable",
"shim"
],
- "time": "2016-01-20 09:13:37"
+ "time": "2016-05-18 14:26:46"
},
{
"name": "symfony/var-dumper",
- "version": "v3.0.3",
+ "version": "v3.1.2",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
- "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074"
+ "reference": "39492b8b8fe514163e677bf154fd80f6cc995759"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9a6a883c48acb215d4825ce9de61dccf93d62074",
- "reference": "9a6a883c48acb215d4825ce9de61dccf93d62074",
+ "url": "https://api.github.com/repos/symfony/var-dumper/zipball/39492b8b8fe514163e677bf154fd80f6cc995759",
+ "reference": "39492b8b8fe514163e677bf154fd80f6cc995759",
"shasum": ""
},
"require": {
@@ -533,7 +788,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-master": "3.1-dev"
}
},
"autoload": {
@@ -567,12 +822,14 @@
"debug",
"dump"
],
- "time": "2016-02-13 09:23:44"
+ "time": "2016-06-29 05:41:56"
}
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {
+ "ffmpeg/ffmpeg": 20
+ },
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
diff --git a/composer.phar b/composer.phar
deleted file mode 100755
index 185064f..0000000
Binary files a/composer.phar and /dev/null differ
diff --git a/config.example.yml b/config.example.yml
index 0734d4d..9f66ab7 100644
--- a/config.example.yml
+++ b/config.example.yml
@@ -1,6 +1,12 @@
youtubedl: vendor/rg3/youtube-dl/youtube_dl/__main__.py
python: /usr/bin/python
-params: --no-playlist --no-warnings -f best
+params:
+ - --no-playlist
+ - --no-warnings
+ - -f best[protocol^=http]
+ - --playlist-end
+ - 1
curl_params:
convert: false
avconv: vendor/bin/ffmpeg
+rtmpdump: vendor/bin/rtmpdump
diff --git a/controllers/FrontController.php b/controllers/FrontController.php
index 8a1074f..9eed80f 100644
--- a/controllers/FrontController.php
+++ b/controllers/FrontController.php
@@ -11,8 +11,15 @@
* @link http://rudloff.pro
* */
namespace Alltube\Controller;
+
use Alltube\VideoDownload;
use Alltube\Config;
+use Symfony\Component\Process\ProcessBuilder;
+use Chain\Chain;
+use Slim\Http\Stream;
+use Slim\Http\Request;
+use Slim\Http\Response;
+
/**
* Main controller
*
@@ -26,177 +33,251 @@ use Alltube\Config;
* */
class FrontController
{
+ public function __construct($container)
+ {
+ $this->config = Config::getInstance();
+ $this->download = new VideoDownload();
+ $this->container = $container;
+ }
/**
* Display index page
*
+ * @param Request $request PSR-7 request
+ * @param Response $response PSR-7 response
+ *
* @return void
*/
- static function index()
+ public function index(Request $request, Response $response)
{
- global $app;
- $config = Config::getInstance();
- $app->render(
+ $this->container->view->render(
+ $response,
'head.tpl',
array(
- 'class'=>'index'
+ 'class'=>'index',
+ 'description'=>'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.'
)
);
- $app->render(
+ $this->container->view->render(
+ $response,
'header.tpl'
);
- $app->render(
+ $this->container->view->render(
+ $response,
'index.tpl',
array(
- 'convert'=>$config->convert
+ 'convert'=>$this->config->convert
)
);
- $app->render('footer.tpl');
+ $this->container->view->render($response, 'footer.tpl');
}
/**
* Display a list of extractors
*
+ * @param Request $request PSR-7 request
+ * @param Response $response PSR-7 response
+ *
* @return void
*/
- static function extractors()
+ public function extractors(Request $request, Response $response)
{
- global $app;
- $app->render(
+ $this->container->view->render(
+ $response,
'head.tpl',
array(
- 'class'=>'extractors'
+ 'class'=>'extractors',
+ 'title'=>'Supported websites',
+ 'description'
+ =>'List of all supported websites from which Alltube Download can extract video or audio files'
)
);
- $app->render('header.tpl');
- $app->render('logo.tpl');
- $app->render(
+ $this->container->view->render($response, 'header.tpl');
+ $this->container->view->render($response, 'logo.tpl');
+ $this->container->view->render(
+ $response,
'extractors.tpl',
array(
- 'extractors'=>VideoDownload::listExtractors()
+ 'extractors'=>$this->download->listExtractors()
)
);
- $app->render('footer.tpl');
+ $this->container->view->render($response, 'footer.tpl');
}
/**
* Dislay information about the video
*
+ * @param Request $request PSR-7 request
+ * @param Response $response PSR-7 response
+ *
* @return void
*/
- static function video()
+ public function video(Request $request, Response $response)
{
- global $app;
- $config = Config::getInstance();
- if (isset($_GET["url"])) {
- if (isset($_GET['audio'])) {
+ $params = $request->getQueryParams();
+ $this->config = Config::getInstance();
+ if (isset($params["url"])) {
+ if (isset($params['audio'])) {
try {
- $video = VideoDownload::getJSON($_GET["url"]);
+ $url = $this->download->getURL($params["url"], 'mp3[protocol^=http]');
+ return $response->withRedirect($url);
+ } catch (\Exception $e) {
+ $video = $this->download->getJSON($params["url"], 'bestaudio/best');
+
+ if (!shell_exec('which '.$this->config->avconv)) {
+ throw(new \Exception('Can\'t find avconv or ffmpeg'));
+ }
+
+ $avconvProc = ProcessBuilder::create(
+ array(
+ $this->config->avconv,
+ '-v', 'quiet',
+ '-i', '-',
+ '-f', 'mp3',
+ '-vn',
+ 'pipe:1'
+ )
+ );
//Vimeo needs a correct user-agent
- $UA = VideoDownload::getUA();
ini_set(
'user_agent',
- $UA
+ $video->http_headers->{'User-Agent'}
);
- $url_info = parse_url($video->url);
- if ($url_info['scheme'] == 'rtmp') {
- ob_end_flush();
- header(
- 'Content-Disposition: attachment; filename="'.
- html_entity_decode(
- pathinfo(
- VideoDownload::getFilename(
- $video->webpage_url
- ), PATHINFO_FILENAME
- ).'.mp3', ENT_COMPAT, 'ISO-8859-1'
- ).'"'
+
+ $response = $response->withHeader(
+ 'Content-Disposition',
+ 'attachment; filename="'.
+ html_entity_decode(
+ pathinfo(
+ $video->_filename,
+ PATHINFO_FILENAME
+ ).'.mp3',
+ ENT_COMPAT,
+ 'ISO-8859-1'
+ ).'"'
+ );
+ $response = $response->withHeader('Content-Type', 'audio/mpeg');
+
+ if (parse_url($video->url, PHP_URL_SCHEME) == 'rtmp') {
+ if (!shell_exec('which '.$this->config->rtmpdump)) {
+ throw(new \Exception('Can\'t find rtmpdump'));
+ }
+ $builder = new ProcessBuilder(
+ array(
+ $this->config->rtmpdump,
+ '-q',
+ '-r',
+ $video->url,
+ '--pageUrl', $video->webpage_url
+ )
);
- header("Content-Type: audio/mpeg");
- passthru(
- '/usr/bin/rtmpdump -q -r '.escapeshellarg($video->url).
- ' | '.$config->avconv.
- ' -v quiet -i - -f mp3 -vn pipe:1'
- );
- exit;
+ if (isset($video->player_url)) {
+ $builder->add('--swfVfy');
+ $builder->add($video->player_url);
+ }
+ if (isset($video->flash_version)) {
+ $builder->add('--flashVer');
+ $builder->add($video->flash_version);
+ }
+ if (isset($video->play_path)) {
+ $builder->add('--playpath');
+ $builder->add($video->play_path);
+ }
+ foreach ($video->rtmp_conn as $conn) {
+ $builder->add('--conn');
+ $builder->add($conn);
+ }
+ $chain = new Chain($builder->getProcess());
+ $chain->add('|', $avconvProc);
} else {
- ob_end_flush();
- header(
- 'Content-Disposition: attachment; filename="'.
- html_entity_decode(
- pathinfo(
- VideoDownload::getFilename(
- $video->webpage_url
- ), PATHINFO_FILENAME
- ).'.mp3', ENT_COMPAT, 'ISO-8859-1'
- ).'"'
+ if (!shell_exec('which curl')) {
+ throw(new \Exception('Can\'t find curl'));
+ }
+ $chain = new Chain(
+ ProcessBuilder::create(
+ array_merge(
+ array(
+ 'curl',
+ '--silent',
+ '--user-agent', $video->http_headers->{'User-Agent'},
+ $video->url
+ ),
+ $this->config->curl_params
+ )
+ )
);
- header("Content-Type: audio/mpeg");
- passthru(
- 'curl '.$config->curl_params.
- ' --user-agent '.escapeshellarg($UA).
- ' '.escapeshellarg($video->url).
- ' | '.$config->avconv.
- ' -v quiet -i - -f mp3 -vn pipe:1'
- );
- exit;
+ $chain->add('|', $avconvProc);
}
- } catch (\Exception $e) {
- $error = $e->getMessage();
+ if ($request->isGet()) {
+ $response = $response->withBody(new Stream(popen($chain->getProcess()->getCommandLine(), 'r')));
+ }
+ return $response;
}
} else {
- try {
- $video = VideoDownload::getJSON($_GET["url"]);
- $app->render(
- 'head.tpl',
- array(
- 'class'=>'video'
- )
- );
- $app->render(
- 'video.tpl',
- array(
- 'video'=>$video
- )
- );
- $app->render('footer.tpl');
- } catch (\Exception $e) {
- $error = $e->getMessage();
- }
+ $video = $this->download->getJSON($params["url"]);
+ $this->container->view->render(
+ $response,
+ 'head.tpl',
+ array(
+ 'class'=>'video',
+ 'title'=>$video->title,
+ 'description'=>'Download "'.$video->title.'" from '.$video->extractor_key
+ )
+ );
+ $this->container->view->render(
+ $response,
+ 'video.tpl',
+ array(
+ 'video'=>$video
+ )
+ );
+ $this->container->view->render($response, 'footer.tpl');
}
+ } else {
+ return $response->withRedirect($this->container->get('router')->pathFor('index'));
}
- if (isset($error)) {
- $app->render(
- 'head.tpl',
- array(
- 'class'=>'video'
- )
- );
- $app->render(
- 'error.tpl',
- array(
- 'errors'=>$error
- )
- );
- $app->render('footer.tpl');
- }
+ }
+
+ public function error(Request $request, Response $response, \Exception $exception)
+ {
+ $this->container->view->render(
+ $response,
+ 'head.tpl',
+ array(
+ 'class'=>'video',
+ 'title'=>'Error'
+ )
+ );
+ $this->container->view->render(
+ $response,
+ 'error.tpl',
+ array(
+ 'errors'=>$exception->getMessage()
+ )
+ );
+ $this->container->view->render($response, 'footer.tpl');
+ return $response->withStatus(500);
}
/**
* Redirect to video file
*
+ * @param Request $request PSR-7 request
+ * @param Response $response PSR-7 response
+ *
* @return void
*/
- static function redirect()
+ public function redirect(Request $request, Response $response)
{
- global $app;
- if (isset($_GET["url"])) {
+ $params = $request->getQueryParams();
+ if (isset($params["url"])) {
try {
- $video = VideoDownload::getURL($_GET["url"]);
- $app->redirect($video['url']);
+ $url = $this->download->getURL($params["url"], $params["format"]);
+ return $response->withRedirect($url);
} catch (\Exception $e) {
- $app->response->headers->set('Content-Type', 'text/plain');
- echo $e->getMessage().PHP_EOL;
+ $response->getBody()->write($e->getMessage());
+ return $response->withHeader('Content-Type', 'text/plain');
}
}
}
@@ -204,18 +285,22 @@ class FrontController
/**
* Output JSON info about the video
*
+ * @param Request $request PSR-7 request
+ * @param Response $response PSR-7 response
+ *
* @return void
*/
- static function json()
+ public function json(Request $request, Response $response)
{
- global $app;
- if (isset($_GET["url"])) {
- $app->response->headers->set('Content-Type', 'application/json');
+ $params = $request->getQueryParams();
+ if (isset($params["url"])) {
try {
- $video = VideoDownload::getJSON($_GET["url"]);
- echo json_encode($video);
+ $video = $this->download->getJSON($params["url"]);
+ return $response->withJson($video);
} catch (\Exception $e) {
- echo json_encode(array('success'=>false, 'error'=>$e->getMessage()));
+ return $response->withJson(
+ array('success'=>false, 'error'=>$e->getMessage())
+ );
}
}
}
diff --git a/css/style.css b/css/style.css
index c456cf5..1c5c8e7 100644
--- a/css/style.css
+++ b/css/style.css
@@ -8,8 +8,8 @@ body {
-/************************HEADER******************************/
-
+/************************HEADER******************************/
+
header {
position:absolute;
top:0;
@@ -17,11 +17,11 @@ header {
width:100%;
padding:0;
}
-
+
.social
{padding-right:21px;}
-
+
header a
{
overflow:hidden;
@@ -37,7 +37,7 @@ background-repeat:no-repeat;
-webkit-transition: all 0.1s ease-in;
-moz-transition: all 0.1s ease-in;
-o-transition: all 0.1s ease-in;
-}
+}
header a:focus,
header a:hover
@@ -51,8 +51,8 @@ header a:hover
.share
{background-image:url('../img/share.png');}
-
-.sharemask
+
+.sharemask
{
height:38px;
width:38px;
@@ -64,11 +64,11 @@ background-image:url('../img/sharemask.png');
background-position:top left;
background-repeat:no-repeat;
}
-
+
.facebook
{background-image:url('../img/facebook.png');}
-
-.facebookmask
+
+.facebookmask
{
height:38px;
width:38px;
@@ -79,12 +79,12 @@ z-index:10;
background-image:url('../img/facebookmask.png');
background-position:top left;
background-repeat:no-repeat;
-}
-
+}
+
.twitter
{background-image:url('../img/twitter.png');}
-
-.twittermask
+
+.twittermask
{
height:38px;
width:38px;
@@ -95,13 +95,13 @@ z-index:10;
background-image:url('../img/twittermask.png');
background-position:top left;
background-repeat:no-repeat;
-}
+}
+
-
/*************************FOOTER****************************/
-
-
+
+
footer {
position:fixed;
bottom:0;
@@ -119,7 +119,7 @@ footer {
.footer_wrapper {
height:28px;
}
-
+
footer a{
color:#adadad;
-webkit-transition: all 0.1s ease-in;
@@ -137,7 +137,7 @@ color:#f2084a;
-moz-transition: all 0.1s ease-in;
-o-transition: all 0.1s ease-in;
}
-
+
@@ -180,7 +180,7 @@ margin-top:8px;
text-decoration:none;
display:inline-block;
}
-
+
.downloadBtn:focus,
.downloadBtn:hover
{
@@ -248,7 +248,7 @@ color:#f2084a;
-moz-transition: all 0.1s ease-in;
-o-transition: all 0.1s ease-in;
}
-
+
#bookmarklet{
padding:15px;
}
@@ -265,7 +265,7 @@ padding-top:10px;
padding-bottom:10px;
border: 2px dotted;
}
-
+
.mp3
{
position:relative;
@@ -279,17 +279,17 @@ border: 2px dotted;
text-align:left;
font-weight:300;
}
-
+
.mp3 p
{
padding:3px;
-}
+}
/*
Demo CSS code
*/
-
+
.audio:not(:checked),
.audio:checked {
position: absolute;
@@ -337,10 +337,10 @@ padding:3px;
.audio:focus + label {
color:black;
}
-
+
/* on checked */
.audio:checked + label:before {
- background:#f2084a;
+ background:#f2084a;
}
.audio:checked + label:after {
background: #fff;
@@ -402,7 +402,7 @@ padding:3px;
-
+
/*************************CONTENT COMPATIBLES****************************/
@@ -565,24 +565,29 @@ h1 {
margin-bottom: 1em;
}
+.monospace {
+ font-family:monospace;
+}
+
@media (max-width: 640px) {
+ .formats,
.thumb {
width:90%;
}
-
+
.URLinput{
min-width:0;
}
-
+
.logo {
max-width:330px;
}
-
+
.logocompatible,
.logocompatible img {
max-width:447px;
}
-
+
.logocompatible,
.logo,
.champs,
@@ -592,64 +597,70 @@ h1 {
margin:auto;
height:auto;
}
-
+
.logo {
margin-top:50px;
}
-
+
.logocompatible img {
width:100%;
height: auto;
}
-
+
.downloadBtn {
margin-top: 0.3em;
}
.mp3 {
margin-bottom: 1em;
}
-
+
footer {
display:none;
}
-
+
.tripleliste ul,
.tripleliste {
width:auto;
margin-left:auto;
margin-top:auto;
}
-
+
.logocompatiblemask {
background:none;
}
-
+
.logocompatible {
height:auto;
background-image:none;
background-color:#4F4F4F;
}
-
+
.logocompatiblemask,
.logobis {
width:auto;
}
-
+
.logocompatiblemask {
position:static;
}
-
+
.logobis {
height:auto;
}
-
+
.titre {
margin:auto;
}
-
+
.error p {
padding:0.5em;
text-align:left;
}
-
+
+}
+
+@media all and (display-mode: standalone) {
+ .bookmarklet_wrapper {
+ display: none;
+ }
}
diff --git a/error.html b/error.html
index 81b5d00..b3ac86c 100644
--- a/error.html
+++ b/error.html
@@ -1,5 +1,5 @@
-
+
@@ -9,7 +9,7 @@
-
An error occurred in the application and your page could not be served. Please try again in a few moments.
diff --git a/img/favicon.png b/img/favicon.png
index 217cb72..b097f07 100644
Binary files a/img/favicon.png and b/img/favicon.png differ
diff --git a/img/logo.png b/img/logo.png
index c31d06c..a5f2054 100644
Binary files a/img/logo.png and b/img/logo.png differ
diff --git a/img/logo_250.png b/img/logo_250.png
index a83aed0..fd3a030 100644
Binary files a/img/logo_250.png and b/img/logo_250.png differ
diff --git a/img/logo_60.png b/img/logo_60.png
index 338185e..9a60f0a 100644
Binary files a/img/logo_60.png and b/img/logo_60.png differ
diff --git a/img/logo_90.png b/img/logo_90.png
index a6b9a86..7964b7c 100644
Binary files a/img/logo_90.png and b/img/logo_90.png differ
diff --git a/img/logo_app.png b/img/logo_app.png
index 7ca733e..6fc6f37 100644
Binary files a/img/logo_app.png and b/img/logo_app.png differ
diff --git a/img/logocompatiblemask.png b/img/logocompatiblemask.png
index 85078f6..40de155 100644
Binary files a/img/logocompatiblemask.png and b/img/logocompatiblemask.png differ
diff --git a/img/mp3hover.png b/img/mp3hover.png
index c79fa6c..402cdfc 100644
Binary files a/img/mp3hover.png and b/img/mp3hover.png differ
diff --git a/img/screenshot.png b/img/screenshot.png
index 261ca65..c75201a 100644
Binary files a/img/screenshot.png and b/img/screenshot.png differ
diff --git a/img/twitter.png b/img/twitter.png
index f9cae65..c997081 100644
Binary files a/img/twitter.png and b/img/twitter.png differ
diff --git a/index.php b/index.php
index 181ffa0..e9cee6f 100644
--- a/index.php
+++ b/index.php
@@ -14,35 +14,47 @@
* */
require_once __DIR__.'/vendor/autoload.php';
use Alltube\VideoDownload;
+use Alltube\Controller\FrontController;
+
+if (strpos($_SERVER['REQUEST_URI'], '/index.php') !== false) {
+ header('Location: '.str_ireplace('/index.php', '/', $_SERVER['REQUEST_URI']));
+ die;
+}
+
+$app = new \Slim\App();
+$container = $app->getContainer();
+$container['view'] = function ($c) {
+ $view = new \Slim\Views\Smarty(__DIR__.'/templates/');
+
+ $view->addSlimPlugins($c['router'], $c['request']->getUri());
+ $view->registerPlugin('modifier', 'noscheme', 'Smarty_Modifier_noscheme');
+
+
+ return $view;
+};
+
+$controller = new FrontController($container);
+
+$container['errorHandler'] = array($controller, 'error');
-$app = new \Slim\Slim(
- array(
- 'view' => new \Slim\Views\Smarty()
- )
-);
-$view = $app->view();
-$view->parserExtensions = array(
- __DIR__.'/vendor/slim/views/SmartyPlugins',
- __DIR__.'/vendor/rudloff/smarty-plugin-noscheme/'
-);
$app->get(
'/',
- array('Alltube\Controller\FrontController', 'index')
-);
+ array($controller, 'index')
+)->setName('index');
$app->get(
'/extractors',
- array('Alltube\Controller\FrontController', 'extractors')
-)->name('extractors');
+ array($controller, 'extractors')
+)->setName('extractors');
$app->get(
'/video',
- array('Alltube\Controller\FrontController', 'video')
-)->name('video');
+ array($controller, 'video')
+)->setName('video');
$app->get(
'/redirect',
- array('Alltube\Controller\FrontController', 'redirect')
-);
+ array($controller, 'redirect')
+)->setName('redirect');
$app->get(
'/json',
- array('Alltube\Controller\FrontController', 'json')
+ array($controller, 'json')
);
$app->run();
diff --git a/js/cast.js b/js/cast.js
index 57261fe..0cc0bd3 100644
--- a/js/cast.js
+++ b/js/cast.js
@@ -1,97 +1,106 @@
/*global chrome*/
-/*jslint devel: true, browser: true */
-var launchBtn, disabledBtn, stopBtn;
-var session, currentMedia;
-
-function receiverListener(e) {
+/*jslint browser: true, nomen: true */
+var castModule = (function () {
'use strict';
- console.log('receiverListener', e);
-}
+ var launchBtn, disabledBtn, stopBtn, session;
-function onMediaDiscovered(how, media) {
- 'use strict';
- console.log('onMediaDiscovered', how);
- currentMedia = media;
- if (launchBtn) {
- stopBtn.classList.remove('cast_hidden');
- launchBtn.classList.add('cast_hidden');
+ function receiverListener(e) {
+ return (e === chrome.cast.ReceiverAvailability.AVAILABLE);
}
-}
-function sessionListener(e) {
- 'use strict';
- session = e;
- session.addMediaListener(onMediaDiscovered.bind(this, 'addMediaListener'));
- if (session.media.length !== 0) {
- onMediaDiscovered('onRequestSessionSuccess', session.media[0]);
+ function onMediaDiscovered() {
+ if (launchBtn) {
+ stopBtn.classList.remove('cast_hidden');
+ launchBtn.classList.add('cast_hidden');
+ }
}
-}
-function onStopCast() {
- 'use strict';
- stopBtn.classList.add('cast_hidden');
- launchBtn.classList.remove('cast_hidden');
-}
-
-function stopCast() {
- 'use strict';
- session.stop(onStopCast);
-}
-
-function onMediaError() {
- 'use strict';
- console.log('onMediaError');
- stopCast();
-}
-
-function onRequestSessionSuccess(e) {
- 'use strict';
- session = e;
- var videoLink = document.getElementById('video_link'), videoURL = videoLink.dataset.video, mediaInfo = new chrome.cast.media.MediaInfo(videoURL, 'video/' + videoLink.dataset.ext), request = new chrome.cast.media.LoadRequest(mediaInfo);
- session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onMediaError);
-}
-
-function onLaunchError(e) {
- 'use strict';
- console.log('onLaunchError', e.description);
-}
-
-function launchCast() {
- 'use strict';
- chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
-}
-
-function onInitSuccess() {
- 'use strict';
- launchBtn = document.getElementById('cast_btn_launch');
- disabledBtn = document.getElementById('cast_disabled');
- stopBtn = document.getElementById('cast_btn_stop');
- if (launchBtn) {
- disabledBtn.classList.add('cast_hidden');
+ function onStopCast() {
+ stopBtn.classList.add('cast_hidden');
launchBtn.classList.remove('cast_hidden');
- launchBtn.addEventListener('click', launchCast, false);
- stopBtn.addEventListener('click', stopCast, false);
}
-}
-function onError() {
- 'use strict';
- console.log('onError');
-}
-
-function initializeCastApi() {
- 'use strict';
- var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID), apiConfig = new chrome.cast.ApiConfig(sessionRequest, sessionListener, receiverListener, chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED);
- chrome.cast.initialize(apiConfig, onInitSuccess, onError);
-}
-
-function loadCastApi(loaded, errorInfo) {
- 'use strict';
- if (loaded) {
- initializeCastApi();
- } else {
- console.log(errorInfo);
+ function onStopCastError(e) {
+ onStopCast();
+ throw e.description;
}
-}
-window['__onGCastApiAvailable'] = loadCastApi;
+ function updateListener() {
+ if (session.status !== chrome.cast.SessionStatus.CONNECTED) {
+ onStopCast();
+ }
+ }
+
+ function sessionListener(e) {
+ session = e;
+ session.addMediaListener(onMediaDiscovered.bind(this, 'addMediaListener'));
+ session.addUpdateListener(updateListener.bind(this));
+ if (session.media.length !== 0) {
+ onMediaDiscovered('onRequestSessionSuccess', session.media[0]);
+ }
+ }
+
+ function stopCast() {
+ session.stop(onStopCast, onStopCastError);
+ }
+
+ function onMediaError(e) {
+ stopCast();
+ throw e.description;
+ }
+
+ function onRequestSessionSuccess(e) {
+ session = e;
+ var videoLink = document.getElementById('video_link'), videoURL = videoLink.dataset.video, mediaInfo = new chrome.cast.media.MediaInfo(videoURL, 'video/' + videoLink.dataset.ext), request = new chrome.cast.media.LoadRequest(mediaInfo);
+ session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onMediaError);
+ }
+
+ function onLaunchError(e) {
+ throw e.description;
+ }
+
+ function launchCast() {
+ chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
+ }
+
+ function onInitSuccess() {
+ launchBtn = document.getElementById('cast_btn_launch');
+ disabledBtn = document.getElementById('cast_disabled');
+ stopBtn = document.getElementById('cast_btn_stop');
+ if (launchBtn) {
+ disabledBtn.classList.add('cast_hidden');
+ launchBtn.classList.remove('cast_hidden');
+ launchBtn.addEventListener('click', launchCast, false);
+ stopBtn.addEventListener('click', stopCast, false);
+ }
+ }
+
+ function onError(e) {
+ throw e.code;
+ }
+
+ function initializeCastApi() {
+ var sessionRequest = new chrome.cast.SessionRequest(chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID), apiConfig = new chrome.cast.ApiConfig(sessionRequest, sessionListener, receiverListener, chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED);
+ chrome.cast.initialize(apiConfig, onInitSuccess, onError);
+ }
+
+ function loadCastApi(loaded, errorInfo) {
+ if (loaded) {
+ initializeCastApi();
+ } else {
+ throw errorInfo;
+ }
+ }
+
+ return {
+ init: function () {
+ var intro = document.getElementById('download_intro');
+ if (intro) {
+ intro.insertAdjacentHTML('beforeend', '
');
+ window.__onGCastApiAvailable = loadCastApi;
+ }
+ }
+ };
+}());
+
+window.addEventListener('load', castModule.init, false);
diff --git a/maintenance.html b/maintenance.html
index f7ba7a5..cae4766 100644
--- a/maintenance.html
+++ b/maintenance.html
@@ -1,5 +1,5 @@
-
+
@@ -9,7 +9,7 @@
-
This application is undergoing maintenance right now. Please check back later.
diff --git a/manifest.json b/manifest.json
index 57256cf..9f08114 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,7 +1,8 @@
{
"short_name": "AllTube",
"name": "AllTube Download",
- "display": "minimal-ui",
+ "description": "Easily download videos from Youtube, Dailymotion, Vimeo and other websites",
+ "display": "standalone",
"icons": [{
"src": "img/favicon.png",
"sizes": "32x32",
@@ -24,6 +25,7 @@
"type": "image/png"
}],
"lang": "en",
- "start_url": "./index.php",
- "theme_color": "#4F4F4F"
+ "start_url": "./",
+ "theme_color": "#4F4F4F",
+ "orientation": "portrait"
}
diff --git a/package.json b/package.json
index 5aafc35..2620eab 100644
--- a/package.json
+++ b/package.json
@@ -1,23 +1,25 @@
{
"name": "alltube",
- "version": "0.4.5",
+ "version": "0.5.0",
"license": "GPL-3.0",
"dependencies": {
- "grunt": "~0.4.5",
- "grunt-cli": "~0.1.13",
+ "grunt": "~1.0.1",
+ "grunt-cli": "~1.2.0",
"grunt-contrib-cssmin": "~1.0.0",
"grunt-contrib-uglify": "~1.0.0",
- "grunt-contrib-watch": "~0.6.1",
+ "grunt-contrib-watch": "~1.0.0",
"grunt-phpcs": "~0.4.0",
"grunt-phpunit": "~0.3.6",
- "grunt-contrib-compress": "~1.1.1",
- "bower": "~1.7.1"
+ "grunt-contrib-compress": "~1.3.0",
+ "bower": "~1.7.1",
+ "grunt-githash": "~0.1.3",
+ "grunt-jslint": "~1.1.14"
},
"repository": {
"type": "git",
"url": "https://github.com/Rudloff/alltube.git"
},
"scripts": {
- "postinstall": "./node_modules/bower/bin/bower install; ./node_modules/grunt-cli/bin/grunt"
+ "postinstall": "node node_modules/bower/bin/bower install && node node_modules/grunt-cli/bin/grunt"
}
}
diff --git a/templates/error.tpl b/templates/error.tpl
index 6756cf2..d000ab3 100644
--- a/templates/error.tpl
+++ b/templates/error.tpl
@@ -10,4 +10,3 @@
{/foreach}
-
diff --git a/templates/footer.tpl b/templates/footer.tpl
index ae9c9be..cdbb327 100644
--- a/templates/footer.tpl
+++ b/templates/footer.tpl
@@ -1,10 +1,10 @@