Merge branch 'release/0.10.0'
This commit is contained in:
commit
169a33dd50
53 changed files with 3905 additions and 595 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -9,6 +9,7 @@ ffmpeg-*/
|
|||
alltube-*.zip
|
||||
coverage/
|
||||
bower_components/
|
||||
config.yml
|
||||
config/config.yml
|
||||
docs/
|
||||
clover.xml
|
||||
i18n/*/LC_MESSAGES/*.mo
|
||||
|
|
14
.htaccess
14
.htaccess
|
@ -1,4 +1,4 @@
|
|||
<ifmodule mod_expires.c>
|
||||
<ifmodule mod_mime.c>
|
||||
AddType application/x-web-app-manifest+json .webapp
|
||||
Addtype font/truetype .ttf
|
||||
</ifmodule>
|
||||
|
@ -15,13 +15,15 @@
|
|||
|
||||
FileETag None
|
||||
|
||||
RewriteEngine On
|
||||
<ifmodule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
|
||||
RewriteCond %{HTTP_HOST} ^alltube\.herokuapp\.com$ [NC]
|
||||
RewriteRule ^(.*)$ https://www.alltubedownload.net/$1 [R=301,L]
|
||||
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]
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^ index.php [QSA,L]
|
||||
</ifmodule>
|
||||
|
||||
<ifmodule mod_filter.c>
|
||||
AddOutputFilterByType DEFLATE text/css text/html application/javascript font/truetype
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
# Contributing
|
||||
|
||||
## Report a bug
|
||||
|
||||
Before opening a new issue, make sure that:
|
||||
|
||||
* It has not already been [reported](https://github.com/Rudloff/alltube/issues).
|
||||
* You read the [README](README.md) and the [FAQ](FAQ.md).
|
||||
* You read the [README](README.md) and the [FAQ](resources/FAQ.md).
|
||||
* You can provide **logs**.
|
||||
|
|
|
@ -7,7 +7,7 @@ RUN docker-php-ext-install intl
|
|||
RUN docker-php-ext-install zip
|
||||
RUN a2enmod rewrite
|
||||
RUN curl -sS https://getcomposer.org/installer | php
|
||||
COPY php.ini /usr/local/etc/php/
|
||||
COPY resources/php.ini /usr/local/etc/php/
|
||||
COPY . /var/www/html/
|
||||
RUN php composer.phar install --prefer-dist
|
||||
RUN npm install
|
||||
|
|
30
Gruntfile.js
30
Gruntfile.js
|
@ -68,7 +68,7 @@ module.exports = function (grunt) {
|
|||
options: {
|
||||
archive: 'alltube-<%= githash.main.tag %>.zip'
|
||||
},
|
||||
src: ['*.php', '!config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg', '!vendor/phpunit/**', '!vendor/squizlabs/**']
|
||||
src: ['*.php', '!config/config.yml', 'dist/**', '.htaccess', 'img/**', 'LICENSE', 'README.md', 'robots.txt', 'resources/sitemap.xml', 'templates/**', 'templates_c/', 'vendor/**', 'classes/**', 'controllers/**', 'bower_components/**', '!vendor/ffmpeg/**', '!vendor/bin/ffmpeg', '!vendor/phpunit/**', '!vendor/squizlabs/**']
|
||||
}
|
||||
},
|
||||
phpdocumentor: {
|
||||
|
@ -80,7 +80,7 @@ module.exports = function (grunt) {
|
|||
},
|
||||
jsonlint: {
|
||||
manifests: {
|
||||
src: ['*.json', '*.webapp'],
|
||||
src: ['*.json', 'resources/*.json'],
|
||||
options: {
|
||||
format: true
|
||||
}
|
||||
|
@ -90,6 +90,26 @@ module.exports = function (grunt) {
|
|||
package: {
|
||||
src: 'package.json'
|
||||
}
|
||||
},
|
||||
potomo: {
|
||||
dist: {
|
||||
options: {
|
||||
poDel: false
|
||||
},
|
||||
files: {
|
||||
'i18n/fr_FR/LC_MESSAGES/Alltube.mo': 'i18n/fr_FR/LC_MESSAGES/Alltube.po',
|
||||
'i18n/zh_CN/LC_MESSAGES/Alltube.mo': 'i18n/zh_CN/LC_MESSAGES/Alltube.po'
|
||||
}
|
||||
}
|
||||
},
|
||||
csslint: {
|
||||
options: {
|
||||
'box-sizing': false,
|
||||
'bulletproof-font-face': false
|
||||
},
|
||||
css: {
|
||||
src: 'css/*'
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -105,9 +125,11 @@ module.exports = function (grunt) {
|
|||
grunt.loadNpmTasks('grunt-phpdocumentor');
|
||||
grunt.loadNpmTasks('grunt-jsonlint');
|
||||
grunt.loadNpmTasks('grunt-fixpack');
|
||||
grunt.loadNpmTasks('grunt-potomo');
|
||||
grunt.loadNpmTasks('grunt-contrib-csslint');
|
||||
|
||||
grunt.registerTask('default', ['uglify', 'cssmin']);
|
||||
grunt.registerTask('lint', ['jslint', 'fixpack', 'jsonlint', 'phpcs']);
|
||||
grunt.registerTask('default', ['uglify', 'cssmin', 'potomo']);
|
||||
grunt.registerTask('lint', ['jslint', 'csslint', 'fixpack', 'jsonlint', 'phpcs']);
|
||||
grunt.registerTask('test', ['phpunit']);
|
||||
grunt.registerTask('doc', ['phpdocumentor']);
|
||||
grunt.registerTask('release', ['default', 'githash', 'compress']);
|
||||
|
|
|
@ -43,12 +43,16 @@ npm install
|
|||
composer install
|
||||
```
|
||||
|
||||
### On Heroku
|
||||
|
||||
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
|
||||
|
||||
## Config
|
||||
|
||||
If you want to use a custom config, you need to create a config file:
|
||||
|
||||
```bash
|
||||
cp config.example.yml config.yml
|
||||
cp config/config.example.yml config/config.yml
|
||||
```
|
||||
|
||||
## PHP requirements
|
||||
|
@ -168,7 +172,7 @@ You can also have a look at this [example project](https://github.com/Rudloff/al
|
|||
|
||||
## FAQ
|
||||
|
||||
Please read the [FAQ](FAQ.md) before reporting any issue.
|
||||
Please read the [FAQ](resources/FAQ.md) before reporting any issue.
|
||||
|
||||
## License
|
||||
|
||||
|
|
38
app.json
Normal file
38
app.json
Normal file
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"name": "AllTube Download",
|
||||
"description": "HTML GUI for youtube-dl",
|
||||
"repository": "https://github.com/Rudloff/alltube.git",
|
||||
"logo": "https://alltubedownload.net/img/logo.png",
|
||||
"keywords": [
|
||||
"alltube",
|
||||
"download",
|
||||
"video",
|
||||
"youtube",
|
||||
"php"
|
||||
],
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "https://github.com/piotras/heroku-buildpack-gettext.git"
|
||||
},
|
||||
{
|
||||
"url": "heroku/nodejs"
|
||||
},
|
||||
{
|
||||
"url": "heroku/python"
|
||||
},
|
||||
{
|
||||
"url": "heroku/php"
|
||||
}
|
||||
],
|
||||
"env": {
|
||||
"CONVERT": {
|
||||
"description": "Enable audio conversion",
|
||||
"value": "true"
|
||||
},
|
||||
"PYTHON": {
|
||||
"description": "Path to python binary",
|
||||
"value": "/app/.heroku/python/bin/python"
|
||||
}
|
||||
},
|
||||
"website": "https://alltubedownload.net/"
|
||||
}
|
|
@ -38,7 +38,7 @@ class Config
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
public $params = ['--no-warnings', '--ignore-errors', '--flat-playlist'];
|
||||
public $params = ['--no-warnings', '--ignore-errors', '--flat-playlist', '--restrict-filenames'];
|
||||
|
||||
/**
|
||||
* Enable audio conversion.
|
||||
|
@ -126,13 +126,13 @@ class Config
|
|||
*
|
||||
* @return Config
|
||||
*/
|
||||
public static function getInstance($yamlfile = 'config.yml')
|
||||
public static function getInstance($yamlfile = 'config/config.yml')
|
||||
{
|
||||
$yamlPath = __DIR__.'/../'.$yamlfile;
|
||||
if (is_null(self::$instance) || self::$instance->file != $yamlfile) {
|
||||
if (is_file($yamlfile)) {
|
||||
$options = Yaml::parse(file_get_contents($yamlPath));
|
||||
} elseif ($yamlfile == 'config.yml' || empty($yamlfile)) {
|
||||
} elseif ($yamlfile == 'config/config.yml' || empty($yamlfile)) {
|
||||
/*
|
||||
Allow for the default file to be missing in order to
|
||||
not surprise users that did not create a config file
|
||||
|
|
95
classes/Locale.php
Normal file
95
classes/Locale.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
/**
|
||||
* Locale class.
|
||||
*/
|
||||
|
||||
namespace Alltube;
|
||||
|
||||
use Teto\HTTP\AcceptLanguage;
|
||||
|
||||
/**
|
||||
* Class used to represent locales.
|
||||
*/
|
||||
class Locale
|
||||
{
|
||||
/**
|
||||
* Locale language.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $language;
|
||||
|
||||
/**
|
||||
* Locale region.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $region;
|
||||
|
||||
/**
|
||||
* Locale constructor.
|
||||
*
|
||||
* @param string $locale ISO 15897 code
|
||||
*/
|
||||
public function __construct($locale)
|
||||
{
|
||||
$parse = AcceptLanguage::parse($locale);
|
||||
$this->language = $parse[1]['language'];
|
||||
$this->region = $parse[1]['region'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the locale to a string.
|
||||
*
|
||||
* @return string ISO 15897 code
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getIso15897();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full name of the locale.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getFullName()
|
||||
{
|
||||
return \Locale::getDisplayName($this->getIso15897(), $this->getIso15897());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ISO 15897 code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIso15897()
|
||||
{
|
||||
return $this->language.'_'.$this->region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BCP 47 code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBcp47()
|
||||
{
|
||||
return $this->language.'-'.$this->region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ISO 3166 code.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIso3166()
|
||||
{
|
||||
return strtolower($this->region);
|
||||
}
|
||||
|
||||
public function getCountry()
|
||||
{
|
||||
return country($this->getIso3166());
|
||||
}
|
||||
}
|
87
classes/LocaleManager.php
Normal file
87
classes/LocaleManager.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
/**
|
||||
* LocaleManager class.
|
||||
*/
|
||||
|
||||
namespace Alltube;
|
||||
|
||||
/**
|
||||
* Class used to manage locales.
|
||||
*/
|
||||
class LocaleManager
|
||||
{
|
||||
/**
|
||||
* Supported locales.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $supportedLocales = ['en_US', 'fr_FR', 'zh_CN'];
|
||||
|
||||
/**
|
||||
* Current locale.
|
||||
*
|
||||
* @var Locale
|
||||
*/
|
||||
private $curLocale;
|
||||
|
||||
/**
|
||||
* Session segment used to store session variables.
|
||||
*
|
||||
* @var \Aura\Session\Segment
|
||||
*/
|
||||
private $sessionSegment;
|
||||
|
||||
/**
|
||||
* LocaleManager constructor.
|
||||
*
|
||||
* @param array $cookies Cookie array
|
||||
*/
|
||||
public function __construct(array $cookies = [])
|
||||
{
|
||||
$session_factory = new \Aura\Session\SessionFactory();
|
||||
$session = $session_factory->newInstance($cookies);
|
||||
$this->sessionSegment = $session->getSegment('Alltube\LocaleManager');
|
||||
$cookieLocale = $this->sessionSegment->get('locale');
|
||||
if (isset($cookieLocale)) {
|
||||
$this->setLocale(new Locale($cookieLocale));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of supported locales.
|
||||
*
|
||||
* @return Locale[]
|
||||
*/
|
||||
public function getSupportedLocales()
|
||||
{
|
||||
$return = [];
|
||||
foreach ($this->supportedLocales as $supportedLocale) {
|
||||
$return[] = new Locale($supportedLocale);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current locale.
|
||||
*
|
||||
* @return Locale
|
||||
*/
|
||||
public function getLocale()
|
||||
{
|
||||
return $this->curLocale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current locale.
|
||||
*
|
||||
* @param Locale $locale Locale
|
||||
*/
|
||||
public function setLocale(Locale $locale)
|
||||
{
|
||||
putenv('LANG='.$locale);
|
||||
setlocale(LC_ALL, [$locale, $locale.'.utf8']);
|
||||
$this->curLocale = $locale;
|
||||
$this->sessionSegment->set('locale', $locale);
|
||||
}
|
||||
}
|
80
classes/LocaleMiddleware.php
Normal file
80
classes/LocaleMiddleware.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
/**
|
||||
* LocaleMiddleware class.
|
||||
*/
|
||||
|
||||
namespace Alltube;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
use Teto\HTTP\AcceptLanguage;
|
||||
|
||||
/**
|
||||
* Detect user locale.
|
||||
*/
|
||||
class LocaleMiddleware
|
||||
{
|
||||
/**
|
||||
* LocaleManager instance.
|
||||
*
|
||||
* @var LocaleManager
|
||||
*/
|
||||
private $localeManager;
|
||||
|
||||
/**
|
||||
* LocaleMiddleware constructor.
|
||||
*
|
||||
* @param ContainerInterface $container Slim dependency container
|
||||
*/
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->localeManager = $container->get('locale');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a locale can be used for the current user.
|
||||
*
|
||||
* @param array $proposedLocale Locale array created by AcceptLanguage::parse()
|
||||
*
|
||||
* @return string Locale name if chosen, nothing otherwise
|
||||
*/
|
||||
public function testLocale(array $proposedLocale)
|
||||
{
|
||||
foreach ($this->localeManager->getSupportedLocales() as $locale) {
|
||||
$parsedLocale = AcceptLanguage::parse($locale);
|
||||
if (isset($proposedLocale['language'])
|
||||
&& $parsedLocale[1]['language'] == $proposedLocale['language']
|
||||
&& $parsedLocale[1]['region'] == $proposedLocale['region']
|
||||
) {
|
||||
return new Locale($proposedLocale['language'].'_'.$proposedLocale['region']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main middleware function.
|
||||
*
|
||||
* @param Request $request PSR request
|
||||
* @param Response $response PSR response
|
||||
* @param callable $next Next middleware
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function __invoke(Request $request, Response $response, callable $next)
|
||||
{
|
||||
$headers = $request->getHeader('Accept-Language');
|
||||
$curLocale = $this->localeManager->getLocale();
|
||||
if (!isset($curLocale)) {
|
||||
if (isset($headers[0])) {
|
||||
$this->localeManager->setLocale(
|
||||
AcceptLanguage::detect([$this, 'testLocale'], new Locale('en_US'), $headers[0])
|
||||
);
|
||||
} else {
|
||||
$this->localeManager->setLocale(new Locale('en_US'));
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request, $response);
|
||||
}
|
||||
}
|
201
classes/PlaylistArchiveStream.php
Normal file
201
classes/PlaylistArchiveStream.php
Normal file
|
@ -0,0 +1,201 @@
|
|||
<?php
|
||||
/**
|
||||
* PlaylistArchiveStream class.
|
||||
*
|
||||
* @codingStandardsIgnoreFile
|
||||
*/
|
||||
|
||||
namespace Alltube;
|
||||
|
||||
use Barracuda\ArchiveStream\TarArchive;
|
||||
|
||||
/**
|
||||
* Class used to create a Tar archive from playlists and stream it to the browser.
|
||||
*
|
||||
* @link http://php.net/manual/en/class.streamwrapper.php
|
||||
*/
|
||||
class PlaylistArchiveStream extends TarArchive
|
||||
{
|
||||
/**
|
||||
* Files to add in the archive.
|
||||
*
|
||||
* @var array[]
|
||||
*/
|
||||
private $files;
|
||||
|
||||
/**
|
||||
* Stream used to store data before it is sent to the browser.
|
||||
*
|
||||
* @var resource
|
||||
*/
|
||||
private $buffer;
|
||||
|
||||
/**
|
||||
* Guzzle client.
|
||||
*
|
||||
* @var \GuzzleHttp\Client
|
||||
*/
|
||||
private $client;
|
||||
|
||||
/**
|
||||
* VideoDownload instance.
|
||||
*
|
||||
* @var VideoDownload
|
||||
*/
|
||||
private $download;
|
||||
|
||||
/**
|
||||
* Current file position in $files array.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $curFile = 0;
|
||||
|
||||
/**
|
||||
* Video format to download.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $format;
|
||||
|
||||
/**
|
||||
* PlaylistArchiveStream constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new \GuzzleHttp\Client();
|
||||
$this->download = new VideoDownload();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add data to the archive.
|
||||
*
|
||||
* @param string $data Data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function send($data)
|
||||
{
|
||||
$pos = ftell($this->buffer);
|
||||
fwrite($this->buffer, $data);
|
||||
fseek($this->buffer, $pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fopen() is used on the stream.
|
||||
*
|
||||
* @param string $path Playlist path (should be playlist://url1;url2;.../format)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_open($path)
|
||||
{
|
||||
$this->format = ltrim(parse_url($path, PHP_URL_PATH), '/');
|
||||
$this->buffer = fopen('php://temp', 'r+');
|
||||
foreach (explode(';', parse_url($path, PHP_URL_HOST)) as $url) {
|
||||
$this->files[] = [
|
||||
'url' => urldecode($url),
|
||||
'headersSent'=> false,
|
||||
'complete' => false,
|
||||
'stream' => null,
|
||||
];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fwrite() is used on the stream.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function stream_write()
|
||||
{
|
||||
//We don't support writing to a stream
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fstat() is used on the stream.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function stream_stat()
|
||||
{
|
||||
//We need this so Slim won't try to get the size of the stream
|
||||
return [
|
||||
'mode'=> 0010000,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when ftell() is used on the stream.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function stream_tell()
|
||||
{
|
||||
return ftell($this->buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fseek() is used on the stream.
|
||||
*
|
||||
* @param int $offset Offset
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_seek($offset)
|
||||
{
|
||||
return fseek($this->buffer, $offset) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when feof() is used on the stream.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function stream_eof()
|
||||
{
|
||||
foreach ($this->files as $file) {
|
||||
if (!$file['complete']) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when fread() is used on the stream.
|
||||
*
|
||||
* @param int $count Number of bytes to read
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function stream_read($count)
|
||||
{
|
||||
if (!$this->files[$this->curFile]['headersSent']) {
|
||||
$urls = $this->download->getUrl($this->files[$this->curFile]['url'], $this->format);
|
||||
$response = $this->client->request('GET', $urls[0], ['stream' => true]);
|
||||
|
||||
$contentLengthHeaders = $response->getHeader('Content-Length');
|
||||
$this->init_file_stream_transfer(
|
||||
$this->download->getFilename($this->files[$this->curFile]['url'], $this->format),
|
||||
$contentLengthHeaders[0]
|
||||
);
|
||||
|
||||
$this->files[$this->curFile]['headersSent'] = true;
|
||||
$this->files[$this->curFile]['stream'] = $response->getBody();
|
||||
} elseif (!$this->files[$this->curFile]['stream']->eof()) {
|
||||
$this->stream_file_part($this->files[$this->curFile]['stream']->read($count));
|
||||
} elseif (!$this->files[$this->curFile]['complete']) {
|
||||
$this->complete_file_stream();
|
||||
$this->files[$this->curFile]['complete'] = true;
|
||||
} elseif (isset($this->files[$this->curFile])) {
|
||||
$this->curFile += 1;
|
||||
}
|
||||
|
||||
return fread($this->buffer, $count);
|
||||
}
|
||||
}
|
|
@ -218,9 +218,9 @@ class VideoDownload
|
|||
*
|
||||
* @return \Symfony\Component\Process\Process Process
|
||||
*/
|
||||
private function getRtmpProcess($video)
|
||||
private function getRtmpProcess(\stdClass $video)
|
||||
{
|
||||
if (!shell_exec('which '.$this->config->rtmpdump)) {
|
||||
if (!$this->checkCommand([$this->config->rtmpdump, '--help'])) {
|
||||
throw(new \Exception('Can\'t find rtmpdump'));
|
||||
}
|
||||
$builder = new ProcessBuilder(
|
||||
|
@ -240,6 +240,22 @@ class VideoDownload
|
|||
return $builder->getProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a command runs successfully.
|
||||
*
|
||||
* @param array $command Command and arguments
|
||||
*
|
||||
* @return bool False if the command returns an error, true otherwise
|
||||
*/
|
||||
private function checkCommand(array $command)
|
||||
{
|
||||
$builder = ProcessBuilder::create($command);
|
||||
$process = $builder->getProcess();
|
||||
$process->run();
|
||||
|
||||
return $process->isSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a process that runs avconv in order to convert a video to MP3.
|
||||
*
|
||||
|
@ -249,11 +265,11 @@ class VideoDownload
|
|||
*/
|
||||
private function getAvconvMp3Process($url)
|
||||
{
|
||||
if (!shell_exec('which '.$this->config->avconv)) {
|
||||
if (!$this->checkCommand([$this->config->avconv, '-version'])) {
|
||||
throw(new \Exception('Can\'t find avconv or ffmpeg'));
|
||||
}
|
||||
|
||||
return ProcessBuilder::create(
|
||||
$builder = ProcessBuilder::create(
|
||||
[
|
||||
$this->config->avconv,
|
||||
'-v', 'quiet',
|
||||
|
@ -265,6 +281,8 @@ class VideoDownload
|
|||
'pipe:1',
|
||||
]
|
||||
);
|
||||
|
||||
return $builder->getProcess();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,7 +310,7 @@ class VideoDownload
|
|||
} else {
|
||||
$avconvProc = $this->getAvconvMp3Process($video->url);
|
||||
|
||||
return popen($avconvProc->getProcess()->getCommandLine(), 'r');
|
||||
return popen($avconvProc->getCommandLine(), 'r');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +323,7 @@ class VideoDownload
|
|||
*/
|
||||
public function getM3uStream(\stdClass $video)
|
||||
{
|
||||
if (!shell_exec('which '.$this->config->avconv)) {
|
||||
if (!$this->checkCommand([$this->config->avconv, '-version'])) {
|
||||
throw(new \Exception('Can\'t find avconv or ffmpeg'));
|
||||
}
|
||||
|
||||
|
@ -362,4 +380,23 @@ class VideoDownload
|
|||
{
|
||||
return popen($this->getRtmpProcess($video)->getCommandLine(), 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Tar stream containing every video in the playlist piped through the server.
|
||||
*
|
||||
* @param object $video Video object returned by youtube-dl
|
||||
* @param string $format Requested format
|
||||
*
|
||||
* @return Response HTTP response
|
||||
*/
|
||||
public function getPlaylistArchiveStream(\stdClass $video, $format)
|
||||
{
|
||||
$playlistItems = [];
|
||||
foreach ($video->entries as $entry) {
|
||||
$playlistItems[] = urlencode($entry->url);
|
||||
}
|
||||
$stream = fopen('playlist://'.implode(';', $playlistItems).'/'.$format, 'r');
|
||||
|
||||
return $stream;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,22 +12,25 @@
|
|||
"symfony/process": "~3.2.0",
|
||||
"ptachoire/process-builder-chain": "~1.2.0",
|
||||
"guzzlehttp/guzzle": "~6.2.0",
|
||||
"rudloff/rtmpdump-bin": "~2.3",
|
||||
"aura/session": "~2.1.0"
|
||||
"aura/session": "~2.1.0",
|
||||
"barracudanetworks/archivestream-php": "~1.0.5",
|
||||
"smarty-gettext/smarty-gettext": "~1.5.1",
|
||||
"zonuexe/http-accept-language": "~0.4.1",
|
||||
"rinvex/country": "~2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/var-dumper": "~3.2.0",
|
||||
"squizlabs/php_codesniffer": "~2.8.0",
|
||||
"squizlabs/php_codesniffer": "~3.0.0",
|
||||
"phpunit/phpunit": "~5.7.2",
|
||||
"ffmpeg/ffmpeg": "dev-release",
|
||||
"rg3/youtube-dl": "~2017.04.28",
|
||||
"rudloff/rtmpdump-bin": "~2.3",
|
||||
"rg3/youtube-dl": "~2017.05.09",
|
||||
"rudloff/rtmpdump-bin": "~2.3.0",
|
||||
"heroku/heroku-buildpack-php": "*"
|
||||
},
|
||||
"extra": {
|
||||
"paas": {
|
||||
"nginx-includes": [
|
||||
"nginx.conf"
|
||||
"resources/nginx.conf"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
@ -36,10 +39,10 @@
|
|||
"type": "package",
|
||||
"package": {
|
||||
"name": "rg3/youtube-dl",
|
||||
"version": "2017.04.28",
|
||||
"version": "2017.05.09",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/rg3/youtube-dl/archive/2017.04.28.zip"
|
||||
"url": "https://github.com/rg3/youtube-dl/archive/2017.05.09.zip"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
419
composer.lock
generated
419
composer.lock
generated
|
@ -4,8 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "0a4bd158955df2e3f5ea89714ba9e740",
|
||||
"content-hash": "cb0e773496b6f26caf1c8591f23488f5",
|
||||
"content-hash": "22e16312bcf339c90850660d9e5923e7",
|
||||
"packages": [
|
||||
{
|
||||
"name": "aura/session",
|
||||
|
@ -67,7 +66,47 @@
|
|||
"session",
|
||||
"sessions"
|
||||
],
|
||||
"time": "2016-10-03 20:28:32"
|
||||
"time": "2016-10-03T20:28:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barracudanetworks/archivestream-php",
|
||||
"version": "1.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barracudanetworks/ArchiveStream-php.git",
|
||||
"reference": "1bf98097d1e9b137fd40081f26abb0a17b097ef7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barracudanetworks/ArchiveStream-php/zipball/1bf98097d1e9b137fd40081f26abb0a17b097ef7",
|
||||
"reference": "1bf98097d1e9b137fd40081f26abb0a17b097ef7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gmp": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.1.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barracuda\\ArchiveStream\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A library for dynamically streaming dynamic tar or zip files without the need to have the complete file stored on the server.",
|
||||
"homepage": "https://github.com/barracudanetworks/ArchiveStream-php",
|
||||
"keywords": [
|
||||
"archive",
|
||||
"php",
|
||||
"stream",
|
||||
"tar",
|
||||
"zip"
|
||||
],
|
||||
"time": "2017-01-13T14:52:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "container-interop/container-interop",
|
||||
|
@ -98,7 +137,7 @@
|
|||
],
|
||||
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
|
||||
"homepage": "https://github.com/container-interop/container-interop",
|
||||
"time": "2017-02-14 19:40:03"
|
||||
"time": "2017-02-14T19:40:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
|
@ -160,7 +199,7 @@
|
|||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"time": "2017-02-28 22:50:30"
|
||||
"time": "2017-02-28T22:50:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
|
@ -211,7 +250,7 @@
|
|||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"time": "2016-12-20 10:07:11"
|
||||
"time": "2016-12-20T10:07:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
|
@ -276,7 +315,7 @@
|
|||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-03-20 17:10:46"
|
||||
"time": "2017-03-20T17:10:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mathmarques/smarty-view",
|
||||
|
@ -326,7 +365,7 @@
|
|||
"template",
|
||||
"view"
|
||||
],
|
||||
"time": "2016-08-25 19:04:49"
|
||||
"time": "2016-08-25T19:04:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nikic/fast-route",
|
||||
|
@ -369,7 +408,7 @@
|
|||
"router",
|
||||
"routing"
|
||||
],
|
||||
"time": "2017-01-19 11:35:12"
|
||||
"time": "2017-01-19T11:35:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "pimple/pimple",
|
||||
|
@ -415,7 +454,7 @@
|
|||
"container",
|
||||
"dependency injection"
|
||||
],
|
||||
"time": "2015-09-11 15:10:35"
|
||||
"time": "2015-09-11T15:10:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
|
@ -464,7 +503,7 @@
|
|||
"container-interop",
|
||||
"psr"
|
||||
],
|
||||
"time": "2017-02-14 16:28:37"
|
||||
"time": "2017-02-14T16:28:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
|
@ -514,7 +553,7 @@
|
|||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2016-08-06 14:39:51"
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ptachoire/process-builder-chain",
|
||||
|
@ -550,35 +589,81 @@
|
|||
}
|
||||
],
|
||||
"description": "Add ability to chain symfony processes",
|
||||
"time": "2016-04-10 08:33:20"
|
||||
"time": "2016-04-10T08:33:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rudloff/rtmpdump-bin",
|
||||
"version": "2.3",
|
||||
"name": "rinvex/country",
|
||||
"version": "v2.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Rudloff/rtmpdump-bin.git",
|
||||
"reference": "133cdd80e3bab66593e88a5276158596383afd97"
|
||||
"url": "https://github.com/rinvex/country.git",
|
||||
"reference": "9405da035644bc76671bfba0c282fef8fd3408e1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97",
|
||||
"reference": "133cdd80e3bab66593e88a5276158596383afd97",
|
||||
"url": "https://api.github.com/repos/rinvex/country/zipball/9405da035644bc76671bfba0c282fef8fd3408e1",
|
||||
"reference": "9405da035644bc76671bfba0c282fef8fd3408e1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"rtmpdump/rtmpdump": "2.3"
|
||||
"require": {
|
||||
"php": ">=5.5.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.2.0"
|
||||
},
|
||||
"bin": [
|
||||
"rtmpdump"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/helpers.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Rinvex\\Country\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
"MIT"
|
||||
],
|
||||
"description": "rtmpdump binary for Linux 64 bit",
|
||||
"time": "2016-04-12 19:17:32"
|
||||
"authors": [
|
||||
{
|
||||
"name": "Rinvex LLC",
|
||||
"email": "help@rinvex.com",
|
||||
"homepage": "https://rinvex.com"
|
||||
},
|
||||
{
|
||||
"name": "Abdelrahman Omran",
|
||||
"email": "me@omranic.com",
|
||||
"homepage": "https://omranic.com",
|
||||
"role": "Project Lead"
|
||||
},
|
||||
{
|
||||
"name": "The Generous Laravel Community",
|
||||
"homepage": "https://github.com/rinvex/country/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Rinvex Country is a simple and lightweight package for retrieving country details with flexibility. A whole bunch of data including name, demonym, capital, iso codes, dialling codes, geo data, currencies, flags, emoji, and other attributes for all 250 countries worldwide at your fingertips.",
|
||||
"homepage": "https://rinvex.com",
|
||||
"keywords": [
|
||||
"Flexible",
|
||||
"Simple",
|
||||
"countries",
|
||||
"country",
|
||||
"currencies",
|
||||
"demonym",
|
||||
"dialling",
|
||||
"emoji",
|
||||
"flags",
|
||||
"geographic",
|
||||
"languages",
|
||||
"rinvex",
|
||||
"svg"
|
||||
],
|
||||
"time": "2016-11-27T05:53:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "slim/slim",
|
||||
|
@ -649,7 +734,61 @@
|
|||
"micro",
|
||||
"router"
|
||||
],
|
||||
"time": "2017-03-19 17:55:20"
|
||||
"time": "2017-03-19T17:55:20+00:00"
|
||||
},
|
||||
{
|
||||
"name": "smarty-gettext/smarty-gettext",
|
||||
"version": "1.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/smarty-gettext/smarty-gettext.git",
|
||||
"reference": "00fe2fcbc41e24e0245cd9d73f96bc7b0337972d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/smarty-gettext/smarty-gettext/zipball/00fe2fcbc41e24e0245cd9d73f96bc7b0337972d",
|
||||
"reference": "00fe2fcbc41e24e0245cd9d73f96bc7b0337972d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-gettext": "*",
|
||||
"ext-pcre": "*",
|
||||
"php": "~5.3|~7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"azatoth/php-pgettext": "~1.0",
|
||||
"smarty/smarty": "3.1.*"
|
||||
},
|
||||
"suggest": {
|
||||
"azatoth/php-pgettext": "Support msgctxt for {t} via context parameter"
|
||||
},
|
||||
"bin": [
|
||||
"tsmarty2c.php"
|
||||
],
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"block.t.php",
|
||||
"function.locale.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1+"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Sagi Bashari",
|
||||
"email": "sagi@boom.org.il"
|
||||
},
|
||||
{
|
||||
"name": "Elan Ruusamäe",
|
||||
"email": "glen@delfi.ee"
|
||||
}
|
||||
],
|
||||
"description": "Gettext plugin enabling internationalization in Smarty Package files",
|
||||
"homepage": "https://github.com/smarty-gettext/smarty-gettext",
|
||||
"time": "2017-05-12T12:14:46+00:00"
|
||||
},
|
||||
{
|
||||
"name": "smarty/smarty",
|
||||
|
@ -702,20 +841,20 @@
|
|||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2016-12-14 21:57:25"
|
||||
"time": "2016-12-14T21:57:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v3.2.8",
|
||||
"version": "v3.2.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0"
|
||||
"reference": "36774717bbd1631be2d0a45acf48aecd5836c867"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
|
||||
"reference": "999c2cf5061e627e6cd551dc9ebf90dd1d11d9f0",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/36774717bbd1631be2d0a45acf48aecd5836c867",
|
||||
"reference": "36774717bbd1631be2d0a45acf48aecd5836c867",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -751,20 +890,20 @@
|
|||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-04-12 14:13:17"
|
||||
"time": "2017-05-08T01:51:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v3.2.8",
|
||||
"version": "v3.2.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/yaml.git",
|
||||
"reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6"
|
||||
"reference": "4cdb9fec28fba88203a71f6d095018867f7a2065"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/acec26fcf7f3031e094e910b94b002fa53d4e4d6",
|
||||
"reference": "acec26fcf7f3031e094e910b94b002fa53d4e4d6",
|
||||
"url": "https://api.github.com/repos/symfony/yaml/zipball/4cdb9fec28fba88203a71f6d095018867f7a2065",
|
||||
"reference": "4cdb9fec28fba88203a71f6d095018867f7a2065",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -806,7 +945,48 @@
|
|||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "https://symfony.com",
|
||||
"time": "2017-05-01 14:55:58"
|
||||
"time": "2017-05-25T23:42:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "zonuexe/http-accept-language",
|
||||
"version": "0.4.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/BaguettePHP/http-accept-language.git",
|
||||
"reference": "f71422b1200737aa9d7c7fa83f07cbe4616198d5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/BaguettePHP/http-accept-language/zipball/f71422b1200737aa9d7c7fa83f07cbe4616198d5",
|
||||
"reference": "f71422b1200737aa9d7c7fa83f07cbe4616198d5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-intl": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phploc/phploc": "*",
|
||||
"phpunit/phpunit": "4.1.*",
|
||||
"theseer/phpdox": "0.6.*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Teto\\HTTP\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "USAMI Kenta",
|
||||
"email": "tadsan@zonu.me"
|
||||
}
|
||||
],
|
||||
"description": "HTTP Accept-Language Header parser",
|
||||
"time": "2014-10-19T09:22:18+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
@ -862,7 +1042,7 @@
|
|||
"constructor",
|
||||
"instantiate"
|
||||
],
|
||||
"time": "2015-06-14 21:17:01"
|
||||
"time": "2015-06-14T21:17:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ffmpeg/ffmpeg",
|
||||
|
@ -920,7 +1100,7 @@
|
|||
"nginx",
|
||||
"php"
|
||||
],
|
||||
"time": "2017-03-27 23:33:27"
|
||||
"time": "2017-03-27T23:33:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
|
@ -962,7 +1142,7 @@
|
|||
"object",
|
||||
"object graph"
|
||||
],
|
||||
"time": "2017-04-12 18:52:22"
|
||||
"time": "2017-04-12T18:52:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-common",
|
||||
|
@ -1016,7 +1196,7 @@
|
|||
"reflection",
|
||||
"static analysis"
|
||||
],
|
||||
"time": "2015-12-27 11:43:31"
|
||||
"time": "2015-12-27T11:43:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/reflection-docblock",
|
||||
|
@ -1061,7 +1241,7 @@
|
|||
}
|
||||
],
|
||||
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
|
||||
"time": "2016-09-30 07:12:33"
|
||||
"time": "2016-09-30T07:12:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpdocumentor/type-resolver",
|
||||
|
@ -1108,7 +1288,7 @@
|
|||
"email": "me@mikevanriel.com"
|
||||
}
|
||||
],
|
||||
"time": "2016-11-25 06:54:22"
|
||||
"time": "2016-11-25T06:54:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
|
@ -1171,7 +1351,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2017-03-02 20:05:34"
|
||||
"time": "2017-03-02T20:05:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -1234,7 +1414,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-04-02 07:44:40"
|
||||
"time": "2017-04-02T07:44:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -1281,7 +1461,7 @@
|
|||
"filesystem",
|
||||
"iterator"
|
||||
],
|
||||
"time": "2016-10-03 07:40:28"
|
||||
"time": "2016-10-03T07:40:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-text-template",
|
||||
|
@ -1322,7 +1502,7 @@
|
|||
"keywords": [
|
||||
"template"
|
||||
],
|
||||
"time": "2015-06-21 13:50:34"
|
||||
"time": "2015-06-21T13:50:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-timer",
|
||||
|
@ -1371,7 +1551,7 @@
|
|||
"keywords": [
|
||||
"timer"
|
||||
],
|
||||
"time": "2017-02-26 11:10:40"
|
||||
"time": "2017-02-26T11:10:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-token-stream",
|
||||
|
@ -1420,20 +1600,20 @@
|
|||
"keywords": [
|
||||
"tokenizer"
|
||||
],
|
||||
"time": "2017-02-27 10:12:30"
|
||||
"time": "2017-02-27T10:12:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "5.7.19",
|
||||
"version": "5.7.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1"
|
||||
"reference": "3cb94a5f8c07a03c8b7527ed7468a2926203f58b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||
"reference": "69c4f49ff376af2692bad9cebd883d17ebaa98a1",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3cb94a5f8c07a03c8b7527ed7468a2926203f58b",
|
||||
"reference": "3cb94a5f8c07a03c8b7527ed7468a2926203f58b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1451,7 +1631,7 @@
|
|||
"phpunit/php-timer": "^1.0.6",
|
||||
"phpunit/phpunit-mock-objects": "^3.2",
|
||||
"sebastian/comparator": "^1.2.4",
|
||||
"sebastian/diff": "~1.2",
|
||||
"sebastian/diff": "^1.4.3",
|
||||
"sebastian/environment": "^1.3.4 || ^2.0",
|
||||
"sebastian/exporter": "~2.0",
|
||||
"sebastian/global-state": "^1.1",
|
||||
|
@ -1502,7 +1682,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2017-04-03 02:22:27"
|
||||
"time": "2017-05-22T07:42:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit-mock-objects",
|
||||
|
@ -1561,19 +1741,47 @@
|
|||
"mock",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2016-12-08 20:27:08"
|
||||
"time": "2016-12-08T20:27:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "rg3/youtube-dl",
|
||||
"version": "2017.04.28",
|
||||
"version": "2017.05.09",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://github.com/rg3/youtube-dl/archive/2017.04.28.zip",
|
||||
"url": "https://github.com/rg3/youtube-dl/archive/2017.05.09.zip",
|
||||
"reference": null,
|
||||
"shasum": null
|
||||
},
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "rudloff/rtmpdump-bin",
|
||||
"version": "2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Rudloff/rtmpdump-bin.git",
|
||||
"reference": "133cdd80e3bab66593e88a5276158596383afd97"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Rudloff/rtmpdump-bin/zipball/133cdd80e3bab66593e88a5276158596383afd97",
|
||||
"reference": "133cdd80e3bab66593e88a5276158596383afd97",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
"rtmpdump/rtmpdump": "2.3"
|
||||
},
|
||||
"bin": [
|
||||
"rtmpdump"
|
||||
],
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"GPL-2.0"
|
||||
],
|
||||
"description": "rtmpdump binary for Linux 64 bit",
|
||||
"time": "2016-04-12T19:17:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
"version": "1.0.1",
|
||||
|
@ -1617,7 +1825,7 @@
|
|||
],
|
||||
"description": "Looks up which function or method a line of code belongs to",
|
||||
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
|
||||
"time": "2017-03-04 06:30:41"
|
||||
"time": "2017-03-04T06:30:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/comparator",
|
||||
|
@ -1681,27 +1889,27 @@
|
|||
"compare",
|
||||
"equality"
|
||||
],
|
||||
"time": "2017-01-29 09:50:25"
|
||||
"time": "2017-01-29T09:50:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/diff.git",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e"
|
||||
"reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"reference": "13edfd8706462032c2f52b4b862974dd46b71c9e",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4",
|
||||
"reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
"php": "^5.3.3 || ^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.8"
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
|
@ -1733,7 +1941,7 @@
|
|||
"keywords": [
|
||||
"diff"
|
||||
],
|
||||
"time": "2015-12-08 07:14:41"
|
||||
"time": "2017-05-22T07:24:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/environment",
|
||||
|
@ -1783,7 +1991,7 @@
|
|||
"environment",
|
||||
"hhvm"
|
||||
],
|
||||
"time": "2016-11-26 07:53:53"
|
||||
"time": "2016-11-26T07:53:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/exporter",
|
||||
|
@ -1850,7 +2058,7 @@
|
|||
"export",
|
||||
"exporter"
|
||||
],
|
||||
"time": "2016-11-19 08:54:04"
|
||||
"time": "2016-11-19T08:54:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/global-state",
|
||||
|
@ -1901,7 +2109,7 @@
|
|||
"keywords": [
|
||||
"global state"
|
||||
],
|
||||
"time": "2015-10-12 03:26:01"
|
||||
"time": "2015-10-12T03:26:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
|
@ -1947,7 +2155,7 @@
|
|||
],
|
||||
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
|
||||
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
|
||||
"time": "2017-02-18 15:18:39"
|
||||
"time": "2017-02-18T15:18:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/recursion-context",
|
||||
|
@ -2000,7 +2208,7 @@
|
|||
],
|
||||
"description": "Provides functionality to recursively process PHP variables",
|
||||
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
|
||||
"time": "2016-11-19 07:33:16"
|
||||
"time": "2016-11-19T07:33:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/resource-operations",
|
||||
|
@ -2042,7 +2250,7 @@
|
|||
],
|
||||
"description": "Provides a list of PHP built-in functions that operate on resources",
|
||||
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
|
||||
"time": "2015-07-28 20:34:47"
|
||||
"time": "2015-07-28T20:34:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/version",
|
||||
|
@ -2085,68 +2293,41 @@
|
|||
],
|
||||
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
|
||||
"homepage": "https://github.com/sebastianbergmann/version",
|
||||
"time": "2016-10-03 07:35:21"
|
||||
"time": "2016-10-03T07:35:21+00:00"
|
||||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "2.8.1",
|
||||
"version": "3.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d"
|
||||
"reference": "b95ff2c3b122a3ee4b57d149a57d2afce65522c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d",
|
||||
"reference": "d7cf0d894e8aa4c73712ee4a331cc1eaa37cdc7d",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/b95ff2c3b122a3ee4b57d149a57d2afce65522c3",
|
||||
"reference": "b95ff2c3b122a3ee4b57d149a57d2afce65522c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-simplexml": "*",
|
||||
"ext-tokenizer": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"php": ">=5.1.2"
|
||||
"php": ">=5.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"bin": [
|
||||
"scripts/phpcs",
|
||||
"scripts/phpcbf"
|
||||
"bin/phpcs",
|
||||
"bin/phpcbf"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
"dev-master": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"CodeSniffer.php",
|
||||
"CodeSniffer/CLI.php",
|
||||
"CodeSniffer/Exception.php",
|
||||
"CodeSniffer/File.php",
|
||||
"CodeSniffer/Fixer.php",
|
||||
"CodeSniffer/Report.php",
|
||||
"CodeSniffer/Reporting.php",
|
||||
"CodeSniffer/Sniff.php",
|
||||
"CodeSniffer/Tokens.php",
|
||||
"CodeSniffer/Reports/",
|
||||
"CodeSniffer/Tokenizers/",
|
||||
"CodeSniffer/DocGenerators/",
|
||||
"CodeSniffer/Standards/AbstractPatternSniff.php",
|
||||
"CodeSniffer/Standards/AbstractScopeSniff.php",
|
||||
"CodeSniffer/Standards/AbstractVariableSniff.php",
|
||||
"CodeSniffer/Standards/IncorrectPatternException.php",
|
||||
"CodeSniffer/Standards/Generic/Sniffs/",
|
||||
"CodeSniffer/Standards/MySource/Sniffs/",
|
||||
"CodeSniffer/Standards/PEAR/Sniffs/",
|
||||
"CodeSniffer/Standards/PSR1/Sniffs/",
|
||||
"CodeSniffer/Standards/PSR2/Sniffs/",
|
||||
"CodeSniffer/Standards/Squiz/Sniffs/",
|
||||
"CodeSniffer/Standards/Zend/Sniffs/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
|
@ -2163,7 +2344,7 @@
|
|||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2017-03-01 22:17:45"
|
||||
"time": "2017-05-04T00:33:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
|
@ -2222,20 +2403,20 @@
|
|||
"portable",
|
||||
"shim"
|
||||
],
|
||||
"time": "2016-11-14 01:06:16"
|
||||
"time": "2016-11-14T01:06:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/var-dumper",
|
||||
"version": "v3.2.8",
|
||||
"version": "v3.2.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/var-dumper.git",
|
||||
"reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8"
|
||||
"reference": "eda0d0891a0b60a25015f7b85ea8040b51d72e1e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/fa47963ac7979ddbd42b2d646d1b056bddbf7bb8",
|
||||
"reference": "fa47963ac7979ddbd42b2d646d1b056bddbf7bb8",
|
||||
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/eda0d0891a0b60a25015f7b85ea8040b51d72e1e",
|
||||
"reference": "eda0d0891a0b60a25015f7b85ea8040b51d72e1e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2290,7 +2471,7 @@
|
|||
"debug",
|
||||
"dump"
|
||||
],
|
||||
"time": "2017-05-01 14:55:58"
|
||||
"time": "2017-05-15T12:02:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
|
@ -2340,7 +2521,7 @@
|
|||
"check",
|
||||
"validate"
|
||||
],
|
||||
"time": "2016-11-23 20:04:58"
|
||||
"time": "2016-11-23T20:04:58+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
namespace Alltube\Controller;
|
||||
|
||||
use Alltube\Config;
|
||||
use Alltube\Locale;
|
||||
use Alltube\PasswordException;
|
||||
use Alltube\VideoDownload;
|
||||
use Psr\Container\ContainerInterface;
|
||||
|
@ -61,6 +62,13 @@ class FrontController
|
|||
*/
|
||||
private $defaultFormat = 'best[protocol^=http]';
|
||||
|
||||
/**
|
||||
* LocaleManager instance.
|
||||
*
|
||||
* @var LocaleManager
|
||||
*/
|
||||
private $localeManager;
|
||||
|
||||
/**
|
||||
* FrontController constructor.
|
||||
*
|
||||
|
@ -78,6 +86,7 @@ class FrontController
|
|||
$this->download = new VideoDownload();
|
||||
$this->container = $container;
|
||||
$this->view = $this->container->get('view');
|
||||
$this->localeManager = $this->container->get('locale');
|
||||
$session_factory = new \Aura\Session\SessionFactory();
|
||||
$session = $session_factory->newInstance($cookies);
|
||||
$this->sessionSegment = $session->getSegment('Alltube\Controller\FrontController');
|
||||
|
@ -101,18 +110,35 @@ class FrontController
|
|||
$response,
|
||||
'index.tpl',
|
||||
[
|
||||
'convert' => $this->config->convert,
|
||||
'uglyUrls' => $this->config->uglyUrls,
|
||||
'class' => 'index',
|
||||
'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.',
|
||||
'domain' => $uri->getScheme().'://'.$uri->getAuthority(),
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'config' => $this->config,
|
||||
'class' => 'index',
|
||||
'description' => 'Easily download videos from Youtube, Dailymotion, Vimeo and other websites.',
|
||||
'domain' => $uri->getScheme().'://'.$uri->getAuthority(),
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'supportedLocales' => $this->localeManager->getSupportedLocales(),
|
||||
'locale' => $this->localeManager->getLocale(),
|
||||
]
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch locale.
|
||||
*
|
||||
* @param Request $request PSR-7 request
|
||||
* @param Response $response PSR-7 response
|
||||
* @param array $data Query parameters
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function locale(Request $request, Response $response, array $data)
|
||||
{
|
||||
$this->localeManager->setLocale(new Locale($data['locale']));
|
||||
|
||||
return $response->withRedirect($this->container->get('router')->pathFor('index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a list of extractors.
|
||||
*
|
||||
|
@ -133,6 +159,7 @@ class FrontController
|
|||
'description' => 'List of all supported websites from which Alltube Download '.
|
||||
'can extract video or audio files',
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'locale' => $this->localeManager->getLocale(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -157,6 +184,7 @@ class FrontController
|
|||
'title' => 'Password prompt',
|
||||
'description' => 'You need a password in order to download this video with Alltube Download',
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'locale' => $this->localeManager->getLocale(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -247,8 +275,7 @@ class FrontController
|
|||
'protocol' => $protocol,
|
||||
'config' => $this->config,
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'uglyUrls' => $this->config->uglyUrls,
|
||||
'remux' => $this->config->remux,
|
||||
'locale' => $this->localeManager->getLocale(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -300,6 +327,7 @@ class FrontController
|
|||
'class' => 'video',
|
||||
'title' => 'Error',
|
||||
'canonical' => $this->getCanonicalUrl($request),
|
||||
'locale' => $this->localeManager->getLocale(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -320,26 +348,32 @@ class FrontController
|
|||
private function getStream($url, $format, Response $response, Request $request, $password = null)
|
||||
{
|
||||
$video = $this->download->getJSON($url, $format, $password);
|
||||
if ($video->protocol == 'rtmp') {
|
||||
if (isset($video->entries)) {
|
||||
$stream = $this->download->getPlaylistArchiveStream($video, $format);
|
||||
$response = $response->withHeader('Content-Type', 'application/x-tar');
|
||||
$response = $response->withHeader(
|
||||
'Content-Disposition',
|
||||
'attachment; filename="'.$video->title.'.tar"'
|
||||
);
|
||||
|
||||
return $response->withBody(new Stream($stream));
|
||||
} elseif ($video->protocol == 'rtmp') {
|
||||
$stream = $this->download->getRtmpStream($video);
|
||||
$response = $response->withHeader('Content-Type', 'video/'.$video->ext);
|
||||
if ($request->isGet()) {
|
||||
$response = $response->withBody(new Stream($stream));
|
||||
}
|
||||
$body = new Stream($stream);
|
||||
} elseif ($video->protocol == 'm3u8') {
|
||||
$stream = $this->download->getM3uStream($video);
|
||||
$response = $response->withHeader('Content-Type', 'video/'.$video->ext);
|
||||
if ($request->isGet()) {
|
||||
$response = $response->withBody(new Stream($stream));
|
||||
}
|
||||
$body = new Stream($stream);
|
||||
} else {
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$stream = $client->request('GET', $video->url, ['stream' => true]);
|
||||
$response = $response->withHeader('Content-Type', $stream->getHeader('Content-Type'));
|
||||
$response = $response->withHeader('Content-Length', $stream->getHeader('Content-Length'));
|
||||
if ($request->isGet()) {
|
||||
$response = $response->withBody($stream->getBody());
|
||||
}
|
||||
$body = $stream->getBody();
|
||||
}
|
||||
if ($request->isGet()) {
|
||||
$response = $response->withBody($body);
|
||||
}
|
||||
$response = $response->withHeader(
|
||||
'Content-Disposition',
|
||||
|
@ -353,7 +387,7 @@ class FrontController
|
|||
/**
|
||||
* Get a remuxed stream piped through the server.
|
||||
*
|
||||
* @param array $urls URLs of the video and audio files
|
||||
* @param string[] $urls URLs of the video and audio files
|
||||
* @param string $format Requested format
|
||||
* @param Response $response PSR-7 response
|
||||
* @param Request $request PSR-7 request
|
||||
|
@ -429,6 +463,10 @@ class FrontController
|
|||
$this->sessionSegment->getFlash($url)
|
||||
);
|
||||
} else {
|
||||
if (empty($videoUrls[0])) {
|
||||
throw new \Exception("Can't find URL of video");
|
||||
}
|
||||
|
||||
return $response->withRedirect($videoUrls[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,3 +10,11 @@
|
|||
font-weight: 400;
|
||||
src: local('Open Sans'), local('OpenSans'), url(../bower_components/opensans-googlefont/OpenSans-Regular.ttf);
|
||||
}
|
||||
|
||||
.small-font {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.large-font {
|
||||
font-size:24px;
|
||||
}
|
||||
|
|
730
css/style.css
730
css/style.css
|
@ -1,119 +1,118 @@
|
|||
|
||||
body {
|
||||
text-align:center;
|
||||
background-color: #EBEBEB;
|
||||
background-image:url('../img/fond.jpg');
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight:400;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************HEADER******************************/
|
||||
/* Header */
|
||||
|
||||
header {
|
||||
position:absolute;
|
||||
top:0;
|
||||
text-align:right;
|
||||
width:100%;
|
||||
padding:0;
|
||||
}
|
||||
position:absolute;
|
||||
text-align:right;
|
||||
top:0;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.social
|
||||
{padding-right:21px;}
|
||||
.social {
|
||||
padding-right:21px;
|
||||
}
|
||||
|
||||
|
||||
header a
|
||||
{
|
||||
overflow:hidden;
|
||||
height:38px;
|
||||
width:38px;
|
||||
position:relative;
|
||||
float:right;
|
||||
margin-top:13px;
|
||||
margin-left:13px;
|
||||
margin-right:0;
|
||||
background-position:0 0;
|
||||
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 .social a {
|
||||
background-position:0 0;
|
||||
background-repeat:no-repeat;
|
||||
float:right;
|
||||
height:38px;
|
||||
margin-left:13px;
|
||||
margin-right:0;
|
||||
margin-top:13px;
|
||||
overflow:hidden;
|
||||
position:relative;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
width:38px;
|
||||
}
|
||||
|
||||
header a:focus,
|
||||
header a:hover
|
||||
{
|
||||
outline:none;
|
||||
header a:hover {
|
||||
background-position:0 100%;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
outline:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
.share
|
||||
{background-image:url('../img/share.png');}
|
||||
|
||||
.sharemask
|
||||
{
|
||||
height:38px;
|
||||
width:38px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:10;
|
||||
background-image:url('../img/sharemask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
.share {
|
||||
background-image:url('../img/share.png');
|
||||
}
|
||||
|
||||
.facebook
|
||||
{background-image:url('../img/facebook.png');}
|
||||
.sharemask {
|
||||
background-image:url('../img/sharemask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
height:38px;
|
||||
left:0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
width:38px;
|
||||
z-index:10;
|
||||
|
||||
.facebookmask
|
||||
{
|
||||
height:38px;
|
||||
width:38px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:10;
|
||||
background-image:url('../img/facebookmask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
|
||||
.twitter
|
||||
{background-image:url('../img/twitter.png');}
|
||||
.facebook {
|
||||
background-image:url('../img/facebook.png');
|
||||
}
|
||||
|
||||
.twittermask
|
||||
{
|
||||
height:38px;
|
||||
width:38px;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
z-index:10;
|
||||
background-image:url('../img/twittermask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
.facebookmask {
|
||||
background-image:url('../img/facebookmask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
height:38px;
|
||||
left:0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
width:38px;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.twitter {
|
||||
background-image:url('../img/twitter.png');
|
||||
}
|
||||
|
||||
.twittermask {
|
||||
background-image:url('../img/twittermask.png');
|
||||
background-position:top left;
|
||||
background-repeat:no-repeat;
|
||||
height:38px;
|
||||
left:0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
width:38px;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************FOOTER****************************/
|
||||
/* Footer */
|
||||
|
||||
|
||||
footer {
|
||||
position:fixed;
|
||||
background-image:url('../img/fondfooter.png');
|
||||
background-position:top left;
|
||||
background-repeat:repeat-x;
|
||||
bottom:0;
|
||||
color:#adadad;
|
||||
padding-top:20px;
|
||||
position:fixed;
|
||||
text-align:center;
|
||||
width:100%;
|
||||
background-image:url('../img/fondfooter.png');
|
||||
background-repeat:repeat-x;
|
||||
background-position:top left;
|
||||
padding-top:20px;
|
||||
color:#adadad;
|
||||
font-size:12px;
|
||||
z-index:11;
|
||||
}
|
||||
|
||||
|
@ -123,20 +122,19 @@ footer {
|
|||
|
||||
footer a{
|
||||
color:#adadad;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
text-decoration:none;
|
||||
text-decoration:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
footer a:focus,
|
||||
footer a:hover
|
||||
{
|
||||
footer a:hover {
|
||||
color:#f2084a;
|
||||
outline:none;
|
||||
color:#f2084a;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,52 +142,47 @@ color:#f2084a;
|
|||
|
||||
|
||||
|
||||
/*************************CONTENT ACCUEIL****************************/
|
||||
/* Home content */
|
||||
|
||||
.logo {
|
||||
padding-bottom:55px;
|
||||
}
|
||||
|
||||
.labelurl
|
||||
{
|
||||
position:relative;
|
||||
color:#3f3f3f;
|
||||
font-size:19px;
|
||||
|
||||
.labelurl {
|
||||
color:#3f3f3f;
|
||||
font-size:19px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.champs
|
||||
{
|
||||
position:relative;
|
||||
margin-bottom:70px;
|
||||
margin-top:8px;
|
||||
.champs {
|
||||
margin-bottom:70px;
|
||||
margin-top:8px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.downloadBtn {
|
||||
position:relative;
|
||||
background-color:#3A3A3A;
|
||||
border: 3px solid #a5a5a5;
|
||||
color:#dedede;
|
||||
border-radius:10px;
|
||||
padding: 12px 14px;
|
||||
font-size:24px;
|
||||
font-weight:800;
|
||||
color:#dedede;
|
||||
cursor:pointer;
|
||||
display:inline-block;
|
||||
font-weight:800;
|
||||
padding: 12px 14px;
|
||||
position:relative;
|
||||
text-decoration:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
text-decoration:none;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
.downloadBtn:focus,
|
||||
.downloadBtn:hover
|
||||
{
|
||||
outline:none;
|
||||
.downloadBtn:hover {
|
||||
background-color:#f2084a;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
outline:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
.downloadBtn::-moz-focus-inner {
|
||||
|
@ -197,22 +190,21 @@ margin-top:8px;
|
|||
}
|
||||
|
||||
.URLinput{
|
||||
position:relative;
|
||||
background-color:#fff;
|
||||
border: 3px solid #a5a5a5;
|
||||
color:#3F3F3F;
|
||||
border-radius:10px;
|
||||
padding: 12px 12px 12px 12px;
|
||||
min-width:426px;
|
||||
font-size:24px;
|
||||
color:#3F3F3F;
|
||||
font-weight:800;
|
||||
margin-right:8px;
|
||||
min-width:426px;
|
||||
padding: 12px 12px 12px 12px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
|
||||
.URLinput:focus {
|
||||
outline: none;
|
||||
border-color:#3A3A3A;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.URLinput:-webkit-input-placeholder{
|
||||
|
@ -223,176 +215,163 @@ margin-top:8px;
|
|||
}
|
||||
|
||||
.combatiblelink {
|
||||
position:relative;
|
||||
color:#a5a5a5;
|
||||
font-size:13px;
|
||||
z-index:10;
|
||||
text-decoration:none;
|
||||
background-image:url('../img/compatiblerouage.png');
|
||||
background-position:0 100%;
|
||||
background-repeat:no-repeat;
|
||||
padding-left:41px;
|
||||
padding-top:10px;
|
||||
padding-bottom:10px;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
background-image:url('../img/compatiblerouage.png');
|
||||
background-position:0 100%;
|
||||
background-repeat:no-repeat;
|
||||
color:#a5a5a5;
|
||||
padding-bottom:10px;
|
||||
padding-left:41px;
|
||||
padding-top:10px;
|
||||
position:relative;
|
||||
text-decoration:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.combatiblelink:focus,
|
||||
.combatiblelink:hover
|
||||
{
|
||||
.combatiblelink:hover {
|
||||
background-position:0 0;
|
||||
color:#f2084a;
|
||||
outline:none;
|
||||
background-position:0 0;
|
||||
color:#f2084a;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
#bookmarklet{
|
||||
padding:15px;
|
||||
}
|
||||
|
||||
.bookmarklet{
|
||||
position:relative;
|
||||
font-size:13px;
|
||||
color:gray;
|
||||
z-index:10;
|
||||
text-decoration:none;
|
||||
padding-left:30px;
|
||||
padding-right:30px;
|
||||
padding-top:10px;
|
||||
padding-bottom:10px;
|
||||
border: 2px dotted;
|
||||
}
|
||||
|
||||
.mp3
|
||||
{
|
||||
.bookmarklet {
|
||||
border: 2px dotted;
|
||||
color:gray;
|
||||
padding:10px 30px;
|
||||
position:relative;
|
||||
text-decoration:none;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.mp3 {
|
||||
background-color:#cecece;
|
||||
color:#696969;
|
||||
border-radius:6px;
|
||||
width:622px;
|
||||
font-size:14px;
|
||||
color:#696969;
|
||||
height:26px;
|
||||
margin-top:12px;
|
||||
position:relative;
|
||||
text-align:left;
|
||||
font-weight:300;
|
||||
width:622px;
|
||||
}
|
||||
|
||||
.mp3 p
|
||||
{
|
||||
padding:3px;
|
||||
.mp3 p {
|
||||
padding:3px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Demo CSS code
|
||||
*/
|
||||
.audio:not(:checked),
|
||||
.audio:checked {
|
||||
left: -9999px;
|
||||
position: absolute;
|
||||
}
|
||||
.audio:not(:checked) + label,
|
||||
.audio:checked + label {
|
||||
cursor: pointer;
|
||||
line-height:22px;
|
||||
padding-left: 82px;
|
||||
position: relative;
|
||||
}
|
||||
.audio:not(:checked) + label:before,
|
||||
.audio:checked + label:before,
|
||||
.audio:not(:checked) + label:after,
|
||||
.audio:checked + label:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
}
|
||||
.audio:not(:checked) + label:before,
|
||||
.audio:checked + label:before {
|
||||
background: #ffffff;
|
||||
border-radius: 6px;
|
||||
height: 20px;
|
||||
left:0;
|
||||
top: -1px;
|
||||
-webkit-transition: background-color .2s;
|
||||
-moz-transition: background-color .2s;
|
||||
-ms-transition: background-color .2s;
|
||||
-o-transition: background-color .2s;
|
||||
transition: background-color .2s;
|
||||
width: 45px;
|
||||
}
|
||||
.audio:not(:checked) + label:after,
|
||||
.audio:checked + label:after {
|
||||
background: #3a3a3a;
|
||||
border-radius: 6px;
|
||||
height: 16px;
|
||||
left: 2px;
|
||||
top: 1px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.audio:not(:checked),
|
||||
.audio:checked {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
.audio:not(:checked) + label,
|
||||
.audio:checked + label {
|
||||
position: relative;
|
||||
padding-left: 82px;
|
||||
cursor: pointer;
|
||||
line-height:22px;
|
||||
}
|
||||
.audio:not(:checked) + label:before,
|
||||
.audio:checked + label:before,
|
||||
.audio:not(:checked) + label:after,
|
||||
.audio:checked + label:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
}
|
||||
.audio:not(:checked) + label:before,
|
||||
.audio:checked + label:before {
|
||||
left:0; top: -1px;
|
||||
width: 45px; height: 20px;
|
||||
background: #ffffff;
|
||||
border-radius: 6px;
|
||||
-webkit-transition: background-color .2s;
|
||||
-moz-transition: background-color .2s;
|
||||
-ms-transition: background-color .2s;
|
||||
-o-transition: background-color .2s;
|
||||
transition: background-color .2s;
|
||||
}
|
||||
.audio:not(:checked) + label:after,
|
||||
.audio:checked + label:after {
|
||||
width: 16px; height: 16px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
border-radius: 6px;
|
||||
background: #3a3a3a;
|
||||
top: 1px; left: 2px;
|
||||
}
|
||||
.audio:focus + label {
|
||||
color:black;
|
||||
}
|
||||
|
||||
.audio:focus + label {
|
||||
color:black;
|
||||
}
|
||||
/* on checked */
|
||||
.audio:checked + label:before {
|
||||
background:#f2084a;
|
||||
}
|
||||
.audio:checked + label:after {
|
||||
background: #fff;
|
||||
left: 27px;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
/* on checked */
|
||||
.audio:checked + label:before {
|
||||
background:#f2084a;
|
||||
}
|
||||
.audio:checked + label:after {
|
||||
background: #fff;
|
||||
top: 1px; left: 27px;
|
||||
}
|
||||
|
||||
.audio:checked + label .ui,
|
||||
.audio:not(:checked) + label .ui:before,
|
||||
.audio:checked + label .ui:after {
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
width: 45px;
|
||||
border-radius: 15px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
line-height: 17px;
|
||||
height:20px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
}
|
||||
.audio:not(:checked) + label .ui:before {
|
||||
content: "no";
|
||||
left: 0;
|
||||
padding-left:23px;
|
||||
padding-top:2px;
|
||||
background-image:url('../img/mp3hover.png');
|
||||
background-repeat:no-repeat;
|
||||
background-position:right top;
|
||||
width:56px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
}
|
||||
.audio:checked + label .ui:after {
|
||||
content: "yes";
|
||||
color: #fff;
|
||||
background-image:url('../img/mp3.png');
|
||||
background-repeat:no-repeat;
|
||||
background-position:right top;
|
||||
width:73px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
}
|
||||
.audio:checked + label .ui,
|
||||
.audio:not(:checked) + label .ui:before,
|
||||
.audio:checked + label .ui:after {
|
||||
border-radius: 15px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
height:20px;
|
||||
left: 3px;
|
||||
line-height: 17px;
|
||||
position: absolute;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
width: 45px;
|
||||
}
|
||||
.audio:not(:checked) + label .ui:before {
|
||||
background-image:url('../img/mp3hover.png');
|
||||
background-position:right top;
|
||||
background-repeat:no-repeat;
|
||||
content: "no";
|
||||
left: 0;
|
||||
min-width:56px;
|
||||
padding-left:23px;
|
||||
padding-top:2px;
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
}
|
||||
.audio:checked + label .ui:after {
|
||||
background-image:url('../img/mp3.png');
|
||||
background-position:right top;
|
||||
background-repeat:no-repeat;
|
||||
color: #fff;
|
||||
content: "yes";
|
||||
-webkit-transition: all .2s;
|
||||
-moz-transition: all .2s;
|
||||
-ms-transition: all .2s;
|
||||
-o-transition: all .2s;
|
||||
transition: all .2s;
|
||||
width:73px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -410,120 +389,114 @@ padding:3px;
|
|||
width: 600px;
|
||||
}
|
||||
|
||||
.playlist-entry h3 {
|
||||
.playlist-entry-title {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.playlist-entry h3 a {
|
||||
.playlist-entry-title a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.playlist-entry h3 a:hover {
|
||||
.playlist-entry-title a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.playlist-entry .downloadBtn {
|
||||
font-size: 16px;
|
||||
border-width: 2px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************CONTENT COMPATIBLES****************************/
|
||||
/* Supported websites list */
|
||||
|
||||
.logobis
|
||||
{
|
||||
width:447px;
|
||||
height:107px;
|
||||
position:relative;
|
||||
margin:0 auto 10px auto;
|
||||
.logobis {
|
||||
height:107px;
|
||||
margin:0 auto 10px auto;
|
||||
position:relative;
|
||||
width:447px;
|
||||
}
|
||||
|
||||
|
||||
.logocompatible
|
||||
{
|
||||
width:447px;
|
||||
height:107px;
|
||||
background-image:url('../img/logocompatible.png');
|
||||
background-repeat:repeat-y;
|
||||
background-position:0 0;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
display:block;
|
||||
.logocompatible {
|
||||
background-image:url('../img/logocompatible.png');
|
||||
background-position:0 0;
|
||||
background-repeat:repeat-y;
|
||||
display:block;
|
||||
height:107px;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
width:447px;
|
||||
}
|
||||
|
||||
.logocompatible:focus,
|
||||
.logocompatible:hover {
|
||||
outline:none;
|
||||
background-position:0 100%;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;}
|
||||
|
||||
|
||||
.logocompatiblemask
|
||||
{
|
||||
z-index:10;
|
||||
position:absolute;
|
||||
top:0;
|
||||
left:0;
|
||||
width:447px;
|
||||
height:107px;
|
||||
background-image:url('../img/logocompatiblemask.png');
|
||||
background-position:0 100%;
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
|
||||
.titre
|
||||
{
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-weight:300;
|
||||
color:#383838;
|
||||
font-size:48px;
|
||||
}
|
||||
|
||||
.tripleliste
|
||||
{
|
||||
margin-top:80px;
|
||||
width:800px;
|
||||
position:relative;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
outline:none;
|
||||
-webkit-transition: all 0.1s ease-in;
|
||||
-moz-transition: all 0.1s ease-in;
|
||||
-o-transition: all 0.1s ease-in;
|
||||
}
|
||||
|
||||
|
||||
.tripleliste ul
|
||||
{
|
||||
margin-bottom:1em;
|
||||
width:600px;
|
||||
margin-left:120px;}
|
||||
.logocompatiblemask {
|
||||
background-image:url('../img/logocompatiblemask.png');
|
||||
background-position:0 100%;
|
||||
background-repeat:no-repeat;
|
||||
height:107px;
|
||||
left:0;
|
||||
position:absolute;
|
||||
top:0;
|
||||
width:447px;
|
||||
z-index:10;
|
||||
}
|
||||
|
||||
.tripleliste ul li
|
||||
{text-align:left;
|
||||
List-Style-Type:none;
|
||||
color:#383838;
|
||||
font-size:16px;
|
||||
.titre {
|
||||
color:#383838;
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
font-size:48px;
|
||||
font-weight:300;
|
||||
}
|
||||
|
||||
width:200px;
|
||||
float:left;
|
||||
position:relative;
|
||||
.tripleliste {
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
margin-top:80px;
|
||||
position:relative;
|
||||
width:800px;
|
||||
}
|
||||
|
||||
|
||||
.tripleliste ul {
|
||||
margin-bottom:1em;
|
||||
margin-left:120px;
|
||||
width:600px;
|
||||
}
|
||||
|
||||
.tripleliste ul li {
|
||||
color:#383838;
|
||||
float:left;
|
||||
list-style-type:none;
|
||||
position:relative;
|
||||
text-align:left;
|
||||
width:200px;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
margin:0;
|
||||
height:100%;
|
||||
margin:0;
|
||||
}
|
||||
.wrapper {
|
||||
height:100%;
|
||||
display:table;
|
||||
margin:auto;
|
||||
padding-bottom:110px;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
display:table;
|
||||
height:100%;
|
||||
margin:auto;
|
||||
padding-bottom:110px;
|
||||
}
|
||||
.main {
|
||||
display:table-cell;
|
||||
|
@ -595,6 +568,65 @@ h1 {
|
|||
font-family:monospace;
|
||||
}
|
||||
|
||||
.locales {
|
||||
float: left;
|
||||
padding-left: 1em;
|
||||
padding-top: 1em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.locales a,
|
||||
.locales a:visited {
|
||||
color: #696969;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.supportedLocales {
|
||||
background-color: #fff;
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
padding-left: 0;
|
||||
transition: visibility 0.5s;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.supportedLocales li {
|
||||
border-bottom: thin solid #E1E1E1;
|
||||
}
|
||||
|
||||
.supportedLocales li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.supportedLocales li a {
|
||||
display: block;
|
||||
padding: 1em;
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
.supportedLocales li:hover {
|
||||
background-color: #cecece;
|
||||
}
|
||||
|
||||
.localesBtn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.localesBtn:focus {
|
||||
background-color: #fff;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.localesBtn:focus + .supportedLocales {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.formats,
|
||||
.thumb {
|
||||
|
@ -619,9 +651,9 @@ h1 {
|
|||
.champs,
|
||||
.URLinput,
|
||||
.mp3 {
|
||||
width:90%;
|
||||
margin:auto;
|
||||
height:auto;
|
||||
margin:auto;
|
||||
width:90%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
|
@ -629,8 +661,8 @@ h1 {
|
|||
}
|
||||
|
||||
.logocompatible img {
|
||||
width:100%;
|
||||
height: auto;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.downloadBtn {
|
||||
|
@ -646,9 +678,9 @@ h1 {
|
|||
|
||||
.tripleliste ul,
|
||||
.tripleliste {
|
||||
width:auto;
|
||||
margin-left:auto;
|
||||
margin-top:auto;
|
||||
width:auto;
|
||||
}
|
||||
|
||||
.logocompatiblemask {
|
||||
|
@ -656,9 +688,9 @@ h1 {
|
|||
}
|
||||
|
||||
.logocompatible {
|
||||
height:auto;
|
||||
background-image:none;
|
||||
background-color:#4F4F4F;
|
||||
background-image:none;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.logocompatiblemask,
|
||||
|
|
134
i18n/fr_FR/LC_MESSAGES/Alltube.po
Normal file
134
i18n/fr_FR/LC_MESSAGES/Alltube.po
Normal file
|
@ -0,0 +1,134 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: Pierre Rudloff <contact@rudloff.pro>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: fr_FR\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 1.6.10\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: templates/error.tpl:5
|
||||
msgid "An error occured"
|
||||
msgstr "Une erreur est survenue"
|
||||
|
||||
#: templates/error.tpl:6
|
||||
msgid "Please check the URL of your video."
|
||||
msgstr "Veuillez vérifier l'URL de votre vidéo"
|
||||
|
||||
#: templates/playlist.tpl:5
|
||||
msgid "Videos extracted from"
|
||||
msgstr "Vidéos extraites depuis"
|
||||
|
||||
#: templates/playlist.tpl:7
|
||||
msgid ":"
|
||||
msgstr " :"
|
||||
|
||||
#: templates/playlist.tpl:26 templates/password.tpl:10 templates/video.tpl:85
|
||||
#: templates/video.tpl:88 templates/index.tpl:18
|
||||
msgid "Download"
|
||||
msgstr "Télécharger"
|
||||
|
||||
#: templates/playlist.tpl:27
|
||||
msgid "More options"
|
||||
msgstr "Plus d'options"
|
||||
|
||||
#: templates/password.tpl:5
|
||||
msgid "This video is protected"
|
||||
msgstr "Cette vidéo est protégée"
|
||||
|
||||
#: templates/password.tpl:6
|
||||
msgid "You need a password in order to download this video."
|
||||
msgstr "L'accès à cette vidéo nécessite un mot de passe."
|
||||
|
||||
#: templates/password.tpl:8
|
||||
msgid "Video password"
|
||||
msgstr "Mot de passe de la vidéo"
|
||||
|
||||
#: templates/extractors.tpl:4
|
||||
msgid "Supported websites"
|
||||
msgstr "Sites web supportés"
|
||||
|
||||
#: templates/video.tpl:6
|
||||
msgid "You are going to download"
|
||||
msgstr "Vous allez télécharger"
|
||||
|
||||
#: templates/video.tpl:26
|
||||
msgid "Available formats:"
|
||||
msgstr "Formats disponibles :"
|
||||
|
||||
#: templates/video.tpl:31
|
||||
msgid "Generic formats"
|
||||
msgstr "Formats génériques"
|
||||
|
||||
#: templates/video.tpl:34
|
||||
msgid "Best"
|
||||
msgstr "Meilleure qualité"
|
||||
|
||||
#: templates/video.tpl:39
|
||||
msgid "Remux best video with best audio"
|
||||
msgstr "Combiner la meilleure vidéo avec le meilleur audio"
|
||||
|
||||
#: templates/video.tpl:43
|
||||
msgid "Worst"
|
||||
msgstr "Pire qualité"
|
||||
|
||||
#: templates/video.tpl:46
|
||||
msgid "Detailed formats"
|
||||
msgstr "Formats détaillés"
|
||||
|
||||
#: templates/inc/footer.tpl:4
|
||||
msgid "Code by"
|
||||
msgstr "Développé par"
|
||||
|
||||
#: templates/inc/footer.tpl:6
|
||||
msgid "Design by"
|
||||
msgstr "Designé par"
|
||||
|
||||
#: templates/inc/footer.tpl:12
|
||||
msgid "AllTube Download on Facebook"
|
||||
msgstr "AllTube Download sur Facebook"
|
||||
|
||||
#: templates/inc/footer.tpl:12
|
||||
msgid "Like us on Facebook"
|
||||
msgstr "Suivez-nous sur Facebook"
|
||||
|
||||
#: templates/inc/footer.tpl:14
|
||||
msgid "Get the code"
|
||||
msgstr "Obtenir le code"
|
||||
|
||||
#: templates/inc/footer.tpl:16
|
||||
msgid "Based on"
|
||||
msgstr "Basé sur"
|
||||
|
||||
#: templates/inc/header.tpl:4
|
||||
msgid "Share on Twitter"
|
||||
msgstr "Partager sur Twitter"
|
||||
|
||||
#: templates/inc/header.tpl:5
|
||||
msgid "Share on Facebook"
|
||||
msgstr "Partager sur Facebook"
|
||||
|
||||
#: templates/index.tpl:8
|
||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
||||
msgstr "Copiez ici l'URL de votre vidéo (Youtube, Dailymotion, etc.)"
|
||||
|
||||
#: templates/index.tpl:23
|
||||
msgid "Audio only (MP3)"
|
||||
msgstr "Audio uniquement (MP3)"
|
||||
|
||||
#: templates/index.tpl:28
|
||||
msgid "See all supported websites"
|
||||
msgstr "Voir tous les sites supportés"
|
||||
|
||||
#: templates/index.tpl:30
|
||||
msgid "Drag this to your bookmarks bar:"
|
||||
msgstr "Glissez ce lien dans votre barre de favoris :"
|
||||
|
||||
#: templates/index.tpl:31
|
||||
msgid "Bookmarklet"
|
||||
msgstr "Bookmarklet"
|
123
i18n/template.pot
Normal file
123
i18n/template.pot
Normal file
|
@ -0,0 +1,123 @@
|
|||
msgid ""
|
||||
msgstr "Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
#: templates/error.tpl:5
|
||||
msgid "An error occured"
|
||||
msgstr ""
|
||||
|
||||
#: templates/error.tpl:6
|
||||
msgid "Please check the URL of your video."
|
||||
msgstr ""
|
||||
|
||||
#: templates/playlist.tpl:5
|
||||
msgid "Videos extracted from"
|
||||
msgstr ""
|
||||
|
||||
#: templates/playlist.tpl:7
|
||||
msgid ":"
|
||||
msgstr ""
|
||||
|
||||
#: templates/playlist.tpl:26 templates/password.tpl:10 templates/video.tpl:85
|
||||
#: templates/video.tpl:88 templates/index.tpl:18
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
#: templates/playlist.tpl:27
|
||||
msgid "More options"
|
||||
msgstr ""
|
||||
|
||||
#: templates/password.tpl:5
|
||||
msgid "This video is protected"
|
||||
msgstr ""
|
||||
|
||||
#: templates/password.tpl:6
|
||||
msgid "You need a password in order to download this video."
|
||||
msgstr ""
|
||||
|
||||
#: templates/password.tpl:8
|
||||
msgid "Video password"
|
||||
msgstr ""
|
||||
|
||||
#: templates/extractors.tpl:4
|
||||
msgid "Supported websites"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:6
|
||||
msgid "You are going to download"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:26
|
||||
msgid "Available formats:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:31
|
||||
msgid "Generic formats"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:34
|
||||
msgid "Best"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:39
|
||||
msgid "Remux best video with best audio"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:43
|
||||
msgid "Worst"
|
||||
msgstr ""
|
||||
|
||||
#: templates/video.tpl:46
|
||||
msgid "Detailed formats"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:4
|
||||
msgid "Code by"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:6
|
||||
msgid "Design by"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:12
|
||||
msgid "AllTube Download on Facebook"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:12
|
||||
msgid "Like us on Facebook"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:14
|
||||
msgid "Get the code"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/footer.tpl:16
|
||||
msgid "Based on"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/header.tpl:4
|
||||
msgid "Share on Twitter"
|
||||
msgstr ""
|
||||
|
||||
#: templates/inc/header.tpl:5
|
||||
msgid "Share on Facebook"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.tpl:8
|
||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.tpl:23
|
||||
msgid "Audio only (MP3)"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.tpl:28
|
||||
msgid "See all supported websites"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.tpl:30
|
||||
msgid "Drag this to your bookmarks bar:"
|
||||
msgstr ""
|
||||
|
||||
#: templates/index.tpl:31
|
||||
msgid "Bookmarklet"
|
||||
msgstr ""
|
135
i18n/zh_CN/LC_MESSAGES/Alltube.po
Normal file
135
i18n/zh_CN/LC_MESSAGES/Alltube.po
Normal file
|
@ -0,0 +1,135 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: Shiqiang Yu <tony19955569@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: zh_CN\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Generator: Poedit 2.0.2\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: ..\..\..\templates/error.tpl:5
|
||||
msgid "An error occured"
|
||||
msgstr "出错了"
|
||||
|
||||
#: ..\..\..\templates/error.tpl:6
|
||||
msgid "Please check the URL of your video."
|
||||
msgstr "请检查您的视频的 URL。"
|
||||
|
||||
#: ..\..\..\templates/extractors.tpl:4
|
||||
msgid "Supported websites"
|
||||
msgstr "支持的网站"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:4
|
||||
msgid "Code by"
|
||||
msgstr "代码来自"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:6
|
||||
msgid "Design by"
|
||||
msgstr "设计来自"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:12
|
||||
msgid "AllTube Download on Facebook"
|
||||
msgstr "去Alltube Download的Facebook页面"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:12
|
||||
msgid "Like us on Facebook"
|
||||
msgstr "在Facebook关注我们"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:14
|
||||
msgid "Get the code"
|
||||
msgstr "获取代码"
|
||||
|
||||
#: ..\..\..\templates/inc/footer.tpl:16
|
||||
msgid "Based on"
|
||||
msgstr "基于"
|
||||
|
||||
#: ..\..\..\templates/inc/header.tpl:4
|
||||
msgid "Share on Twitter"
|
||||
msgstr "分享到 Twitter"
|
||||
|
||||
#: ..\..\..\templates/inc/header.tpl:5
|
||||
msgid "Share on Facebook"
|
||||
msgstr "分享到 Facebook"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:9
|
||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
||||
msgstr "在这里复制您的视频 (Youtube、 Dailymotion 等) 的 URL"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:19 ..\..\..\templates/password.tpl:10
|
||||
#: ..\..\..\templates/playlist.tpl:23 ..\..\..\templates/video.tpl:85
|
||||
#: ..\..\..\templates/video.tpl:90
|
||||
msgid "Download"
|
||||
msgstr "下载"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:24
|
||||
msgid "Audio only (MP3)"
|
||||
msgstr "仅限音频(mp3)"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:29
|
||||
msgid "See all supported websites"
|
||||
msgstr "请参阅支持的所有网站"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:31
|
||||
msgid "Drag this to your bookmarks bar:"
|
||||
msgstr "把这个拖到你的书签:"
|
||||
|
||||
#: ..\..\..\templates/index.tpl:32
|
||||
msgid "Bookmarklet"
|
||||
msgstr "书签工具"
|
||||
|
||||
#: ..\..\..\templates/password.tpl:5
|
||||
msgid "This video is protected"
|
||||
msgstr "这个视频受保护"
|
||||
|
||||
#: ..\..\..\templates/password.tpl:6
|
||||
msgid "You need a password in order to download this video."
|
||||
msgstr "你需要密码才能下载这个视频。"
|
||||
|
||||
#: ..\..\..\templates/password.tpl:8
|
||||
msgid "Video password"
|
||||
msgstr "视频密码"
|
||||
|
||||
#: ..\..\..\templates/playlist.tpl:5
|
||||
msgid "Videos extracted from the"
|
||||
msgstr "视频从"
|
||||
|
||||
#: ..\..\..\templates/playlist.tpl:7
|
||||
msgid "playlist:"
|
||||
msgstr "播放列表提取:"
|
||||
|
||||
#: ..\..\..\templates/playlist.tpl:24
|
||||
msgid "More options"
|
||||
msgstr "更多选项"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:6
|
||||
msgid "You are going to download"
|
||||
msgstr "你即将下载"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:24
|
||||
msgid "Available formats:"
|
||||
msgstr "可用的格式︰"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:31
|
||||
msgid "Generic formats"
|
||||
msgstr "通用格式"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:34
|
||||
msgid "Best"
|
||||
msgstr "最佳"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:39
|
||||
msgid "Remux best video with best audio"
|
||||
msgstr "重新封装最佳视频与最佳音频"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:43
|
||||
msgid "Worst"
|
||||
msgstr "最差"
|
||||
|
||||
#: ..\..\..\templates/video.tpl:46
|
||||
msgid "Detailed formats"
|
||||
msgstr "详细格式"
|
11
index.php
11
index.php
|
@ -3,6 +3,9 @@
|
|||
require_once __DIR__.'/vendor/autoload.php';
|
||||
use Alltube\Config;
|
||||
use Alltube\Controller\FrontController;
|
||||
use Alltube\LocaleManager;
|
||||
use Alltube\LocaleMiddleware;
|
||||
use Alltube\PlaylistArchiveStream;
|
||||
use Alltube\UglyRouter;
|
||||
use Alltube\ViewFactory;
|
||||
use Slim\App;
|
||||
|
@ -12,6 +15,8 @@ if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '/index.ph
|
|||
die;
|
||||
}
|
||||
|
||||
stream_wrapper_register('playlist', PlaylistArchiveStream::class);
|
||||
|
||||
$app = new App();
|
||||
$container = $app->getContainer();
|
||||
$config = Config::getInstance();
|
||||
|
@ -19,6 +24,8 @@ if ($config->uglyUrls) {
|
|||
$container['router'] = new UglyRouter();
|
||||
}
|
||||
$container['view'] = ViewFactory::create($container);
|
||||
$container['locale'] = new LocaleManager($_COOKIE);
|
||||
$app->add(new LocaleMiddleware($container));
|
||||
|
||||
$controller = new FrontController($container, null, $_COOKIE);
|
||||
|
||||
|
@ -40,4 +47,8 @@ $app->get(
|
|||
'/redirect',
|
||||
[$controller, 'redirect']
|
||||
)->setName('redirect');
|
||||
$app->get(
|
||||
'/locale/{locale}',
|
||||
[$controller, 'locale']
|
||||
)->setName('locale');
|
||||
$app->run();
|
||||
|
|
15
js/cast.js
15
js/cast.js
|
@ -33,10 +33,10 @@ var castModule = (function () {
|
|||
|
||||
function sessionListener(e) {
|
||||
session = e;
|
||||
session.addMediaListener(onMediaDiscovered.bind(this, 'addMediaListener'));
|
||||
session.addUpdateListener(updateListener.bind(this));
|
||||
session.addMediaListener(onMediaDiscovered);
|
||||
session.addUpdateListener(updateListener);
|
||||
if (session.media.length !== 0) {
|
||||
onMediaDiscovered('onRequestSessionSuccess', session.media[0]);
|
||||
onMediaDiscovered();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ var castModule = (function () {
|
|||
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);
|
||||
session.loadMedia(request, onMediaDiscovered, onMediaError);
|
||||
}
|
||||
|
||||
function onLaunchError(e) {
|
||||
|
@ -80,7 +80,8 @@ var castModule = (function () {
|
|||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -103,4 +104,6 @@ var castModule = (function () {
|
|||
};
|
||||
}());
|
||||
|
||||
window.addEventListener('load', castModule.init, false);
|
||||
if (typeof window === 'object') {
|
||||
window.addEventListener('load', castModule.init, false);
|
||||
}
|
||||
|
|
1603
package-lock.json
generated
Normal file
1603
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,16 @@
|
|||
{
|
||||
"name": "alltube",
|
||||
"description": "HTML GUI for youtube-dl",
|
||||
"version": "0.9.0",
|
||||
"version": "0.10.0",
|
||||
"author": "Pierre Rudloff",
|
||||
"bugs": "https://github.com/Rudloff/alltube/issues",
|
||||
"dependencies": {
|
||||
"bower": "~1.8.0",
|
||||
"grunt": "~1.0.1",
|
||||
"grunt-contrib-cssmin": "~2.0.0",
|
||||
"grunt-contrib-uglify": "~2.2.0"
|
||||
"grunt-contrib-csslint": "~2.0.0",
|
||||
"grunt-contrib-cssmin": "~2.2.0",
|
||||
"grunt-contrib-uglify": "~3.0.0",
|
||||
"grunt-potomo": "~3.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt-contrib-compress": "~1.4.1",
|
||||
|
|
|
@ -9,7 +9,7 @@ You can ususally download the video by doing *File > Save to* or *ctrl + S*.
|
|||
|
||||
## How do I change config parameters?
|
||||
|
||||
You need to create a YAML file called `config.yml` at the root of your project.
|
||||
You need to create a YAML file called `config.yml` in the `config/` folder.
|
||||
Here are the parameters that you can set:
|
||||
|
||||
* `youtubedl`: path to your youtube-dl binary
|
|
@ -1 +1 @@
|
|||
Sitemap: http://alltubedownload.net/sitemap.xml
|
||||
Sitemap: http://alltubedownload.net/resources/sitemap.xml
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<div class="wrapper">
|
||||
<div class="main error">
|
||||
{include file="inc/logo.tpl"}
|
||||
<h2>An error occured</h2>
|
||||
Please check the URL of your video.
|
||||
<h2>{t}An error occured{/t}</h2>
|
||||
{t}Please check the URL of your video.{/t}
|
||||
<p><i>
|
||||
{foreach $errors as $error}
|
||||
{$error|escape}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{include file='inc/head.tpl'}
|
||||
{include file='inc/header.tpl'}
|
||||
{include file='inc/logo.tpl'}
|
||||
<h2 class="titre">Supported websites</h2>
|
||||
<h2 class="titre">{t}Supported websites{/t}</h2>
|
||||
<div class="tripleliste">
|
||||
<ul>
|
||||
{foreach $extractors as $extractor}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
</div>
|
||||
<footer>
|
||||
<footer class="small-font">
|
||||
<div class="footer_wrapper">
|
||||
Code by <a rel="author" target="blank"
|
||||
{t}Code by{/t} <a rel="author" target="blank"
|
||||
href="http://rudloff.pro/">Pierre Rudloff</a>
|
||||
· Design by
|
||||
· {t}Design by{/t}
|
||||
<a rel="author" target="blank"
|
||||
href="http://olivierhaquette.fr">Olivier Haquette</a>
|
||||
·
|
||||
<a target="_blank"
|
||||
href="https://www.facebook.com/pages/AllTube-Download/571380966249415"
|
||||
title="AllTube Download on Facebook">Like us on Facebook</a>
|
||||
title="{t}AllTube Download on Facebook{/t}">{t}Like us on Facebook{/t}</a>
|
||||
·
|
||||
<a href="https://github.com/Rudloff/alltube">Get the code</a>
|
||||
<a href="https://github.com/Rudloff/alltube">{t}Get the code{/t}</a>
|
||||
·
|
||||
Based on <a href="http://rg3.github.io/youtube-dl/">youtube-dl</a>
|
||||
{t}Based on{/t} <a href="http://rg3.github.io/youtube-dl/">youtube-dl</a>
|
||||
</div>
|
||||
</footer>
|
||||
<script src="{base_url}/dist/main.js"></script>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{locale path="../i18n" domain="Alltube"}
|
||||
<!Doctype HTML>
|
||||
<html lang="en">
|
||||
<html {if isset($locale)}lang="{$locale->getBcp47()}"{/if}>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||
|
@ -20,6 +21,6 @@
|
|||
<meta name="twitter:creator" content="@Tael67" />
|
||||
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
|
||||
<meta name="theme-color" content="#4F4F4F">
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<link rel="manifest" href="{base_url}/resources/manifest.json" />
|
||||
</head>
|
||||
<body class="{$class}">
|
||||
|
|
|
@ -1,8 +1,26 @@
|
|||
<header>
|
||||
{if isset($supportedLocales)}
|
||||
<div class="locales small-font">
|
||||
<button class="localesBtn small-font" title="{t}Switch language{/t}">
|
||||
{if isset($locale)}
|
||||
{$locale->getCountry()->getEmoji()}
|
||||
{else}
|
||||
Set language
|
||||
{/if}
|
||||
</button>
|
||||
<ul class="supportedLocales">
|
||||
{foreach $supportedLocales as $supportedLocale}
|
||||
{if $supportedLocale != $locale}
|
||||
<li><a hreflang="{$supportedLocale->getBcp47()}" lang="{$supportedLocale->getBcp47()}" href="{path_for name='locale' data=['locale'=>$supportedLocale->getIso15897()]}">{$supportedLocale->getCountry()->getEmoji()} {$supportedLocale->getFullName()}</a></li>
|
||||
{/if}
|
||||
{/foreach}
|
||||
</ul>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="social">
|
||||
<a class="twitter" href="http://twitter.com/home?status={base_url|urlencode}" target="_blank">
|
||||
Share on Twitter<div class="twittermask"></div></a>
|
||||
<a class="facebook" href="https://www.facebook.com/sharer/sharer.php?u={base_url|urlencode}" target="_blank">Share on Facebook<div class="facebookmask"></div></a>
|
||||
<a class="twitter" href="http://twitter.com/home?status={base_url|urlencode}" title="{t}Share on Twitter{/t}" target="_blank">
|
||||
<div class="twittermask"></div></a>
|
||||
<a class="facebook" href="https://www.facebook.com/sharer/sharer.php?u={base_url|urlencode}" title="{t}Share on Facebook{/t}" target="_blank"><div class="facebookmask"></div></a>
|
||||
</div>
|
||||
</header>
|
||||
<div class="wrapper">
|
||||
|
|
|
@ -5,30 +5,30 @@
|
|||
alt="AllTube Download" width="328" height="284"></div>
|
||||
<form action="{path_for name="video"}">
|
||||
<label class="labelurl" for="url">
|
||||
Copy here the URL of your video (Youtube, Dailymotion, etc.)
|
||||
{t}Copy here the URL of your video (Youtube, Dailymotion, etc.){/t}
|
||||
</label>
|
||||
<div class="champs">
|
||||
<span class="URLinput_wrapper">
|
||||
<input class="URLinput" type="url" name="url" id="url"
|
||||
<input class="URLinput large-font" type="url" name="url" id="url"
|
||||
required autofocus placeholder="http://example.com/video" />
|
||||
</span>
|
||||
{if $uglyUrls}
|
||||
{if $config->uglyUrls}
|
||||
<input type="hidden" name="page" value="video" />
|
||||
{/if}
|
||||
<input class="downloadBtn" type="submit" value="Download" /><br/>
|
||||
{if $convert}
|
||||
<div class="mp3">
|
||||
<input class="downloadBtn large-font" type="submit" value="{t}Download{/t}" /><br/>
|
||||
{if $config->convert}
|
||||
<div class="mp3 small-font">
|
||||
<p><input type="checkbox" id="audio" class="audio" name="audio">
|
||||
<label for="audio"><span class="ui"></span>
|
||||
Audio only (MP3)</label></p>
|
||||
{t}Audio only (MP3){/t}</label></p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</form>
|
||||
<a class="combatiblelink" href="{path_for name="extractors"}">See all supported websites</a>
|
||||
<a class="combatiblelink small-font" href="{path_for name="extractors"}">{t}See all supported websites{/t}</a>
|
||||
<div id="bookmarklet" class="bookmarklet_wrapper">
|
||||
<p> Drag this to your bookmarks bar: </p>
|
||||
<a class="bookmarklet" href="javascript:window.location='{$domain}{path_for name='video'}?url='+encodeURIComponent(location.href);">Bookmarklet</a>
|
||||
<p> {t}Drag this to your bookmarks bar:{/t} </p>
|
||||
<a class="bookmarklet small-font" href="javascript:window.location='{$domain}{path_for name='video'}?url='+encodeURIComponent(location.href);">{t}Bookmarklet{/t}</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<div class="wrapper">
|
||||
<div class="main">
|
||||
{include file="inc/logo.tpl"}
|
||||
<h2>This video is protected</h2>
|
||||
<p>You need a password in order to download this video.</p>
|
||||
<h2>{t}This video is protected{/t}</h2>
|
||||
<p>{t}You need a password in order to download this video.{/t}</p>
|
||||
<form action="" method="POST">
|
||||
<input class="URLinput" type="password" name="password" title="Video password" />
|
||||
<input class="URLinput" type="password" name="password" title="{t}Video password{/t}" />
|
||||
<br/><br/>
|
||||
<input class="downloadBtn" type="submit" value="Download" />
|
||||
<input class="downloadBtn" type="submit" value="{t}Download{/t}" />
|
||||
</form>
|
||||
</div>
|
||||
{include file='inc/footer.tpl'}
|
||||
|
|
|
@ -2,13 +2,16 @@
|
|||
<div class="wrapper">
|
||||
<div class="main">
|
||||
{include file="inc/logo.tpl"}
|
||||
<p>Videos extracted from the {if isset($video->title)}<i>
|
||||
<p>{t}Videos extracted from{/t} {if isset($video->title)}<i>
|
||||
<a href="{$video->webpage_url}">
|
||||
{$video->title}</a></i>{/if} playlist:
|
||||
{$video->title}</a></i>{/if}{t}:{/t}
|
||||
</p>
|
||||
{if $config->stream}
|
||||
<a href="{path_for name="redirect"}?url={$video->webpage_url}" class="downloadBtn">Download everything</a>
|
||||
{/if}
|
||||
{foreach $video->entries as $video}
|
||||
<div class="playlist-entry">
|
||||
<h3><a target="_blank" href="{strip}
|
||||
<h3 class="playlist-entry-title"><a target="_blank" href="{strip}
|
||||
{if isset($video->ie_key) and $video->ie_key == Youtube and !filter_var($video->url, FILTER_VALIDATE_URL)}
|
||||
https://www.youtube.com/watch?v=
|
||||
{/if}
|
||||
|
@ -20,8 +23,8 @@
|
|||
{$video->title}
|
||||
{/if}
|
||||
</a></h3>
|
||||
<a target="_blank" class="downloadBtn" href="{path_for name="redirect"}?url={$video->url}">Download</a>
|
||||
<a target="_blank" href="{path_for name="video"}?url={$video->url}">More options</a>
|
||||
<a target="_blank" class="downloadBtn" href="{path_for name="redirect"}?url={$video->url}">{t}Download{/t}</a>
|
||||
<a target="_blank" href="{path_for name="video"}?url={$video->url}">{t}More options{/t}</a>
|
||||
</div>
|
||||
{/foreach}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div itemscope itemtype="http://schema.org/VideoObject">
|
||||
<div class="main">
|
||||
{include file="inc/logo.tpl"}
|
||||
<p id="download_intro">You are going to download<i itemprop="name">
|
||||
<p id="download_intro">{t}You are going to download{/t}<i itemprop="name">
|
||||
<a itemprop="url" id="video_link"
|
||||
data-ext="{$video->ext}"
|
||||
data-video="{$video->url|escape}"
|
||||
|
@ -20,30 +20,30 @@
|
|||
<meta itemprop="uploadDate" content="{$video->upload_date}" />
|
||||
{/if}
|
||||
<br/>
|
||||
<form action="{path_for name="redirect"}">
|
||||
<input type="hidden" name="url" value="{$video->webpage_url}" />
|
||||
{if isset($video->formats)}
|
||||
<h3><label for="format">Available formats:</label></h3>
|
||||
<form action="{path_for name="redirect"}">
|
||||
<input type="hidden" name="url" value="{$video->webpage_url}" />
|
||||
{if $uglyUrls}
|
||||
<h3><label for="format">{t}Available formats:{/t}</label></h3>
|
||||
{if $config->uglyUrls}
|
||||
<input type="hidden" name="page" value="redirect" />
|
||||
{/if}
|
||||
<select name="format" id="format" class="formats monospace">
|
||||
<optgroup label="Generic formats">
|
||||
<optgroup label="{t}Generic formats{/t}">
|
||||
<option value="best{$protocol}">
|
||||
{strip}
|
||||
Best ({$video->ext})
|
||||
{t}Best{/t} ({$video->ext})
|
||||
{/strip}
|
||||
</option>
|
||||
{if $remux}
|
||||
{if $config->remux}
|
||||
<option value="bestvideo+bestaudio">
|
||||
Remux best video with best audio
|
||||
{t}Remux best video with best audio{/t}
|
||||
</option>
|
||||
{/if}
|
||||
<option value="worst{$protocol}">
|
||||
Worst
|
||||
{t}Worst{/t}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="Detailed formats" class="monospace">
|
||||
<optgroup label="{t}Detailed formats{/t}" class="monospace">
|
||||
{foreach $video->formats as $format}
|
||||
{if $config->stream || $format->protocol|in_array:array('http', 'https')}
|
||||
{strip}
|
||||
|
@ -82,12 +82,10 @@
|
|||
{/foreach}
|
||||
</optgroup>
|
||||
</select><br/><br/>
|
||||
<input class="downloadBtn" type="submit" value="Download" /><br/>
|
||||
<input class="downloadBtn" type="submit" value="{t}Download{/t}" /><br/>
|
||||
</form>
|
||||
{else}
|
||||
<input type="hidden" name="format" value="best{$protocol}" />
|
||||
<a class="downloadBtn"
|
||||
href="{$video->url|escape}">Download</a><br/>
|
||||
<input class="downloadBtn" type="submit" value="{t}Download{/t}" /><br/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -24,7 +24,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->config = Config::getInstance('config_test.yml');
|
||||
$this->config = Config::getInstance('config/config_test.yml');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,7 +83,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
|
|||
Config::destroyInstance();
|
||||
putenv('CONVERT=1');
|
||||
putenv('PYTHON=foo');
|
||||
$config = Config::getInstance('config_test.yml');
|
||||
$config = Config::getInstance('config/config_test.yml');
|
||||
$this->assertEquals($config->convert, true);
|
||||
$this->assertEquals($config->python, 'foo');
|
||||
putenv('CONVERT');
|
||||
|
|
|
@ -7,6 +7,7 @@ namespace Alltube\Test;
|
|||
|
||||
use Alltube\Config;
|
||||
use Alltube\Controller\FrontController;
|
||||
use Alltube\LocaleManager;
|
||||
use Alltube\ViewFactory;
|
||||
use Slim\Container;
|
||||
use Slim\Http\Environment;
|
||||
|
@ -55,7 +56,8 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
|
|||
$this->request = Request::createFromEnvironment(Environment::mock());
|
||||
$this->response = new Response();
|
||||
$this->container['view'] = ViewFactory::create($this->container, $this->request);
|
||||
$this->controller = new FrontController($this->container, Config::getInstance('config_test.yml'));
|
||||
$this->container['locale'] = new LocaleManager();
|
||||
$this->controller = new FrontController($this->container, Config::getInstance('config/config_test.yml'));
|
||||
$this->container['router']->map(['GET'], '/', [$this->controller, 'index'])
|
||||
->setName('index');
|
||||
$this->container['router']->map(['GET'], '/video', [$this->controller, 'video'])
|
||||
|
@ -64,6 +66,8 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
|
|||
->setName('extractors');
|
||||
$this->container['router']->map(['GET'], '/redirect', [$this->controller, 'redirect'])
|
||||
->setName('redirect');
|
||||
$this->container['router']->map(['GET'], '/locale', [$this->controller, 'locale'])
|
||||
->setName('locale');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -396,7 +400,7 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$this->assertRequestIsOk(
|
||||
'redirect',
|
||||
['url'=> 'http://www.rtl2.de/sendung/grip-das-motormagazin/folge/folge-203-0'],
|
||||
['url'=> 'http://www.canalc2.tv/video/12163', 'format'=>'rtmp'],
|
||||
new Config(['stream'=>true])
|
||||
);
|
||||
}
|
||||
|
@ -453,4 +457,48 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
$this->assertRequestIsServerError('redirect', ['url'=>'http://example.com/foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the redirect() function with an video that returns an empty URL.
|
||||
* This can be caused by trying to redirect to a playlist.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRedirectWithEmptyUrl()
|
||||
{
|
||||
$this->assertRequestIsServerError(
|
||||
'redirect',
|
||||
['url'=> 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the redirect() function with a playlist stream.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testRedirectWithPlaylist()
|
||||
{
|
||||
$this->assertRequestIsOk(
|
||||
'redirect',
|
||||
['url'=> 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC'],
|
||||
new Config(['stream'=>true])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the locale() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLocale()
|
||||
{
|
||||
$this->assertTrue(
|
||||
$this->controller->locale(
|
||||
$this->request,
|
||||
$this->response,
|
||||
['locale'=> 'fr_FR']
|
||||
)->isRedirect()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
77
tests/LocaleManagerTest.php
Normal file
77
tests/LocaleManagerTest.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
/**
|
||||
* LocaleManagerTest class.
|
||||
*/
|
||||
|
||||
namespace Alltube\Test;
|
||||
|
||||
use Alltube\Locale;
|
||||
use Alltube\LocaleManager;
|
||||
|
||||
/**
|
||||
* Unit tests for the Config class.
|
||||
*/
|
||||
class LocaleManagerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* LocaleManager class instance.
|
||||
*
|
||||
* @var LocaleManager
|
||||
*/
|
||||
private $localeManager;
|
||||
|
||||
/**
|
||||
* Prepare tests.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->localeManager = new LocaleManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getSupportedLocales function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConstructorWithCookies()
|
||||
{
|
||||
$_SESSION['Alltube\LocaleManager']['locale'] = 'foo_BAR';
|
||||
$localeManager = new LocaleManager([]);
|
||||
$this->assertEquals('foo_BAR', (string) $localeManager->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getSupportedLocales function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetSupportedLocales()
|
||||
{
|
||||
foreach ($this->localeManager->getSupportedLocales() as $locale) {
|
||||
$this->assertInstanceOf(Locale::class, $locale);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getLocale function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetLocale()
|
||||
{
|
||||
$this->assertNull($this->localeManager->getLocale());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the setLocale function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testSetLocale()
|
||||
{
|
||||
$this->localeManager->setLocale(new Locale('foo_BAR'));
|
||||
$locale = $this->localeManager->getLocale();
|
||||
$this->assertInstanceOf(Locale::class, $locale);
|
||||
$this->assertEquals('foo_BAR', (string) $locale);
|
||||
}
|
||||
}
|
107
tests/LocaleMiddlewareTest.php
Normal file
107
tests/LocaleMiddlewareTest.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
/**
|
||||
* LocaleMiddlewareTest class.
|
||||
*/
|
||||
|
||||
namespace Alltube\Test;
|
||||
|
||||
use Alltube\LocaleManager;
|
||||
use Alltube\LocaleMiddleware;
|
||||
use Slim\Container;
|
||||
use Slim\Http\Environment;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Http\Response;
|
||||
|
||||
/**
|
||||
* Unit tests for the FrontController class.
|
||||
*/
|
||||
class LocaleMiddlewareTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* LocaleMiddleware instance.
|
||||
*
|
||||
* @var LocaleMiddleware
|
||||
*/
|
||||
private $middleware;
|
||||
|
||||
/**
|
||||
* Prepare tests.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$container = new Container();
|
||||
$container['locale'] = new LocaleManager();
|
||||
$this->middleware = new LocaleMiddleware($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the testLocale() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testTestLocale()
|
||||
{
|
||||
$locale = [
|
||||
'language'=> 'fr',
|
||||
'region' => 'FR',
|
||||
];
|
||||
$this->assertEquals('fr_FR', $this->middleware->testLocale($locale));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the testLocale() function with an unsupported locale.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLocaleWithWrongLocale()
|
||||
{
|
||||
$locale = [
|
||||
'language'=> 'foo',
|
||||
'region' => 'BAR',
|
||||
];
|
||||
$this->assertNull($this->middleware->testLocale($locale));
|
||||
$this->assertNull($this->middleware->testLocale([]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the __invoke() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvoke()
|
||||
{
|
||||
$request = Request::createFromEnvironment(Environment::mock());
|
||||
$this->middleware->__invoke(
|
||||
$request->withHeader('Accept-Language', 'fr-FR'),
|
||||
new Response(),
|
||||
function () {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the __invoke() function withot the Accept-Language header.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testInvokeWithoutHeader()
|
||||
{
|
||||
$request = Request::createFromEnvironment(Environment::mock());
|
||||
$this->middleware->__invoke(
|
||||
$request->withoutHeader('Accept-Language'),
|
||||
new Response(),
|
||||
function () {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the environment is correctly set up.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testEnv()
|
||||
{
|
||||
$this->markTestIncomplete('We need to find a way to reliably test LC_ALL and LANG values');
|
||||
}
|
||||
}
|
79
tests/LocaleTest.php
Normal file
79
tests/LocaleTest.php
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* LocaleTest class.
|
||||
*/
|
||||
|
||||
namespace Alltube\Test;
|
||||
|
||||
use Alltube\Locale;
|
||||
|
||||
/**
|
||||
* Unit tests for the Config class.
|
||||
*/
|
||||
class LocaleTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* Locale class instance.
|
||||
*
|
||||
* @var Locale
|
||||
*/
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* Prepare tests.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->locale = new Locale('fr_FR');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the __toString function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetToString()
|
||||
{
|
||||
$this->assertEquals('fr_FR', $this->locale->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getFullName function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetFullName()
|
||||
{
|
||||
$this->assertEquals('français (France)', $this->locale->getFullName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getIso15897 function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetIso15897()
|
||||
{
|
||||
$this->assertEquals('fr_FR', $this->locale->getIso15897());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getBcp47 function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetBcp47()
|
||||
{
|
||||
$this->assertEquals('fr-FR', $this->locale->getBcp47());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the getIso3166 function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetIso3166()
|
||||
{
|
||||
$this->assertEquals('fr', $this->locale->getIso3166());
|
||||
}
|
||||
}
|
105
tests/PlaylistArchiveStreamTest.php
Normal file
105
tests/PlaylistArchiveStreamTest.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* PlaylistArchiveStreamTest class.
|
||||
*/
|
||||
|
||||
namespace Alltube\Test;
|
||||
|
||||
use Alltube\PlaylistArchiveStream;
|
||||
|
||||
/**
|
||||
* Unit tests for the ViewFactory class.
|
||||
*/
|
||||
class PlaylistArchiveStreamTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* PlaylistArchiveStream instance.
|
||||
*
|
||||
* @var PlaylistArchiveStream
|
||||
*/
|
||||
private $stream;
|
||||
|
||||
/**
|
||||
* Prepare tests.
|
||||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->stream = new PlaylistArchiveStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_open() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamOpen()
|
||||
{
|
||||
$this->assertTrue($this->stream->stream_open('playlist://foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_write() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamWrite()
|
||||
{
|
||||
$this->assertEquals(0, $this->stream->stream_write());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_stat() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamStat()
|
||||
{
|
||||
$this->assertEquals(['mode'=>4096], $this->stream->stream_stat());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_tell() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamTell()
|
||||
{
|
||||
$this->stream->stream_open('playlist://foo');
|
||||
$this->assertInternalType('int', $this->stream->stream_tell());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_seek() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamSeek()
|
||||
{
|
||||
$this->stream->stream_open('playlist://foo');
|
||||
$this->assertInternalType('bool', $this->stream->stream_seek(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_read() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamRead()
|
||||
{
|
||||
$this->stream->stream_open('playlist://BaW_jenozKc;BaW_jenozKc/worst');
|
||||
while (!$this->stream->stream_eof()) {
|
||||
$this->assertLessThanOrEqual(8192, strlen($this->stream->stream_read(8192)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the stream_eof() function.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testStreamEof()
|
||||
{
|
||||
$this->stream->stream_open('playlist://foo');
|
||||
$this->assertFalse($this->stream->stream_eof());
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
*/
|
||||
protected function setUp()
|
||||
{
|
||||
$this->download = new VideoDownload(Config::getInstance('config_test.yml'));
|
||||
$this->download = new VideoDownload(Config::getInstance('config/config_test.yml'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,32 +151,32 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
return [
|
||||
[
|
||||
'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'best[protocol^=http]',
|
||||
"It's Not Me, It's You - Hearts Under Fire-M7IpKCZ47pU",
|
||||
'It_s_Not_Me_It_s_You_-_Hearts_Under_Fire-M7IpKCZ47pU',
|
||||
'mp4',
|
||||
'googlevideo.com',
|
||||
],
|
||||
[
|
||||
'https://www.youtube.com/watch?v=RJJ6FCAXvKg', 22,
|
||||
"'Heart Attack' - Demi Lovato ".
|
||||
'(Sam Tsui & Against The Current)-RJJ6FCAXvKg',
|
||||
'Heart_Attack_-_Demi_Lovato_'.
|
||||
'Sam_Tsui_Against_The_Current-RJJ6FCAXvKg',
|
||||
'mp4',
|
||||
'googlevideo.com',
|
||||
],
|
||||
[
|
||||
'https://vimeo.com/24195442', 'best[protocol^=http]',
|
||||
'Carving the Mountains-24195442',
|
||||
'Carving_the_Mountains-24195442',
|
||||
'mp4',
|
||||
'vimeocdn.com',
|
||||
],
|
||||
[
|
||||
'http://www.bbc.co.uk/programmes/b039g8p7', 'bestaudio/best',
|
||||
'Leonard Cohen, Kaleidoscope - BBC Radio 4-b039d07m',
|
||||
'Leonard_Cohen_Kaleidoscope_-_BBC_Radio_4-b039d07m',
|
||||
'flv',
|
||||
'bbcodspdns.fcod.llnwd.net',
|
||||
],
|
||||
[
|
||||
'http://www.rtl2.de/sendung/grip-das-motormagazin/folge/folge-203-0', 'bestaudio/best',
|
||||
'GRIP sucht den Sommerkönig-folge-203-0',
|
||||
'GRIP_sucht_den_Sommerkonig-folge-203-0',
|
||||
'f4v',
|
||||
'edgefcs.net',
|
||||
],
|
||||
|
@ -193,7 +193,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
return [
|
||||
[
|
||||
'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'bestvideo+bestaudio',
|
||||
"It's Not Me, It's You - Hearts Under Fire-M7IpKCZ47pU",
|
||||
'It_s_Not_Me_It_s_You_-_Hearts_Under_Fire-M7IpKCZ47pU',
|
||||
'mp4',
|
||||
'googlevideo.com',
|
||||
],
|
||||
|
@ -210,7 +210,7 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
return [
|
||||
[
|
||||
'https://twitter.com/verge/status/813055465324056576/video/1', 'best',
|
||||
'The Verge - This tiny origami robot can self-fold and complete tasks-813055465324056576',
|
||||
'The_Verge_-_This_tiny_origami_robot_can_self-fold_and_complete_tasks-813055465324056576',
|
||||
'mp4',
|
||||
'video.twimg.com',
|
||||
],
|
||||
|
@ -226,10 +226,10 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
{
|
||||
return [
|
||||
[
|
||||
'http://www.rtl2.de/sendung/grip-das-motormagazin/folge/folge-203-0', 'bestaudio/best',
|
||||
'GRIP sucht den Sommerkönig-folge-203-0',
|
||||
'f4v',
|
||||
'edgefcs.net',
|
||||
'http://www.canalc2.tv/video/12163', 'rtmp',
|
||||
'Terrasses_du_Numerique-12163',
|
||||
'flv',
|
||||
'vod-flash.u-strasbg.fr',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
@ -480,4 +480,18 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
|||
$video = $download->getJSON($url, $format);
|
||||
$download->getM3uStream($video);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPlaylistArchiveStream function without avconv.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetPlaylistArchiveStream()
|
||||
{
|
||||
$video = $this->download->getJSON(
|
||||
'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC',
|
||||
'best'
|
||||
);
|
||||
$this->assertStream($this->download->getPlaylistArchiveStream($video, 'best'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace Alltube\Test;
|
|||
|
||||
use Alltube\ViewFactory;
|
||||
use Slim\Container;
|
||||
use Slim\Http\Environment;
|
||||
use Slim\Http\Request;
|
||||
use Slim\Views\Smarty;
|
||||
|
||||
/**
|
||||
|
@ -24,4 +26,16 @@ class ViewFactoryTest extends \PHPUnit_Framework_TestCase
|
|||
$view = ViewFactory::create(new Container());
|
||||
$this->assertInstanceOf(Smarty::class, $view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the create() function with a X-Forwarded-Proto header.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testCreateWithXForwardedProto()
|
||||
{
|
||||
$request = Request::createFromEnvironment(Environment::mock());
|
||||
$view = ViewFactory::create(new Container(), $request->withHeader('X-Forwarded-Proto', 'https'));
|
||||
$this->assertInstanceOf(Smarty::class, $view);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
/**
|
||||
* File used to bootstrap tests.
|
||||
*/
|
||||
use Alltube\PlaylistArchiveStream;
|
||||
|
||||
/**
|
||||
* Composer autoload.
|
||||
|
@ -9,3 +10,5 @@
|
|||
require_once __DIR__.'/../vendor/autoload.php';
|
||||
|
||||
session_start();
|
||||
|
||||
stream_wrapper_register('playlist', PlaylistArchiveStream::class);
|
||||
|
|
Loading…
Reference in a new issue