Merge branch 'release/3.1.0'
This commit is contained in:
commit
36a91c8d4d
64 changed files with 2006 additions and 1336 deletions
24
.github/workflows/ci.yml
vendored
Normal file
24
.github/workflows/ci.yml
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
name: Tests
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
jobs:
|
||||||
|
tests:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
php-version:
|
||||||
|
- '7.3'
|
||||||
|
- '7.4'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use PHP ${{ matrix.php-version }}
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php-version }}
|
||||||
|
tools: composer
|
||||||
|
- run: composer install --no-progress
|
||||||
|
- run: composer check-platform-reqs
|
||||||
|
- run: composer lint
|
||||||
|
- run: composer test
|
|
@ -18,9 +18,6 @@ FileETag None
|
||||||
<ifmodule mod_rewrite.c>
|
<ifmodule mod_rewrite.c>
|
||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
RewriteCond %{HTTP_HOST} ^alltube\.herokuapp\.com$ [NC]
|
|
||||||
RewriteRule ^(.*)$ https://www.alltubedownload.net/$1 [R=301,L]
|
|
||||||
|
|
||||||
RewriteCond %{REQUEST_FILENAME} !-f
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
RewriteRule ^ index.php [QSA,L]
|
RewriteRule ^ index.php [QSA,L]
|
||||||
</ifmodule>
|
</ifmodule>
|
||||||
|
|
12
.travis.yml
12
.travis.yml
|
@ -1,12 +0,0 @@
|
||||||
---
|
|
||||||
language: php
|
|
||||||
php: 7.3
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- language-pack-fr
|
|
||||||
install: composer install --no-progress
|
|
||||||
script:
|
|
||||||
- composer check-platform-reqs
|
|
||||||
- composer lint
|
|
||||||
- composer test
|
|
|
@ -1,6 +1,6 @@
|
||||||
# AllTube Download
|
# AllTube Download
|
||||||
|
|
||||||
HTML GUI for youtube-dl ([alltubedownload.net](http://alltubedownload.net/))
|
HTML GUI for youtube-dl
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ If you want to serve the application under a basepath and/or with a different in
|
||||||
* X-Forwarded-Host (ex. `another.domain.com`)
|
* X-Forwarded-Host (ex. `another.domain.com`)
|
||||||
* X-Forwarded-Path (ex: `/alltube`)
|
* X-Forwarded-Path (ex: `/alltube`)
|
||||||
* X-Forwarded-Port (ex: `5555`)
|
* X-Forwarded-Port (ex: `5555`)
|
||||||
|
* X-Forwarded-Proto (ex: `https`)
|
||||||
|
|
||||||
### Apache
|
### Apache
|
||||||
|
|
||||||
|
@ -164,7 +165,7 @@ so that you can reuse it in your projects.
|
||||||
## JSON API
|
## JSON API
|
||||||
|
|
||||||
We also provide a JSON API that you can use like this:
|
We also provide a JSON API that you can use like this:
|
||||||
[/json?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ](https://alltubedownload.net/json?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ)
|
`/json?url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdQw4w9WgXcQ`
|
||||||
|
|
||||||
It returns a JSON object generated by youtube-dl.
|
It returns a JSON object generated by youtube-dl.
|
||||||
You can find a list of all the properties [in the youtube-dl documentation](https://github.com/ytdl-org/youtube-dl#output-template).
|
You can find a list of all the properties [in the youtube-dl documentation](https://github.com/ytdl-org/youtube-dl#output-template).
|
||||||
|
|
4
app.json
4
app.json
|
@ -2,7 +2,6 @@
|
||||||
"name": "AllTube Download",
|
"name": "AllTube Download",
|
||||||
"description": "HTML GUI for youtube-dl",
|
"description": "HTML GUI for youtube-dl",
|
||||||
"repository": "https://github.com/Rudloff/alltube.git",
|
"repository": "https://github.com/Rudloff/alltube.git",
|
||||||
"logo": "https://alltubedownload.net/img/logo.png",
|
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"alltube",
|
"alltube",
|
||||||
"download",
|
"download",
|
||||||
|
@ -28,6 +27,5 @@
|
||||||
"value": "false",
|
"value": "false",
|
||||||
"required": false
|
"required": false
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"website": "https://alltubedownload.net/"
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class App extends \Slim\App
|
||||||
// Middlewares.
|
// Middlewares.
|
||||||
$this->add(new LocaleMiddleware($container));
|
$this->add(new LocaleMiddleware($container));
|
||||||
$this->add(new CspMiddleware($container));
|
$this->add(new CspMiddleware($container));
|
||||||
$this->add(new LinkHeaderMiddleware($container));
|
$this->add(new LinkHeaderMiddleware());
|
||||||
$this->add(new RouterPathMiddleware($container));
|
$this->add(new RouterPathMiddleware($container));
|
||||||
|
|
||||||
// Controllers.
|
// Controllers.
|
||||||
|
@ -94,7 +94,7 @@ class App extends \Slim\App
|
||||||
|
|
||||||
$this->any(
|
$this->any(
|
||||||
'/watch',
|
'/watch',
|
||||||
[$frontController, 'info']
|
[$frontController, 'watch']
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->any(
|
$this->any(
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Config
|
||||||
/**
|
/**
|
||||||
* Config constructor.
|
* Config constructor.
|
||||||
*
|
*
|
||||||
* @param mixed[] $options Options
|
* @param scalar[]|scalar[][]|null[] $options Options
|
||||||
* @throws ConfigException
|
* @throws ConfigException
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = [])
|
public function __construct(array $options = [])
|
||||||
|
@ -205,7 +205,7 @@ class Config
|
||||||
* @throws ConfigException If Python is missing
|
* @throws ConfigException If Python is missing
|
||||||
* @throws ConfigException If youtube-dl is missing
|
* @throws ConfigException If youtube-dl is missing
|
||||||
*/
|
*/
|
||||||
private function validateOptions()
|
private function validateOptions(): void
|
||||||
{
|
{
|
||||||
if (!is_file($this->youtubedl)) {
|
if (!is_file($this->youtubedl)) {
|
||||||
throw new ConfigException("Can't find youtube-dl at " . $this->youtubedl);
|
throw new ConfigException("Can't find youtube-dl at " . $this->youtubedl);
|
||||||
|
@ -222,11 +222,11 @@ class Config
|
||||||
/**
|
/**
|
||||||
* Apply the provided options.
|
* Apply the provided options.
|
||||||
*
|
*
|
||||||
* @param mixed[] $options Options
|
* @param scalar[]|scalar[][]|null[] $options Options
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function applyOptions(array $options)
|
private function applyOptions(array $options): void
|
||||||
{
|
{
|
||||||
foreach ($options as $option => $value) {
|
foreach ($options as $option => $value) {
|
||||||
if (isset($this->$option) && isset($value)) {
|
if (isset($this->$option) && isset($value)) {
|
||||||
|
@ -243,7 +243,7 @@ class Config
|
||||||
* @return void
|
* @return void
|
||||||
* @throws ConfigException
|
* @throws ConfigException
|
||||||
*/
|
*/
|
||||||
private function getEnv()
|
private function getEnv(): void
|
||||||
{
|
{
|
||||||
foreach (get_object_vars($this) as $prop => $value) {
|
foreach (get_object_vars($this) as $prop => $value) {
|
||||||
try {
|
try {
|
||||||
|
@ -278,11 +278,11 @@ class Config
|
||||||
/**
|
/**
|
||||||
* Manually set some options.
|
* Manually set some options.
|
||||||
*
|
*
|
||||||
* @param mixed[] $options Options (see `config/config.example.yml` for available options)
|
* @param scalar[]|scalar[][]|null[] $options Options (see `config/config.example.yml` for available options)
|
||||||
* @return void
|
* @return void
|
||||||
* @throws ConfigException
|
* @throws ConfigException
|
||||||
*/
|
*/
|
||||||
public function setOptions(array $options)
|
public function setOptions(array $options): void
|
||||||
{
|
{
|
||||||
$this->applyOptions($options);
|
$this->applyOptions($options);
|
||||||
$this->validateOptions();
|
$this->validateOptions();
|
||||||
|
|
|
@ -169,10 +169,8 @@ abstract class BaseController
|
||||||
*/
|
*/
|
||||||
protected function getVideoPageUrl(Request $request): string
|
protected function getVideoPageUrl(Request $request): string
|
||||||
{
|
{
|
||||||
$url = $request->getQueryParam('url') ?: $request->getQueryParam('v');
|
|
||||||
|
|
||||||
// Prevent SSRF attacks.
|
// Prevent SSRF attacks.
|
||||||
$parts = Url::validateUrl($url, new Options());
|
$parts = Url::validateUrl($request->getQueryParam('url'), new Options());
|
||||||
|
|
||||||
return $parts['url'];
|
return $parts['url'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,13 +220,12 @@ class DownloadController extends BaseController
|
||||||
if ($request->isGet()) {
|
if ($request->isGet()) {
|
||||||
$response = $response->withBody($body);
|
$response = $response->withBody($body);
|
||||||
}
|
}
|
||||||
$response = $response->withHeader(
|
|
||||||
|
return $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="' .
|
'attachment; filename="' .
|
||||||
$this->video->getFilename() . '"'
|
$this->video->getFilename() . '"'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -14,6 +14,8 @@ use Alltube\Middleware\CspMiddleware;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException;
|
use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException;
|
||||||
use Slim\Http\StatusCode;
|
use Slim\Http\StatusCode;
|
||||||
|
use Slim\Http\Uri;
|
||||||
|
use stdClass;
|
||||||
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
use Psr\Container\ContainerInterface;
|
use Psr\Container\ContainerInterface;
|
||||||
|
@ -146,7 +148,7 @@ class FrontController extends BaseController
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
* @throws AlltubeLibraryException
|
* @throws AlltubeLibraryException
|
||||||
*/
|
*/
|
||||||
private function getInfoResponse(Request $request, Response $response)
|
private function getInfoResponse(Request $request, Response $response): Response
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$this->video->getJson();
|
$this->video->getJson();
|
||||||
|
@ -176,6 +178,50 @@ class FrontController extends BaseController
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$formats = [];
|
||||||
|
$genericFormatsLabel = $this->localeManager->t('Generic formats');
|
||||||
|
$detailedFormatsLabel = $this->localeManager->t('Detailed formats');
|
||||||
|
|
||||||
|
foreach ($this->config->genericFormats as $id => $genericFormat) {
|
||||||
|
$formats[$genericFormatsLabel][$id] = $this->localeManager->t($genericFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = $this->video->getJson();
|
||||||
|
if (isset($json->formats)) {
|
||||||
|
/** @var stdClass $format */
|
||||||
|
foreach ($json->formats as $format) {
|
||||||
|
if ($this->config->stream || in_array($format->protocol, ['http', 'https'])) {
|
||||||
|
$formatParts = [
|
||||||
|
// File extension
|
||||||
|
$format->ext,
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($format->width) || isset($format->height)) {
|
||||||
|
// Video dimensions
|
||||||
|
$formatParts[] = implode('x', array_filter([$format->width, $format->height]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($format->filesize)) {
|
||||||
|
// File size
|
||||||
|
$formatParts[] = round($format->filesize / 1000000, 2) . ' MB';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($format->format_note)) {
|
||||||
|
// Format name
|
||||||
|
$formatParts[] = $format->format_note;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($format->format_id)) {
|
||||||
|
// Format ID
|
||||||
|
$formatParts[] = '(' . $format->format_id . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
$formats[$detailedFormatsLabel][$format->format_id] = implode(' ', $formatParts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->view->render(
|
$this->view->render(
|
||||||
$response,
|
$response,
|
||||||
$template,
|
$template,
|
||||||
|
@ -185,6 +231,7 @@ class FrontController extends BaseController
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
'defaultFormat' => $this->defaultFormat,
|
'defaultFormat' => $this->defaultFormat,
|
||||||
|
'formats' => $formats
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -302,4 +349,24 @@ class FrontController extends BaseController
|
||||||
return $this->displayError($request, $response, $message);
|
return $this->displayError($request, $response, $message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Route that mimics YouTube video URLs ("/watch?v=foo")
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Response $response
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function watch(Request $request, Response $response): Response
|
||||||
|
{
|
||||||
|
// We build a full YouTube URL from the video ID.
|
||||||
|
$youtubeUri = Uri::createFromString('https://www.youtube.com/watch')
|
||||||
|
->withQuery(http_build_query(['v' => $request->getQueryParam('v')]));
|
||||||
|
|
||||||
|
// Then pass it to the info route.
|
||||||
|
return $response->withRedirect(
|
||||||
|
Uri::createFromString($this->router->pathFor('info'))
|
||||||
|
->withQuery(http_build_query(['url' => strval($youtubeUri)]))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
namespace Alltube\Controller;
|
namespace Alltube\Controller;
|
||||||
|
|
||||||
use Alltube\Library\Exception\AlltubeLibraryException;
|
use Alltube\Library\Exception\AlltubeLibraryException;
|
||||||
use Exception;
|
|
||||||
use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException;
|
use Graby\HttpClient\Plugin\ServerSideRequestForgeryProtection\Exception\InvalidURLException;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
use Slim\Http\Response;
|
use Slim\Http\Response;
|
||||||
|
@ -25,6 +24,7 @@ class JsonController extends BaseController
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
|
* @throws AlltubeLibraryException
|
||||||
*/
|
*/
|
||||||
public function json(Request $request, Response $response): Response
|
public function json(Request $request, Response $response): Response
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Alltube;
|
namespace Alltube;
|
||||||
|
|
||||||
|
use Slim\Http\StatusCode;
|
||||||
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
|
@ -17,7 +18,7 @@ class ErrorHandler
|
||||||
* @param Throwable $e
|
* @param Throwable $e
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function handle(Throwable $e)
|
public static function handle(Throwable $e): void
|
||||||
{
|
{
|
||||||
error_log($e);
|
error_log($e);
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ class ErrorHandler
|
||||||
http_response_code($exception->getStatusCode());
|
http_response_code($exception->getStatusCode());
|
||||||
die($exception->getAsString());
|
die($exception->getAsString());
|
||||||
} else {
|
} else {
|
||||||
http_response_code(500);
|
http_response_code(StatusCode::HTTP_INTERNAL_SERVER_ERROR);
|
||||||
die('Error when starting the app: ' . htmlentities($e->getMessage()));
|
die('Error when starting the app: ' . htmlentities($e->getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace Alltube\Factory;
|
||||||
|
|
||||||
use Alltube\Exception\DependencyException;
|
use Alltube\Exception\DependencyException;
|
||||||
use Alltube\LocaleManager;
|
use Alltube\LocaleManager;
|
||||||
|
use Locale;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +21,7 @@ class LocaleManagerFactory
|
||||||
*/
|
*/
|
||||||
public static function create(Container $container): LocaleManager
|
public static function create(Container $container): LocaleManager
|
||||||
{
|
{
|
||||||
if (!class_exists('Locale')) {
|
if (!class_exists(Locale::class)) {
|
||||||
throw new DependencyException('You need to install the intl extension for PHP.');
|
throw new DependencyException('You need to install the intl extension for PHP.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Consolidation\Log\LoggerManager;
|
||||||
use Consolidation\Log\LogOutputStyler;
|
use Consolidation\Log\LogOutputStyler;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LoggerFactory
|
* Class LoggerFactory
|
||||||
|
@ -23,9 +24,9 @@ class LoggerFactory
|
||||||
{
|
{
|
||||||
$config = $container->get('config');
|
$config = $container->get('config');
|
||||||
if ($config->debug) {
|
if ($config->debug) {
|
||||||
$verbosity = ConsoleOutput::VERBOSITY_DEBUG;
|
$verbosity = OutputInterface::VERBOSITY_DEBUG;
|
||||||
} else {
|
} else {
|
||||||
$verbosity = ConsoleOutput::VERBOSITY_NORMAL;
|
$verbosity = OutputInterface::VERBOSITY_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
$loggerManager = new LoggerManager();
|
$loggerManager = new LoggerManager();
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
namespace Alltube\Factory;
|
namespace Alltube\Factory;
|
||||||
|
|
||||||
use Aura\Session\Session;
|
use Aura\Session\Session;
|
||||||
|
use Aura\Session\SessionFactory as AuraSessionFactory;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +24,7 @@ class SessionFactory
|
||||||
*/
|
*/
|
||||||
public static function create(Container $container): Session
|
public static function create(Container $container): Session
|
||||||
{
|
{
|
||||||
$session_factory = new \Aura\Session\SessionFactory();
|
$session_factory = new AuraSessionFactory();
|
||||||
$session = $session_factory->newInstance($_COOKIE);
|
$session = $session_factory->newInstance($_COOKIE);
|
||||||
|
|
||||||
$session->setCookieParams(['httponly' => true]);
|
$session->setCookieParams(['httponly' => true]);
|
||||||
|
|
|
@ -20,22 +20,6 @@ use SmartyException;
|
||||||
*/
|
*/
|
||||||
class ViewFactory
|
class ViewFactory
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Generate the canonical URL of the current page.
|
|
||||||
*
|
|
||||||
* @param Request $request PSR-7 Request
|
|
||||||
*
|
|
||||||
* @return string URL
|
|
||||||
*/
|
|
||||||
private static function getCanonicalUrl(Request $request): string
|
|
||||||
{
|
|
||||||
/** @var Uri $uri */
|
|
||||||
$uri = $request->getUri();
|
|
||||||
|
|
||||||
return $uri->withBasePath('')
|
|
||||||
->withHost('alltubedownload.net')
|
|
||||||
->withScheme('https');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Uri $uri
|
* @param Uri $uri
|
||||||
|
@ -66,22 +50,13 @@ class ViewFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Smarty view object.
|
* Create a URI suitable for templates.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container Slim dependency container
|
* @param Request $request
|
||||||
* @param Request|null $request PSR-7 request
|
* @return Uri
|
||||||
*
|
|
||||||
* @return Smarty
|
|
||||||
* @throws SmartyException
|
|
||||||
*/
|
*/
|
||||||
public static function create(ContainerInterface $container, Request $request = null): Smarty
|
public static function prepareUri(Request $request): Uri
|
||||||
{
|
{
|
||||||
if (!isset($request)) {
|
|
||||||
$request = $container->get('request');
|
|
||||||
}
|
|
||||||
|
|
||||||
$view = new Smarty($container->get('root_path') . '/templates/');
|
|
||||||
|
|
||||||
/** @var Uri $uri */
|
/** @var Uri $uri */
|
||||||
$uri = $request->getUri();
|
$uri = $request->getUri();
|
||||||
if (in_array('https', $request->getHeader('X-Forwarded-Proto'))) {
|
if (in_array('https', $request->getHeader('X-Forwarded-Proto'))) {
|
||||||
|
@ -101,25 +76,45 @@ class ViewFactory
|
||||||
$uri = $uri->withBasePath($path);
|
$uri = $uri->withBasePath($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return self::cleanBasePath($uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create Smarty view object.
|
||||||
|
*
|
||||||
|
* @param ContainerInterface $container Slim dependency container
|
||||||
|
* @param Request|null $request PSR-7 request
|
||||||
|
*
|
||||||
|
* @return Smarty
|
||||||
|
* @throws SmartyException
|
||||||
|
*/
|
||||||
|
public static function create(ContainerInterface $container, Request $request = null): Smarty
|
||||||
|
{
|
||||||
|
if (!isset($request)) {
|
||||||
|
$request = $container->get('request');
|
||||||
|
}
|
||||||
|
|
||||||
|
$view = new Smarty($container->get('root_path') . '/templates/');
|
||||||
|
|
||||||
|
$uri = self::prepareUri($request);
|
||||||
|
|
||||||
/** @var LocaleManager $localeManager */
|
/** @var LocaleManager $localeManager */
|
||||||
$localeManager = $container->get('locale');
|
$localeManager = $container->get('locale');
|
||||||
|
|
||||||
$uri = self::cleanBasePath($uri);
|
|
||||||
|
|
||||||
$smartyPlugins = new SmartyPlugins($container->get('router'), $uri->withUserInfo(''));
|
$smartyPlugins = new SmartyPlugins($container->get('router'), $uri->withUserInfo(''));
|
||||||
$view->registerPlugin('function', 'path_for', [$smartyPlugins, 'pathFor']);
|
$view->registerPlugin('function', 'path_for', [$smartyPlugins, 'pathFor']);
|
||||||
$view->registerPlugin('function', 'base_url', [$smartyPlugins, 'baseUrl']);
|
$view->registerPlugin('function', 'base_url', [$smartyPlugins, 'baseUrl']);
|
||||||
$view->registerPlugin('block', 't', [$localeManager, 'smartyTranslate']);
|
$view->registerPlugin('block', 't', [$localeManager, 'smartyTranslate']);
|
||||||
|
|
||||||
$view->offsetSet('canonical', self::getCanonicalUrl($request));
|
|
||||||
$view->offsetSet('locale', $container->get('locale'));
|
$view->offsetSet('locale', $container->get('locale'));
|
||||||
$view->offsetSet('config', $container->get('config'));
|
$view->offsetSet('config', $container->get('config'));
|
||||||
$view->offsetSet('domain', $uri->withBasePath('')->getBaseUrl());
|
$view->offsetSet('domain', $uri->withBasePath('')->getBaseUrl());
|
||||||
|
|
||||||
if ($container->has('debugbar')) {
|
if ($container->has('debugbar')) {
|
||||||
$debugBar = $container->get('debugbar');
|
$debugBar = $container->get('debugbar');
|
||||||
|
$collector = new SmartyCollector($view->getSmarty());
|
||||||
$debugBar->addCollector(new SmartyCollector($view->getSmarty()));
|
$collector->useHtmlVarDumper();
|
||||||
|
$debugBar->addCollector($collector);
|
||||||
|
|
||||||
$view->offsetSet(
|
$view->offsetSet(
|
||||||
'debug_render',
|
'debug_render',
|
||||||
|
|
|
@ -114,7 +114,7 @@ class LocaleManager
|
||||||
* @param Locale $locale Locale
|
* @param Locale $locale Locale
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setLocale(Locale $locale)
|
public function setLocale(Locale $locale): void
|
||||||
{
|
{
|
||||||
$this->translator->setLocale($locale->getIso15897());
|
$this->translator->setLocale($locale->getIso15897());
|
||||||
$this->curLocale = $locale;
|
$this->curLocale = $locale;
|
||||||
|
@ -125,7 +125,7 @@ class LocaleManager
|
||||||
* Unset the current locale.
|
* Unset the current locale.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function unsetLocale()
|
public function unsetLocale(): void
|
||||||
{
|
{
|
||||||
$this->translator->setLocale(self::DEFAULT_LOCALE);
|
$this->translator->setLocale(self::DEFAULT_LOCALE);
|
||||||
$this->curLocale = null;
|
$this->curLocale = null;
|
||||||
|
@ -135,14 +135,14 @@ class LocaleManager
|
||||||
/**
|
/**
|
||||||
* Smarty "t" block.
|
* Smarty "t" block.
|
||||||
*
|
*
|
||||||
* @param mixed[] $params Block parameters
|
* @param string[]|string[][] $params Block parameters
|
||||||
* @param string|null $text Block content
|
* @param string|null $text Block content
|
||||||
*
|
*
|
||||||
* @return string Translated string
|
* @return string Translated string
|
||||||
*/
|
*/
|
||||||
public function smartyTranslate(array $params, string $text = null): string
|
public function smartyTranslate(array $params, string $text = null): string
|
||||||
{
|
{
|
||||||
if (isset($params['params'])) {
|
if (isset($params['params']) && is_array($params['params'])) {
|
||||||
return $this->t($text, $params['params']);
|
return $this->t($text, $params['params']);
|
||||||
} else {
|
} else {
|
||||||
return $this->t($text);
|
return $this->t($text);
|
||||||
|
@ -154,7 +154,7 @@ class LocaleManager
|
||||||
*
|
*
|
||||||
* @param string|null $string $string String to translate
|
* @param string|null $string $string String to translate
|
||||||
*
|
*
|
||||||
* @param mixed[] $params
|
* @param string[] $params
|
||||||
* @return string Translated string
|
* @return string Translated string
|
||||||
*/
|
*/
|
||||||
public function t(string $string = null, array $params = []): string
|
public function t(string $string = null, array $params = []): string
|
||||||
|
|
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
namespace Alltube\Middleware;
|
namespace Alltube\Middleware;
|
||||||
|
|
||||||
use Psr\Container\ContainerInterface;
|
use Alltube\Factory\ViewFactory;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
use Slim\Http\Response;
|
use Slim\Http\Response;
|
||||||
use Slim\Router;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class LinkHeaderMiddleware
|
* Class LinkHeaderMiddleware
|
||||||
|
@ -13,19 +12,6 @@ use Slim\Router;
|
||||||
*/
|
*/
|
||||||
class LinkHeaderMiddleware
|
class LinkHeaderMiddleware
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* @var Router
|
|
||||||
*/
|
|
||||||
private $router;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LinkHeaderMiddleware constructor.
|
|
||||||
* @param ContainerInterface $container
|
|
||||||
*/
|
|
||||||
public function __construct(ContainerInterface $container)
|
|
||||||
{
|
|
||||||
$this->router = $container->get('router');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
|
@ -35,12 +21,19 @@ class LinkHeaderMiddleware
|
||||||
*/
|
*/
|
||||||
public function __invoke(Request $request, Response $response, callable $next)
|
public function __invoke(Request $request, Response $response, callable $next)
|
||||||
{
|
{
|
||||||
|
$uri = ViewFactory::prepareUri($request);
|
||||||
|
|
||||||
$response = $response->withHeader(
|
$response = $response->withHeader(
|
||||||
'Link',
|
'Link',
|
||||||
'<' . $this->router->getBasePath() . '/css/style.css>; rel=preload; as=style'
|
implode(
|
||||||
|
'; ',
|
||||||
|
[
|
||||||
|
'<' . $uri->getBasePath() . '/css/style.css>',
|
||||||
|
'rel=preload', 'as=style'
|
||||||
|
]
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
return $next($request, $response);
|
return $next($request, $response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class LocaleMiddleware
|
||||||
/**
|
/**
|
||||||
* Test if a locale can be used for the current user.
|
* Test if a locale can be used for the current user.
|
||||||
*
|
*
|
||||||
* @param mixed[] $proposedLocale Locale array created by AcceptLanguage::parse()
|
* @param string[] $proposedLocale Locale array created by AcceptLanguage::parse()
|
||||||
*
|
*
|
||||||
* @return Locale|null Locale if chosen, nothing otherwise
|
* @return Locale|null Locale if chosen, nothing otherwise
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -31,7 +31,7 @@ class ReleaseCommand extends Tasks
|
||||||
|
|
||||||
$tmpDir = $this->_tmpDir();
|
$tmpDir = $this->_tmpDir();
|
||||||
|
|
||||||
$filename = 'alltube-' . trim((string)$result->getMessage()) . '.zip';
|
$filename = 'alltube-' . trim($result->getMessage()) . '.zip';
|
||||||
|
|
||||||
/** @var FilesystemStack $rmTask */
|
/** @var FilesystemStack $rmTask */
|
||||||
$rmTask = $this->taskFilesystemStack();
|
$rmTask = $this->taskFilesystemStack();
|
||||||
|
|
|
@ -23,7 +23,7 @@ class ConvertedPlaylistArchiveStream extends PlaylistArchiveStream
|
||||||
* @return void
|
* @return void
|
||||||
* @throws AlltubeLibraryException
|
* @throws AlltubeLibraryException
|
||||||
*/
|
*/
|
||||||
protected function startVideoStream(Video $video)
|
protected function startVideoStream(Video $video): void
|
||||||
{
|
{
|
||||||
$this->curVideoStream = new Stream($this->downloader->getAudioStream($video));
|
$this->curVideoStream = new Stream($this->downloader->getAudioStream($video));
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ class PlaylistArchiveStream extends ZipArchive implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function send($data)
|
protected function send($data): void
|
||||||
{
|
{
|
||||||
$pos = $this->tell();
|
$pos = $this->tell();
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ class PlaylistArchiveStream extends ZipArchive implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function rewind()
|
public function rewind(): void
|
||||||
{
|
{
|
||||||
rewind($this->buffer);
|
rewind($this->buffer);
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ class PlaylistArchiveStream extends ZipArchive implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
public function seek($offset, $whence = SEEK_SET): void
|
||||||
{
|
{
|
||||||
fseek($this->buffer, $offset, $whence);
|
fseek($this->buffer, $offset, $whence);
|
||||||
}
|
}
|
||||||
|
@ -256,7 +256,7 @@ class PlaylistArchiveStream extends ZipArchive implements StreamInterface
|
||||||
* @return void
|
* @return void
|
||||||
* @throws AlltubeLibraryException
|
* @throws AlltubeLibraryException
|
||||||
*/
|
*/
|
||||||
protected function startVideoStream(Video $video)
|
protected function startVideoStream(Video $video): void
|
||||||
{
|
{
|
||||||
$response = $this->downloader->getHttpResponse($video);
|
$response = $this->downloader->getHttpResponse($video);
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ class PlaylistArchiveStream extends ZipArchive implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function close()
|
public function close(): void
|
||||||
{
|
{
|
||||||
if (is_resource($this->buffer)) {
|
if (is_resource($this->buffer)) {
|
||||||
fclose($this->buffer);
|
fclose($this->buffer);
|
||||||
|
|
|
@ -63,7 +63,7 @@ class YoutubeChunkStream implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function close()
|
public function close(): void
|
||||||
{
|
{
|
||||||
$this->response->getBody()->close();
|
$this->response->getBody()->close();
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ class YoutubeChunkStream implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
public function seek($offset, $whence = SEEK_SET): void
|
||||||
{
|
{
|
||||||
$this->response->getBody()->seek($offset, $whence);
|
$this->response->getBody()->seek($offset, $whence);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +136,7 @@ class YoutubeChunkStream implements StreamInterface
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function rewind()
|
public function rewind(): void
|
||||||
{
|
{
|
||||||
$this->response->getBody()->rewind();
|
$this->response->getBody()->rewind();
|
||||||
}
|
}
|
||||||
|
@ -156,9 +156,9 @@ class YoutubeChunkStream implements StreamInterface
|
||||||
*
|
*
|
||||||
* @param mixed $string The string that is to be written
|
* @param mixed $string The string that is to be written
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function write($string)
|
public function write($string): int
|
||||||
{
|
{
|
||||||
return $this->response->getBody()->write($string);
|
return $this->response->getBody()->write($string);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ class UglyRouter extends Router
|
||||||
*
|
*
|
||||||
* @param ServerRequestInterface $request The current HTTP request object
|
* @param ServerRequestInterface $request The current HTTP request object
|
||||||
*
|
*
|
||||||
* @return mixed[]
|
* @return int[]|string[]|array[]
|
||||||
*
|
*
|
||||||
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
|
* @link https://github.com/nikic/FastRoute/blob/master/src/Dispatcher.php
|
||||||
*/
|
*/
|
||||||
|
@ -55,7 +55,7 @@ class UglyRouter extends Router
|
||||||
*/
|
*/
|
||||||
public function pathFor($name, array $data = [], array $queryParams = []): string
|
public function pathFor($name, array $data = [], array $queryParams = []): string
|
||||||
{
|
{
|
||||||
$queryParams['page'] = $name;
|
$queryParams['page'] = $this->relativePathFor($name, $data);
|
||||||
$url = Uri::createFromString($this->relativePathFor($name, $data, $queryParams))->withPath('');
|
$url = Uri::createFromString($this->relativePathFor($name, $data, $queryParams))->withPath('');
|
||||||
|
|
||||||
if ($this->basePath) {
|
if ($this->basePath) {
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "rudloff/alltube",
|
"name": "rudloff/alltube",
|
||||||
"type": "project",
|
|
||||||
"description": "HTML GUI for youtube-dl",
|
"description": "HTML GUI for youtube-dl",
|
||||||
"homepage": "http://alltubedownload.net/",
|
|
||||||
"license": "GPL-3.0-only",
|
"license": "GPL-3.0-only",
|
||||||
|
"type": "project",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Pierre Rudloff",
|
"name": "Pierre Rudloff",
|
||||||
|
@ -14,7 +13,7 @@
|
||||||
{
|
{
|
||||||
"name": "Olivier Haquette",
|
"name": "Olivier Haquette",
|
||||||
"email": "contact@olivierhaquette.fr",
|
"email": "contact@olivierhaquette.fr",
|
||||||
"homepage": "http://olivierhaquette.fr/",
|
"homepage": "https://ographik.fr/",
|
||||||
"role": "Designer"
|
"role": "Designer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -29,22 +28,22 @@
|
||||||
"j0k3r/httplug-ssrf-plugin": "^2.0",
|
"j0k3r/httplug-ssrf-plugin": "^2.0",
|
||||||
"jawira/case-converter": "^3.4",
|
"jawira/case-converter": "^3.4",
|
||||||
"jean85/pretty-package-versions": "^1.3",
|
"jean85/pretty-package-versions": "^1.3",
|
||||||
"mathmarques/smarty-view": "^1.1",
|
"mathmarques/smarty-view": "^1.2",
|
||||||
"oomphinc/composer-installers-extender": "^2.0",
|
"oomphinc/composer-installers-extender": "^2.0",
|
||||||
"paragonie/csp-builder": "^2.5",
|
"paragonie/csp-builder": "^2.5",
|
||||||
"rinvex/countries": "^6.1",
|
"rinvex/countries": "^6.1",
|
||||||
"rudloff/alltube-library": "^0.1.1",
|
"rudloff/alltube-library": "^0.1.3",
|
||||||
"symfony/finder": "^5.0",
|
"symfony/finder": "^5.4",
|
||||||
"symfony/translation": "^4.0",
|
"symfony/translation": "^4.0",
|
||||||
"symfony/yaml": "^4.0",
|
"symfony/yaml": "^4.0",
|
||||||
"webfontkit/open-sans": "^1.0",
|
"webfontkit/open-sans": "^1.0",
|
||||||
"ytdl-org/youtube-dl": "^2021.04",
|
"ytdl-org/youtube-dl": "^2021.12",
|
||||||
"zonuexe/http-accept-language": "^0.4.1"
|
"zonuexe/http-accept-language": "^0.4.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"consolidation/robo": "^2.1",
|
"consolidation/robo": "^2.1",
|
||||||
"enlightn/security-checker": "^1.4",
|
"enlightn/security-checker": "^1.4",
|
||||||
"ergebnis/composer-normalize": "^2.6",
|
"ergebnis/composer-normalize": "^2.20",
|
||||||
"insite/composer-dangling-locked-deps": "^0.2.1",
|
"insite/composer-dangling-locked-deps": "^0.2.1",
|
||||||
"junker/debugbar-smarty": "^0.1.0",
|
"junker/debugbar-smarty": "^0.1.0",
|
||||||
"kitchenu/slim-debugbar": "^1.1",
|
"kitchenu/slim-debugbar": "^1.1",
|
||||||
|
@ -52,13 +51,45 @@
|
||||||
"php-mock/php-mock-mockery": "^1.3",
|
"php-mock/php-mock-mockery": "^1.3",
|
||||||
"phpro/grumphp": "^1.3",
|
"phpro/grumphp": "^1.3",
|
||||||
"phpstan/phpstan": "^0.12.72",
|
"phpstan/phpstan": "^0.12.72",
|
||||||
"phpunit/phpunit": "^8.4",
|
"phpunit/phpunit": "^9.5",
|
||||||
|
"povils/phpmnd": "^2.5",
|
||||||
"smarty-gettext/smarty-gettext": "^1.6",
|
"smarty-gettext/smarty-gettext": "^1.6",
|
||||||
"squizlabs/php_codesniffer": "^3.5",
|
"squizlabs/php_codesniffer": "^3.5",
|
||||||
"symfony/error-handler": "^5.0",
|
"symfony/error-handler": "^5.4",
|
||||||
"symfony/var-dumper": "^5.0"
|
"symfony/var-dumper": "^5.4"
|
||||||
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "ytdl-org/youtube-dl",
|
||||||
|
"version": "2021.12.17",
|
||||||
|
"dist": {
|
||||||
|
"type": "tar",
|
||||||
|
"url": "https://yt-dl.org/downloads/2021.12.17/youtube-dl-2021.12.17.tar.gz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Alltube\\": "classes/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Alltube\\Test\\": "tests/"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"composer/installers": true,
|
||||||
|
"cweagans/composer-patches": true,
|
||||||
|
"ergebnis/composer-normalize": true,
|
||||||
|
"insite/composer-dangling-locked-deps": true,
|
||||||
|
"oomphinc/composer-installers-extender": true,
|
||||||
|
"phpro/grumphp": true
|
||||||
|
},
|
||||||
"platform": {
|
"platform": {
|
||||||
"php": "7.3.11"
|
"php": "7.3.11"
|
||||||
},
|
},
|
||||||
|
@ -82,29 +113,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Alltube\\": "classes/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"Alltube\\Test\\": "tests/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"repositories": [
|
|
||||||
{
|
|
||||||
"type": "package",
|
|
||||||
"package": {
|
|
||||||
"name": "ytdl-org/youtube-dl",
|
|
||||||
"version": "2021.04.01",
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://github.com/ytdl-org/youtube-dl/archive/2021.04.01.zip"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "grumphp run --ansi",
|
"lint": "grumphp run --ansi",
|
||||||
"release": "robo release --ansi",
|
"release": "robo release --ansi",
|
||||||
|
|
2128
composer.lock
generated
2128
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -255,7 +255,7 @@ footer a:hover {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
width: 622px;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mp3-inner {
|
.mp3-inner {
|
||||||
|
@ -545,6 +545,7 @@ h1 {
|
||||||
|
|
||||||
.thumb {
|
.thumb {
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.format {
|
.format {
|
||||||
|
|
|
@ -13,6 +13,7 @@ grumphp:
|
||||||
securitychecker_enlightn: ~
|
securitychecker_enlightn: ~
|
||||||
composer_normalize: ~
|
composer_normalize: ~
|
||||||
composer_dangling_locked_deps: ~
|
composer_dangling_locked_deps: ~
|
||||||
|
phpmnd: ~
|
||||||
phpcs:
|
phpcs:
|
||||||
standard: PSR12
|
standard: PSR12
|
||||||
phpstan:
|
phpstan:
|
||||||
|
|
|
@ -98,7 +98,7 @@ msgid "Share on Facebook"
|
||||||
msgstr "شاركها على فيسبوك"
|
msgstr "شاركها على فيسبوك"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "انسخ هنا رابط الفيديو (يوتيوب، انستقرام، وغيرها)"
|
msgstr "انسخ هنا رابط الفيديو (يوتيوب، انستقرام، وغيرها)"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
|
|
|
@ -131,8 +131,8 @@ msgid "Video password"
|
||||||
msgstr "Videopasswort"
|
msgstr "Videopasswort"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Kopiere hier die URL deines Videos (Youtube, Dailymotion, etc.) hinein"
|
msgstr "Kopiere hier die URL deines Videos (YouTube, Dailymotion, etc.) hinein"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -106,8 +106,8 @@ msgid "Share on Facebook"
|
||||||
msgstr "Compartir en Facebook"
|
msgstr "Compartir en Facebook"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Copia aquí la URL de tu vídeo (Youtube, Dailymotion, etc.)"
|
msgstr "Copia aquí la URL de tu vídeo (YouTube, Dailymotion, etc.)"
|
||||||
|
|
||||||
#: templates/index.tpl:23
|
#: templates/index.tpl:23
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -59,8 +59,8 @@ msgid "Video password"
|
||||||
msgstr "Password del video"
|
msgstr "Password del video"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Copia qui l'URL del video (Youtube, Dailymotion, ecc.)"
|
msgstr "Copia qui l'URL del video (YouTube, Dailymotion, ecc.)"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -134,7 +134,7 @@ msgstr "閲覧用パスワード"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "動画のリンク(URL)を入力欄に入力してください。(例:Youtube,Dailymotion等。)"
|
msgstr "動画のリンク(URL)を入力欄に入力してください。(例:YouTube,Dailymotion等。)"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -71,8 +71,8 @@ msgid "Video password"
|
||||||
msgstr "Hasło do wideo"
|
msgstr "Hasło do wideo"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Zamieść link do wideo (Yotube, Dailymotion, itp.)"
|
msgstr "Zamieść link do wideo (YouTube, Dailymotion, itp.)"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -106,8 +106,8 @@ msgid "Share on Facebook"
|
||||||
msgstr "Compartilhe no Facebook"
|
msgstr "Compartilhe no Facebook"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Cole aqui a URL do vídeo (Youtube, Dailymotion, etc.)"
|
msgstr "Cole aqui a URL do vídeo (YouTube, Dailymotion, etc.)"
|
||||||
|
|
||||||
#: templates/index.tpl:24
|
#: templates/index.tpl:24
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -65,8 +65,8 @@ msgid "Video password"
|
||||||
msgstr "Video parolası"
|
msgstr "Video parolası"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/index.tpl:8
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
msgstr "Videonuzun URL'sini buraya kopyalayın (Youtube, Dailymotion, vb.)"
|
msgstr "Videonuzun URL'sini buraya kopyalayın (YouTube, Dailymotion, vb.)"
|
||||||
|
|
||||||
#: templates/index.tpl:25
|
#: templates/index.tpl:25
|
||||||
msgid "Audio only (MP3)"
|
msgid "Audio only (MP3)"
|
||||||
|
|
|
@ -1,134 +1,227 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"MIME-Version: 1.0\n"
|
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
|
||||||
"X-Generator: POEditor.com\n"
|
|
||||||
"Project-Id-Version: AllTube Download\n"
|
|
||||||
"Language: zh-CN\n"
|
|
||||||
|
|
||||||
#: templates/error.tpl:6
|
#: templates/inc/footer.tpl:8
|
||||||
msgid "Please check the URL of your video."
|
msgid "Code by @dev"
|
||||||
msgstr "请检查您的视频的 URL。"
|
msgstr "由 @dev 开发"
|
||||||
|
|
||||||
#: 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:83
|
|
||||||
#: templates/video.tpl:86 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:24
|
|
||||||
msgid "Available formats:"
|
|
||||||
msgstr "可用的格式︰"
|
|
||||||
|
|
||||||
#: templates/video.tpl:29
|
|
||||||
msgid "Generic formats"
|
|
||||||
msgstr "通用格式"
|
|
||||||
|
|
||||||
#: templates/video.tpl:32
|
|
||||||
msgid "Best"
|
|
||||||
msgstr "最佳"
|
|
||||||
|
|
||||||
#: templates/video.tpl:37
|
|
||||||
msgid "Remux best video with best audio"
|
|
||||||
msgstr "重新封装最佳视频与最佳音频"
|
|
||||||
|
|
||||||
#: templates/video.tpl:41
|
|
||||||
msgid "Worst"
|
|
||||||
msgstr "最差"
|
|
||||||
|
|
||||||
#: templates/video.tpl:44
|
|
||||||
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 "去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
|
#: templates/inc/footer.tpl:16
|
||||||
msgid "Based on"
|
msgid "Design by @designer"
|
||||||
msgstr "基于"
|
msgstr "由 @designer 设计"
|
||||||
|
|
||||||
#: templates/inc/header.tpl:21
|
#: templates/inc/footer.tpl:21
|
||||||
msgid "Share on Twitter"
|
msgid "Get the code"
|
||||||
msgstr "分享到 Twitter"
|
msgstr "获取源代码"
|
||||||
|
|
||||||
#: templates/inc/header.tpl:23
|
#: templates/inc/footer.tpl:29
|
||||||
msgid "Share on Facebook"
|
msgid "Based on @youtubedl"
|
||||||
msgstr "分享到 Facebook"
|
msgstr "基于 @youtubedl"
|
||||||
|
|
||||||
#: templates/index.tpl:8
|
#: templates/inc/footer.tpl:33
|
||||||
msgid "Copy here the URL of your video (Youtube, Dailymotion, etc.)"
|
msgid "Donate using Liberapay"
|
||||||
msgstr "在这里复制您的视频 (Youtube、 Dailymotion 等) 的 URL"
|
msgstr "使用 Liberapay 捐赠"
|
||||||
|
|
||||||
#: templates/index.tpl:23
|
#: templates/inc/footer.tpl:35
|
||||||
msgid "Audio only (MP3)"
|
msgid "Donate"
|
||||||
msgstr "仅限音频(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 "书签工具"
|
|
||||||
|
|
||||||
#: templates/inc/header.tpl:4
|
#: templates/inc/header.tpl:4
|
||||||
msgid "Switch language"
|
msgid "Switch language"
|
||||||
msgstr "切换语言"
|
msgstr "切换语言"
|
||||||
|
|
||||||
|
#: templates/inc/header.tpl:8
|
||||||
|
msgid "Set language"
|
||||||
|
msgstr "设置语言"
|
||||||
|
|
||||||
|
#: templates/info.tpl:11
|
||||||
|
msgid "You are going to download @title."
|
||||||
|
msgstr "您将要下载 @title。"
|
||||||
|
|
||||||
|
#: templates/info.tpl:29
|
||||||
|
msgid "Available formats:"
|
||||||
|
msgstr "可用的格式:"
|
||||||
|
|
||||||
|
#: templates/info.tpl:31
|
||||||
|
msgid "Generic formats"
|
||||||
|
msgstr "通用格式"
|
||||||
|
|
||||||
|
#: templates/info.tpl:35
|
||||||
|
msgid "Best"
|
||||||
|
msgstr "最佳"
|
||||||
|
|
||||||
|
#: templates/info.tpl:36
|
||||||
|
msgid "Remux best video with best audio"
|
||||||
|
msgstr "重新封装最佳视频和最佳音频"
|
||||||
|
|
||||||
|
#: templates/info.tpl:37
|
||||||
|
msgid "Worst"
|
||||||
|
msgstr "最差"
|
||||||
|
|
||||||
|
#: templates/info.tpl:42
|
||||||
|
msgid "Detailed formats"
|
||||||
|
msgstr "详细格式"
|
||||||
|
|
||||||
|
#: templates/info.tpl:86
|
||||||
|
msgid "Stream the video through the server"
|
||||||
|
msgstr "通过服务器传输视频"
|
||||||
|
|
||||||
|
#: templates/info.tpl:92
|
||||||
|
msgid "Convert into a custom format:"
|
||||||
|
msgstr "转换为自定义格式:"
|
||||||
|
|
||||||
|
#: templates/info.tpl:93
|
||||||
|
msgid "Custom format"
|
||||||
|
msgstr "自定义格式"
|
||||||
|
|
||||||
|
#: templates/info.tpl:93
|
||||||
|
msgid "Format to convert to"
|
||||||
|
msgstr "要转换到的格式"
|
||||||
|
|
||||||
|
#: templates/info.tpl:98
|
||||||
|
# Other translators: Please check that file for context
|
||||||
|
msgid "with"
|
||||||
|
msgstr ",并带"
|
||||||
|
|
||||||
|
#: templates/info.tpl:99
|
||||||
|
msgid "Bit rate"
|
||||||
|
msgstr "比特率"
|
||||||
|
|
||||||
|
#: templates/info.tpl:100
|
||||||
|
msgid "Custom bitrate"
|
||||||
|
msgstr "自定义比特率"
|
||||||
|
|
||||||
|
#: templates/info.tpl:103
|
||||||
|
msgid "kbit/s audio"
|
||||||
|
msgstr "kbit/s 的音频"
|
||||||
|
|
||||||
|
#: templates/info.tpl:107 templates/playlist.tpl:38 templates/password.tpl:11
|
||||||
|
#: templates/index.tpl:19
|
||||||
|
msgid "Download"
|
||||||
|
msgstr "下载"
|
||||||
|
|
||||||
|
#: templates/playlist.tpl:12
|
||||||
|
msgid "Videos extracted from @title:"
|
||||||
|
msgstr "从 @title 中提取的视频:"
|
||||||
|
|
||||||
|
#: templates/playlist.tpl:39
|
||||||
|
msgid "More options"
|
||||||
|
msgstr "更多选项"
|
||||||
|
|
||||||
|
#: templates/extractors.tpl:4 classes/Controller/FrontController.php:111
|
||||||
|
msgid "Supported websites"
|
||||||
|
msgstr "支持的网站"
|
||||||
|
|
||||||
#: templates/error.tpl:5
|
#: templates/error.tpl:5
|
||||||
msgid "An error occurred"
|
msgid "An error occurred"
|
||||||
msgstr "出错了"
|
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/index.tpl:8
|
||||||
|
# I don't think this needs to be a 100% match
|
||||||
|
msgid "Copy here the URL of your video (YouTube, Dailymotion, etc.)"
|
||||||
|
msgstr "在此处粘贴视频网址"
|
||||||
|
|
||||||
|
#: templates/index.tpl:25
|
||||||
|
msgid "Audio only (MP3)"
|
||||||
|
msgstr "仅音频(MP3)"
|
||||||
|
|
||||||
|
#: templates/index.tpl:29
|
||||||
|
# Still check that file for context
|
||||||
|
msgid "From"
|
||||||
|
msgstr "从"
|
||||||
|
|
||||||
|
#: templates/index.tpl:32
|
||||||
|
msgid "to"
|
||||||
|
msgstr "到"
|
||||||
|
|
||||||
|
#: templates/index.tpl:41
|
||||||
|
msgid "See all supported websites"
|
||||||
|
msgstr "查看所有支持的网站"
|
||||||
|
|
||||||
|
#: templates/index.tpl:43
|
||||||
|
msgid "Drag this to your bookmarks bar:"
|
||||||
|
msgstr "您可以把这个书签工具拖到您的书签栏中:"
|
||||||
|
|
||||||
|
#: templates/index.tpl:45
|
||||||
|
msgid "Bookmarklet"
|
||||||
|
msgstr "书签工具"
|
||||||
|
|
||||||
|
#: classes/Controller/DownloadController.php:64
|
||||||
|
#: classes/Controller/FrontController.php:166
|
||||||
|
msgid "Wrong password"
|
||||||
|
msgstr "密码错误"
|
||||||
|
|
||||||
|
#: classes/Controller/DownloadController.php:69
|
||||||
|
msgid "Conversion of playlists is not supported."
|
||||||
|
msgstr "不支持转换播放列表。"
|
||||||
|
|
||||||
|
#: classes/Controller/DownloadController.php:76
|
||||||
|
msgid "Conversion of M3U8 files is not supported."
|
||||||
|
msgstr "不支持转换 M3U8 文件。"
|
||||||
|
|
||||||
|
#: classes/Controller/DownloadController.php:82
|
||||||
|
# ref. Chinese Wikipedia article about DASH
|
||||||
|
msgid "Conversion of DASH segments is not supported."
|
||||||
|
msgstr "不支持转换 DASH 片段。"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:65
|
||||||
|
msgid ""
|
||||||
|
"Easily download videos from YouTube, Dailymotion, Vimeo and other websites."
|
||||||
|
msgstr ""
|
||||||
|
"轻松从 YouTube、Dailymotion、Vimeo 等网站下载视频。"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:112
|
||||||
|
# NOTE: DON'T translate AllTube Download
|
||||||
|
msgid ""
|
||||||
|
"List of all supported websites from which AllTube Download can extract video "
|
||||||
|
"or audio files"
|
||||||
|
msgstr ""
|
||||||
|
"AllTube Download 能够提取视频"
|
||||||
|
"或音频文件的的所有网站"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:138
|
||||||
|
msgid "Password prompt"
|
||||||
|
msgstr "密码提示"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:140
|
||||||
|
msgid ""
|
||||||
|
"You need a password in order to download this video with AllTube Download"
|
||||||
|
msgstr ""
|
||||||
|
"您需要密码才能使用 AllTube Download 下载此视频"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:174
|
||||||
|
# Download page header?
|
||||||
|
msgid "Video download"
|
||||||
|
msgstr "下载视频"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:176
|
||||||
|
msgid "Download video from @extractor"
|
||||||
|
msgstr "从 @extractor 下载视频"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:182
|
||||||
|
msgid "Download @title from @extractor"
|
||||||
|
msgstr "从 @extractor 下载 @title"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:255
|
||||||
|
msgid "Error"
|
||||||
|
msgstr "错误"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:271
|
||||||
|
msgid "Page not found"
|
||||||
|
msgstr "找不到页面"
|
||||||
|
|
||||||
|
#: classes/Controller/FrontController.php:282
|
||||||
|
msgid "Method not allowed"
|
||||||
|
msgstr "不允许此请求方法"
|
||||||
|
|
11
phpunit.xml
11
phpunit.xml
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<phpunit bootstrap="tests/bootstrap.php">
|
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="tests/bootstrap.php"
|
||||||
<filter>
|
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||||
<whitelist>
|
<coverage>
|
||||||
|
<include>
|
||||||
<directory>classes/</directory>
|
<directory>classes/</directory>
|
||||||
</whitelist>
|
</include>
|
||||||
</filter>
|
</coverage>
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite name="Tests">
|
<testsuite name="Tests">
|
||||||
<directory>tests/</directory>
|
<directory>tests/</directory>
|
||||||
|
|
|
@ -6,19 +6,6 @@ Most recent browsers automatically play a video
|
||||||
if it is a format they know how to play.
|
if it is a format they know how to play.
|
||||||
You can usually download the video by doing *File > Save to* or *ctrl + S*.
|
You can usually download the video by doing *File > Save to* or *ctrl + S*.
|
||||||
|
|
||||||
## [alltubedownload.net](https://alltubedownload.net) is too slow
|
|
||||||
|
|
||||||
[alltubedownload.net](https://alltubedownload.net) is hosted on a free [Heroku server](https://www.heroku.com/pricing)
|
|
||||||
so it has low RAM and CPU.
|
|
||||||
|
|
||||||
AllTube probably won't switch to a more expensive hosting
|
|
||||||
because this project does not earn any financial resources
|
|
||||||
and you are encouraged to host it yourself.
|
|
||||||
|
|
||||||
## alltubedownload.net often says "An error occurred in the application…"
|
|
||||||
|
|
||||||
See above.
|
|
||||||
|
|
||||||
## Change config parameters
|
## Change config parameters
|
||||||
|
|
||||||
You need to create a YAML file called `config.yml` in the `config/` folder.
|
You need to create a YAML file called `config.yml` in the `config/` folder.
|
||||||
|
@ -68,8 +55,7 @@ There are two known workarounds:
|
||||||
|
|
||||||
* You can run AllTube locally on your computer.
|
* You can run AllTube locally on your computer.
|
||||||
* You can enable streaming videos through the server (see below).
|
* You can enable streaming videos through the server (see below).
|
||||||
Please note that this can use a lot of resources on the server
|
Please note that this can use a lot of resources on the server.
|
||||||
(which is why we won't enable it on alltubedownload.net).
|
|
||||||
|
|
||||||
## I get a 404 error on every page except the index
|
## I get a 404 error on every page except the index
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
"start_url": "./",
|
"start_url": "../",
|
||||||
"theme_color": "#4F4F4F",
|
"theme_color": "#4F4F4F",
|
||||||
"background_color": "#EBEBEB",
|
"background_color": "#EBEBEB",
|
||||||
"orientation": "portrait"
|
"orientation": "portrait"
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
||||||
<url>
|
|
||||||
<loc>https://alltubedownload.net/</loc>
|
|
||||||
<changefreq>yearly</changefreq>
|
|
||||||
<priority>1</priority>
|
|
||||||
</url>
|
|
||||||
<url>
|
|
||||||
<loc>https://alltubedownload.net/extractors</loc>
|
|
||||||
<changefreq>weekly</changefreq>
|
|
||||||
</url>
|
|
||||||
</urlset>
|
|
|
@ -1 +0,0 @@
|
||||||
Sitemap: https://alltubedownload.net/resources/sitemap.xml
|
|
|
@ -1 +1 @@
|
||||||
python-3.8.6
|
python-3.8.12
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{include file='inc/head.tpl'}
|
{extends file='page.tpl'}
|
||||||
<div class="wrapper">
|
{block name='main'}
|
||||||
<main class="main error">
|
<div class="error">
|
||||||
{include file="inc/logo.tpl"}
|
{include file="inc/logo.tpl"}
|
||||||
<h2>{t}An error occurred{/t}</h2>
|
<h2>{t}An error occurred{/t}</h2>
|
||||||
<p><i>{$error|escape|nl2br}</i></p>
|
<p><i>{$error|escape|nl2br}</i></p>
|
||||||
</main>
|
</div>
|
||||||
{include file='inc/footer.tpl'}
|
{/block}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{include file='inc/head.tpl'}
|
{extends file='page.tpl'}
|
||||||
{include file='inc/header.tpl'}
|
{block name='main'}
|
||||||
{include file='inc/logo.tpl'}
|
{include file='inc/logo.tpl'}
|
||||||
<h2 class="titre">{t}Supported websites{/t}</h2>
|
<h2 class="titre">{t}Supported websites{/t}</h2>
|
||||||
<div class="tripleliste">
|
<div class="tripleliste">
|
||||||
<ul>
|
<ul>
|
||||||
{foreach $extractors as $extractor}
|
{foreach $extractors as $extractor}
|
||||||
<li>{$extractor}</li>
|
<li>{$extractor}</li>
|
||||||
{/foreach}
|
{/foreach}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{include file='inc/footer.tpl'}
|
{/block}
|
||||||
|
|
|
@ -1,18 +1,11 @@
|
||||||
</div>
|
|
||||||
<footer class="small-font">
|
<footer class="small-font">
|
||||||
<div class="footer_wrapper">
|
<div class="footer_wrapper">
|
||||||
{$dev="<a rel='author' target='blank'
|
{include file='snippets/dev.tpl' assign=dev}
|
||||||
href='http://rudloff.pro/'>
|
|
||||||
Pierre Rudloff
|
|
||||||
</a>"}
|
|
||||||
{t params=['@dev'=>$dev]}Code by @dev{/t}
|
{t params=['@dev'=>$dev]}Code by @dev{/t}
|
||||||
|
|
||||||
·
|
·
|
||||||
|
|
||||||
{$designer="<a rel='author' target='blank'
|
{include file='snippets/designer.tpl' assign=designer}
|
||||||
href='http://olivierhaquette.fr'>
|
|
||||||
Olivier Haquette
|
|
||||||
</a>"}
|
|
||||||
{t params=['@designer' => $designer]}Design by @designer{/t}
|
{t params=['@designer' => $designer]}Design by @designer{/t}
|
||||||
|
|
||||||
·
|
·
|
||||||
|
@ -23,15 +16,7 @@
|
||||||
|
|
||||||
·
|
·
|
||||||
|
|
||||||
{$youtubedl="<a href='http://ytdl-org.github.io/youtube-dl/'>
|
{include file='snippets/youtubedl.tpl' assign=youtubedl}
|
||||||
youtube-dl
|
|
||||||
</a>"}
|
|
||||||
{t params=['@youtubedl'=>$youtubedl]}Based on @youtubedl{/t}
|
{t params=['@youtubedl'=>$youtubedl]}Based on @youtubedl{/t}
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
|
||||||
{if isset($debug_render)}
|
|
||||||
{$debug_render->render()}
|
|
||||||
{/if}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
<!doctype html>
|
|
||||||
<html lang="{$locale->getLocale()->getBcp47()}">
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name=viewport content="width=device-width, initial-scale=1"/>
|
<meta name=viewport content="width=device-width, initial-scale=1"/>
|
||||||
|
@ -11,7 +9,6 @@
|
||||||
<link rel="stylesheet" href="{base_url}/assets/open-sans/open-sans.css"/>
|
<link rel="stylesheet" href="{base_url}/assets/open-sans/open-sans.css"/>
|
||||||
<link rel="stylesheet" href="{base_url}/css/style.css"/>
|
<link rel="stylesheet" href="{base_url}/css/style.css"/>
|
||||||
<title>{$config->appName}{if isset($title)} - {$title|escape}{/if}</title>
|
<title>{$config->appName}{if isset($title)} - {$title|escape}{/if}</title>
|
||||||
<link rel="canonical" href="{$canonical}"/>
|
|
||||||
<link rel="icon" href="{base_url}/img/favicon.png"/>
|
<link rel="icon" href="{base_url}/img/favicon.png"/>
|
||||||
<meta property="og:title" content="{$config->appName}{if isset($title)} - {$title|escape}{/if}"/>
|
<meta property="og:title" content="{$config->appName}{if isset($title)} - {$title|escape}{/if}"/>
|
||||||
<meta property="og:image" content="{base_url}/img/logo.png"/>
|
<meta property="og:image" content="{base_url}/img/logo.png"/>
|
||||||
|
@ -27,5 +24,3 @@
|
||||||
{$debug_render->renderHead()}
|
{$debug_render->renderHead()}
|
||||||
{/if}
|
{/if}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
|
||||||
<div class="page {$class}">
|
|
||||||
|
|
|
@ -27,4 +27,3 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
<div class="wrapper">
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<h1 class="logobis">
|
<h1 class="logobis">
|
||||||
<a class="logocompatible" href="{path_for name="index"}">
|
<a class="logocompatible" href="{path_for name="index"}">
|
||||||
<span class="logocompatiblemask"><img src="{base_url}/img/logocompatiblemask.png" width="447" height="107"
|
<span class="logocompatiblemask">
|
||||||
alt="{$config->appName}"/></span>
|
{html_image file='img/logocompatiblemask.png' path_prefix={base_url}|cat:'/' alt=$config->appName}
|
||||||
</a></h1>
|
</span>
|
||||||
|
</a>
|
||||||
|
</h1>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{include file='inc/head.tpl'}
|
{extends file='page.tpl'}
|
||||||
{include file='inc/header.tpl'}
|
{block name='main'}
|
||||||
<main class="main">
|
<div>
|
||||||
<div><img class="logo" src="{base_url}/img/logo.png"
|
{html_image file='img/logo.png' path_prefix={base_url}|cat:'/' alt=$config->appName class="logo"}
|
||||||
alt="{$config->appName}" width="328" height="284"></div>
|
</div>
|
||||||
<form action="{path_for name="info"}">
|
<form action="{path_for name="info"}">
|
||||||
<label class="labelurl" for="url">
|
<label class="labelurl" for="url">
|
||||||
{t}Copy here the URL of your video (YouTube, Dailymotion, etc.){/t}
|
{t}Copy here the URL of your video (YouTube, Dailymotion, etc.){/t}
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
<span class="URLinput_wrapper">
|
<span class="URLinput_wrapper">
|
||||||
<!-- We used to have an autofocus attribute on this field but it triggerd a very specific CSS bug: https://github.com/Rudloff/alltube/issues/117 -->
|
<!-- We used to have an autofocus attribute on this field but it triggerd a very specific CSS bug: https://github.com/Rudloff/alltube/issues/117 -->
|
||||||
<input class="URLinput large-font" type="url" name="url" id="url"
|
<input class="URLinput large-font" type="url" name="url" id="url"
|
||||||
required placeholder="http://example.com/video"/>
|
required placeholder="https://example.com/video"/>
|
||||||
</span>
|
</span>
|
||||||
{if $config->uglyUrls}
|
{if $config->uglyUrls}
|
||||||
<input type="hidden" name="page" value="info"/>
|
<input type="hidden" name="page" value="info"/>
|
||||||
|
@ -20,18 +20,23 @@
|
||||||
{if $config->convert}
|
{if $config->convert}
|
||||||
<div class="mp3 small-font">
|
<div class="mp3 small-font">
|
||||||
<div class="mp3-inner">
|
<div class="mp3-inner">
|
||||||
<input type="checkbox" id="audio" class="audio" name="audio" {($config->defaultAudio) ? 'checked' : ''}>
|
<input type="checkbox" id="audio" class="audio"
|
||||||
|
name="audio" {($config->defaultAudio) ? 'checked' : ''}>
|
||||||
<label for="audio"><span class="ui"></span>
|
<label for="audio"><span class="ui"></span>
|
||||||
{t}Audio only (MP3){/t}
|
{t}Audio only (MP3){/t}
|
||||||
</label>
|
</label>
|
||||||
{if $config->convertSeek}
|
{if $config->convertSeek}
|
||||||
<div class="seekOptions">
|
<div class="seekOptions">
|
||||||
<label for="from">{t}From{/t}</label> <input type="text" pattern="(\d+:)?(\d+:)?\d+(\.\d+)?"
|
<label for="from">{t}From{/t}</label> <input type="text"
|
||||||
placeholder="HH:MM:SS" value="" name="from"
|
pattern="(\d+:)?(\d+:)?\d+(\.\d+)?"
|
||||||
id="from"/>
|
placeholder="HH:MM:SS" value=""
|
||||||
<label for="to">{t}to{/t}</label> <input type="text" pattern="(\d+:)?(\d+:)?\d+(\.\d+)?"
|
name="from"
|
||||||
placeholder="HH:MM:SS" value="" name="to" id="to"/>
|
id="from"/>
|
||||||
</div>
|
<label for="to">{t}to{/t}</label> <input type="text"
|
||||||
|
pattern="(\d+:)?(\d+:)?\d+(\.\d+)?"
|
||||||
|
placeholder="HH:MM:SS" value="" name="to"
|
||||||
|
id="to"/>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,6 +49,4 @@
|
||||||
<a class="bookmarklet small-font"
|
<a class="bookmarklet small-font"
|
||||||
href="javascript:window.location='{$domain}{path_for name='info' queryParams=['url' => '%url%']}'.replace('%url%', encodeURIComponent(location.href));">{t}Bookmarklet{/t}</a>
|
href="javascript:window.location='{$domain}{path_for name='info' queryParams=['url' => '%url%']}'.replace('%url%', encodeURIComponent(location.href));">{t}Bookmarklet{/t}</a>
|
||||||
</div>
|
</div>
|
||||||
|
{/block}
|
||||||
</main>
|
|
||||||
{include file='inc/footer.tpl'}
|
|
||||||
|
|
|
@ -1,111 +1,59 @@
|
||||||
{include file="inc/head.tpl"}
|
{extends file='page.tpl'}
|
||||||
<div class="wrapper">
|
{block name='main'}
|
||||||
<div itemscope itemtype="http://schema.org/VideoObject">
|
<div itemscope itemtype="https://schema.org/VideoObject">
|
||||||
<main class="main">
|
{include file="inc/logo.tpl"}
|
||||||
{include file="inc/logo.tpl"}
|
{include file='snippets/title.tpl' assign=title}
|
||||||
{$title="<i itemprop='name'>
|
<p id="download_intro">
|
||||||
<a itemprop='url' id='video_link'
|
{t params=['@title' => $title]}You are going to download @title.{/t}
|
||||||
href='{$video->webpage_url}'>
|
</p>
|
||||||
{$video->title}</a></i>"}
|
{if isset($video->thumbnail)}
|
||||||
<p id="download_intro">
|
{html_image file=$video->thumbnail itemprop="thumbnailUrl" class="thumb"}
|
||||||
{t params=['@title' => $title]}You are going to download @title.{/t}
|
{/if}
|
||||||
</p>
|
{if isset($video->description)}
|
||||||
{if isset($video->thumbnail)}
|
<meta itemprop="description" content="{$video->description|escape}"/>
|
||||||
<img itemprop="thumbnailUrl" class="thumb" src="{$video->thumbnail}" alt=""/>
|
{/if}
|
||||||
|
{if isset($video->upload_date)}
|
||||||
|
<meta itemprop="uploadDate" content="{$video->upload_date}"/>
|
||||||
|
{/if}
|
||||||
|
<br/>
|
||||||
|
<form action="{path_for name="download"}">
|
||||||
|
<input type="hidden" name="url" value="{$video->webpage_url}"/>
|
||||||
|
{if $config->uglyUrls}
|
||||||
|
<input type="hidden" name="page" value="download"/>
|
||||||
{/if}
|
{/if}
|
||||||
{if isset($video->description)}
|
{if isset($video->formats) && count($video->formats) > 1}
|
||||||
<meta itemprop="description" content="{$video->description|escape}"/>
|
<h3><label for="format">{t}Available formats:{/t}</label></h3>
|
||||||
|
{*
|
||||||
|
To make the default generic formats translatable:
|
||||||
|
{t}Best{/t}
|
||||||
|
{t}Remux best video with best audio{/t}
|
||||||
|
{t}Worst{/t}
|
||||||
|
*}
|
||||||
|
{html_options name='format' options=$formats selected=$defaultFormat id="format" class="formats monospace"}
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
{/if}
|
{/if}
|
||||||
{if isset($video->upload_date)}
|
{if $config->stream}
|
||||||
<meta itemprop="uploadDate" content="{$video->upload_date}"/>
|
<input type="checkbox" {if $config->stream !== 'ask'}checked{/if} name="stream" id="stream"/>
|
||||||
|
<label for="stream">{t}Stream the video through the server{/t}</label>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
{/if}
|
{/if}
|
||||||
<br/>
|
{if $config->convertAdvanced}
|
||||||
<form action="{path_for name="download"}">
|
<input type="checkbox" name="customConvert" id="customConvert"/>
|
||||||
<input type="hidden" name="url" value="{$video->webpage_url}"/>
|
<label for="customConvert">{t}Convert into a custom format:{/t}</label>
|
||||||
{if $config->uglyUrls}
|
{html_options name='customFormat' values=$config->convertAdvancedFormats output=$config->convertAdvancedFormats
|
||||||
<input type="hidden" name="page" value="download"/>
|
title="{t}Custom format{/t}" name="customFormat" aria-label="{t}Format to convert to{/t}"}
|
||||||
{/if}
|
{t}with{/t}
|
||||||
{if isset($video->formats) && count($video->formats) > 1}
|
<label for="customBitrate" class="sr-only">{t}Bit rate{/t}</label>
|
||||||
<h3><label for="format">{t}Available formats:{/t}</label></h3>
|
<input type="number" value="{$config->audioBitrate}" title="{t}Custom bitrate{/t}"
|
||||||
<select name="format" id="format" class="formats monospace">
|
class="customBitrate"
|
||||||
<optgroup label="{t}Generic formats{/t}">
|
name="customBitrate" id="customBitrate" aria-describedby="customBitrateUnit"/>
|
||||||
{foreach $config->genericFormats as $format => $name}
|
<span id="customBitrateUnit">{t}kbit/s audio{/t}</span>
|
||||||
{*
|
<br/>
|
||||||
To make the default generic formats translatable:
|
<br/>
|
||||||
{t}Best{/t}
|
{/if}
|
||||||
{t}Remux best video with best audio{/t}
|
<input class="downloadBtn" type="submit" value="{t}Download{/t}"/><br/>
|
||||||
{t}Worst{/t}
|
</form>
|
||||||
*}
|
|
||||||
<option value="{$format}">{t}{$name}{/t}</option>
|
|
||||||
{/foreach}
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="{t}Detailed formats{/t}" class="monospace">
|
|
||||||
{foreach $video->formats as $format}
|
|
||||||
{if $config->stream || $format->protocol|in_array:array('http', 'https')}
|
|
||||||
{strip}
|
|
||||||
<option value="{$format->format_id}">
|
|
||||||
{$format->ext}
|
|
||||||
{for $foo=1 to (5 - ($format->ext|strlen))}
|
|
||||||
|
|
||||||
{/for}
|
|
||||||
{if isset($format->width)}
|
|
||||||
{$format->width}x{$format->height}
|
|
||||||
{for $foo=1 to (10 - (("{$format->width}x{$format->height}")|strlen))}
|
|
||||||
|
|
||||||
{/for}
|
|
||||||
{else}
|
|
||||||
{for $foo=1 to 10}
|
|
||||||
|
|
||||||
{/for}
|
|
||||||
{/if}
|
|
||||||
{if isset($format->filesize)}
|
|
||||||
{($format->filesize/1000000)|round:2} MB
|
|
||||||
{for $foo=1 to (7 - (($format->filesize/1000000)|round:2|strlen))}
|
|
||||||
|
|
||||||
{/for}
|
|
||||||
{else}
|
|
||||||
{for $foo=1 to 10}
|
|
||||||
|
|
||||||
{/for}
|
|
||||||
{/if}
|
|
||||||
{if isset($format->format_note)}
|
|
||||||
{$format->format_note}
|
|
||||||
{/if}
|
|
||||||
({$format->format_id})
|
|
||||||
</option>
|
|
||||||
{/strip}
|
|
||||||
{/if}
|
|
||||||
{/foreach}
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
{/if}
|
|
||||||
{if $config->stream}
|
|
||||||
<input type="checkbox" {if $config->stream !== 'ask'}checked{/if} name="stream" id="stream"/>
|
|
||||||
<label for="stream">{t}Stream the video through the server{/t}</label>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
{/if}
|
|
||||||
{if $config->convertAdvanced}
|
|
||||||
<input type="checkbox" name="customConvert" id="customConvert"/>
|
|
||||||
<label for="customConvert">{t}Convert into a custom format:{/t}</label>
|
|
||||||
<select title="{t}Custom format{/t}" name="customFormat" aria-label="{t}Format to convert to{/t}">
|
|
||||||
{foreach $config->convertAdvancedFormats as $format}
|
|
||||||
<option>{$format}</option>
|
|
||||||
{/foreach}
|
|
||||||
</select>
|
|
||||||
{t}with{/t}
|
|
||||||
<label for="customBitrate" class="sr-only">{t}Bit rate{/t}</label>
|
|
||||||
<input type="number" value="{$config->audioBitrate}" title="{t}Custom bitrate{/t}"
|
|
||||||
class="customBitrate"
|
|
||||||
name="customBitrate" id="customBitrate" aria-describedby="customBitrateUnit"/>
|
|
||||||
<span id="customBitrateUnit">{t}kbit/s audio{/t}</span>
|
|
||||||
<br/>
|
|
||||||
<br/>
|
|
||||||
{/if}
|
|
||||||
<input class="downloadBtn" type="submit" value="{t}Download{/t}"/><br/>
|
|
||||||
</form>
|
|
||||||
</main>
|
|
||||||
</div>
|
</div>
|
||||||
{include file="inc/footer.tpl"}
|
{/block}
|
||||||
|
|
18
templates/page.tpl
Normal file
18
templates/page.tpl
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="{$locale->getLocale()->getBcp47()}">
|
||||||
|
{include file='inc/head.tpl'}
|
||||||
|
<body>
|
||||||
|
<div class="page {$class}">
|
||||||
|
{include file='inc/header.tpl'}
|
||||||
|
<div class="wrapper">
|
||||||
|
<main class="main">
|
||||||
|
{block name="main"}{/block}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
{include file='inc/footer.tpl'}
|
||||||
|
</div>
|
||||||
|
{if isset($debug_render)}
|
||||||
|
{$debug_render->render()}
|
||||||
|
{/if}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,14 +1,12 @@
|
||||||
{include file='inc/head.tpl'}
|
{extends file='page.tpl'}
|
||||||
<div class="wrapper">
|
{block name='main'}
|
||||||
<main class="main">
|
{include file="inc/logo.tpl"}
|
||||||
{include file="inc/logo.tpl"}
|
<h2>{t}This video is protected{/t}</h2>
|
||||||
<h2>{t}This video is protected{/t}</h2>
|
<p>{t}You need a password in order to download this video.{/t}</p>
|
||||||
<p>{t}You need a password in order to download this video.{/t}</p>
|
<form action="" method="POST">
|
||||||
<form action="" method="POST">
|
<label class="sr-only" for="password">{t}Video password{/t}</label>
|
||||||
<label class="sr-only" for="password">{t}Video password{/t}</label>
|
<input class="URLinput" type="password" name="password" id="password"/>
|
||||||
<input class="URLinput" type="password" name="password" id="password"/>
|
<br/><br/>
|
||||||
<br/><br/>
|
<input class="downloadBtn" type="submit" value="{t}Download{/t}"/>
|
||||||
<input class="downloadBtn" type="submit" value="{t}Download{/t}"/>
|
</form>
|
||||||
</form>
|
{/block}
|
||||||
</main>
|
|
||||||
{include file='inc/footer.tpl'}
|
|
||||||
|
|
|
@ -1,44 +1,40 @@
|
||||||
{include file="inc/head.tpl"}
|
{extends file='page.tpl'}
|
||||||
<div class="wrapper">
|
{block name='main'}
|
||||||
<main class="main">
|
{include file="inc/logo.tpl"}
|
||||||
{include file="inc/logo.tpl"}
|
|
||||||
|
|
||||||
{if isset($video->title)}
|
{if isset($video->title)}
|
||||||
{$title="<i>
|
{include file='snippets/title.tpl' assign=title}
|
||||||
<a href='{$video->webpage_url}'>
|
<p>
|
||||||
{$video->title}</a>
|
{t params=['@title'=>$title]}Videos extracted from @title:{/t}
|
||||||
</i>"}
|
</p>
|
||||||
<p>
|
{/if}
|
||||||
{t params=['@title'=>$title]}Videos extracted from @title:{/t}
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{if $config->stream}
|
{if $config->stream}
|
||||||
<a href="{path_for name="download"}?url={$video->webpage_url}" class="downloadBtn">Download everything</a>
|
<a href="{path_for name="download"}?url={$video->webpage_url}" class="downloadBtn">Download everything</a>
|
||||||
{/if}
|
{/if}
|
||||||
{foreach $video->entries as $entry}
|
{foreach $video->entries as $entry}
|
||||||
<div class="playlist-entry">
|
<div class="playlist-entry">
|
||||||
<h3 class="playlist-entry-title"><a target="_blank" href="{strip}
|
<h3 class="playlist-entry-title">
|
||||||
|
<a target="_blank" href="{strip}
|
||||||
{if isset($entry->ie_key) and $entry->ie_key == Youtube and !filter_var($entry->url, FILTER_VALIDATE_URL)}
|
{if isset($entry->ie_key) and $entry->ie_key == Youtube and !filter_var($entry->url, FILTER_VALIDATE_URL)}
|
||||||
https://www.youtube.com/watch?v=
|
https://www.youtube.com/watch?v=
|
||||||
{/if}
|
{/if}
|
||||||
{$entry->url}
|
{$entry->url}
|
||||||
{/strip}">
|
{/strip}">
|
||||||
{if !isset($entry->title)}
|
{if !isset($entry->title)}
|
||||||
{if $entry->ie_key == YoutubePlaylist}
|
{if $entry->ie_key == YoutubePlaylist}
|
||||||
Playlist
|
Playlist
|
||||||
{else}
|
|
||||||
Video
|
|
||||||
{/if}
|
|
||||||
{else}
|
{else}
|
||||||
{$entry->title}
|
Video
|
||||||
{/if}
|
{/if}
|
||||||
</a></h3>
|
{else}
|
||||||
<a target="_blank" class="downloadBtn"
|
{$entry->title}
|
||||||
href="{path_for name="download"}?url={$entry->url}">{t}Download{/t}</a>
|
{/if}
|
||||||
<a target="_blank" href="{path_for name="info"}?url={$entry->url}">{t}More options{/t}</a>
|
</a>
|
||||||
</div>
|
</h3>
|
||||||
{/foreach}
|
<a target="_blank" class="downloadBtn"
|
||||||
|
href="{path_for name="download"}?url={$entry->url}">{t}Download{/t}</a>
|
||||||
</main>
|
<a target="_blank" href="{path_for name="info"}?url={$entry->url}">{t}More options{/t}</a>
|
||||||
{include file="inc/footer.tpl"}
|
</div>
|
||||||
|
{/foreach}
|
||||||
|
{/block}
|
||||||
|
|
4
templates/snippets/designer.tpl
Normal file
4
templates/snippets/designer.tpl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<a rel="author" target="blank"
|
||||||
|
href="https://ographik.fr/">
|
||||||
|
Olivier Haquette
|
||||||
|
</a>
|
4
templates/snippets/dev.tpl
Normal file
4
templates/snippets/dev.tpl
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<a rel="author" target="blank"
|
||||||
|
href="https://rudloff.pro/">
|
||||||
|
Pierre Rudloff
|
||||||
|
</a>
|
5
templates/snippets/title.tpl
Normal file
5
templates/snippets/title.tpl
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<i itemprop="name">
|
||||||
|
<a itemprop="url" id="video_link"
|
||||||
|
href="{$video->webpage_url}">
|
||||||
|
{$video->title}</a>
|
||||||
|
</i>
|
3
templates/snippets/youtubedl.tpl
Normal file
3
templates/snippets/youtubedl.tpl
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<a href="https://ytdl-org.github.io/youtube-dl/">
|
||||||
|
youtube-dl
|
||||||
|
</a>
|
|
@ -6,7 +6,9 @@
|
||||||
|
|
||||||
namespace Alltube\Test;
|
namespace Alltube\Test;
|
||||||
|
|
||||||
|
use OndraM\CiDetector\CiDetector;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use PHPUnit\Util\Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class used by every test.
|
* Abstract class used by every test.
|
||||||
|
@ -37,7 +39,11 @@ abstract class BaseTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected function checkRequirements()
|
protected function checkRequirements()
|
||||||
{
|
{
|
||||||
$annotations = $this->getAnnotations();
|
$ciDetector = new CiDetector();
|
||||||
|
$annotations = Test::parseTestMethodAnnotations(
|
||||||
|
static::class,
|
||||||
|
$this->getName()
|
||||||
|
);
|
||||||
$requires = [];
|
$requires = [];
|
||||||
|
|
||||||
if (isset($annotations['class']['requires'])) {
|
if (isset($annotations['class']['requires'])) {
|
||||||
|
@ -48,7 +54,7 @@ abstract class BaseTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($requires as $require) {
|
foreach ($requires as $require) {
|
||||||
if ($require == 'download' && getenv('CI')) {
|
if ($require == 'download' && $ciDetector->isCiDetected()) {
|
||||||
$this->markTestSkipped('Do not run tests that download videos on CI.');
|
$this->markTestSkipped('Do not run tests that download videos on CI.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,14 +108,6 @@ class DownloadControllerTest extends ControllerTest
|
||||||
public function testDownloadWithRtmpStream()
|
public function testDownloadWithRtmpStream()
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('We need to find another RTMP video.');
|
$this->markTestIncomplete('We need to find another RTMP video.');
|
||||||
|
|
||||||
$config = $this->container->get('config');
|
|
||||||
$config->setOptions(['stream' => true]);
|
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
|
||||||
'download',
|
|
||||||
['url' => 'http://www.rtvnh.nl/video/131946', 'format' => 'rtmp-264']
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -161,7 +153,7 @@ class DownloadControllerTest extends ControllerTest
|
||||||
*/
|
*/
|
||||||
public function testDownloadWithMissingPassword()
|
public function testDownloadWithMissingPassword()
|
||||||
{
|
{
|
||||||
$this->assertRequestIsClientError('download', ['url' => 'http://vimeo.com/68375962']);
|
$this->assertRequestIsClientError('download', ['url' => 'https://vimeo.com/68375962']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,7 +164,7 @@ class DownloadControllerTest extends ControllerTest
|
||||||
public function testDownloadWithError()
|
public function testDownloadWithError()
|
||||||
{
|
{
|
||||||
$this->expectException(YoutubedlException::class);
|
$this->expectException(YoutubedlException::class);
|
||||||
$this->getRequestResult('download', ['url' => 'http://example.com/foo']);
|
$this->getRequestResult('download', ['url' => 'https://example.com/foo']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -186,12 +186,12 @@ class FrontControllerTest extends ControllerTest
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @requires download
|
* @requires download
|
||||||
* @throws AlltubeLibraryException
|
* @throws AlltubeLibraryException|InvalidURLException
|
||||||
*/
|
*/
|
||||||
public function testInfoWithPassword()
|
public function testInfoWithPassword()
|
||||||
{
|
{
|
||||||
$result = $this->controller->info(
|
$result = $this->controller->info(
|
||||||
$this->container->get('request')->withQueryParams(['url' => 'http://vimeo.com/68375962'])
|
$this->container->get('request')->withQueryParams(['url' => 'https://vimeo.com/68375962'])
|
||||||
->withParsedBody(['password' => 'youtube-dl']),
|
->withParsedBody(['password' => 'youtube-dl']),
|
||||||
$this->container->get('response')
|
$this->container->get('response')
|
||||||
);
|
);
|
||||||
|
@ -206,8 +206,8 @@ class FrontControllerTest extends ControllerTest
|
||||||
*/
|
*/
|
||||||
public function testInfoWithMissingPassword()
|
public function testInfoWithMissingPassword()
|
||||||
{
|
{
|
||||||
$this->assertRequestIsClientError('info', ['url' => 'http://vimeo.com/68375962']);
|
$this->assertRequestIsClientError('info', ['url' => 'https://vimeo.com/68375962']);
|
||||||
$this->assertRequestIsClientError('info', ['url' => 'http://vimeo.com/68375962', 'audio' => true]);
|
$this->assertRequestIsClientError('info', ['url' => 'https://vimeo.com/68375962', 'audio' => true]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -49,7 +49,7 @@ class JsonControllerTest extends ControllerTest
|
||||||
public function testJsonWithError()
|
public function testJsonWithError()
|
||||||
{
|
{
|
||||||
$this->expectException(YoutubedlException::class);
|
$this->expectException(YoutubedlException::class);
|
||||||
$this->getRequestResult('json', ['url' => 'http://example.com/foo']);
|
$this->getRequestResult('json', ['url' => 'https://example.com/foo']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -79,7 +79,7 @@ class UglyRouterTest extends ContainerTest
|
||||||
public function testPathFor()
|
public function testPathFor()
|
||||||
{
|
{
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'/?page=foo',
|
'/?page=%2Ffoo',
|
||||||
$this->router->pathFor('foo', [], [])
|
$this->router->pathFor('foo', [], [])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ class UglyRouterTest extends ContainerTest
|
||||||
{
|
{
|
||||||
$this->router->setBasePath('/bar');
|
$this->router->setBasePath('/bar');
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
'/bar/?page=foo',
|
'/bar/?page=%2Ffoo',
|
||||||
$this->router->pathFor('foo', [], [])
|
$this->router->pathFor('foo', [], [])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ class VideoTest extends ContainerTest
|
||||||
*/
|
*/
|
||||||
public function testgetUrlWithPassword()
|
public function testgetUrlWithPassword()
|
||||||
{
|
{
|
||||||
$video = new Video($this->downloader, 'http://vimeo.com/68375962', 'best', 'youtube-dl');
|
$video = new Video($this->downloader, 'https://vimeo.com/68375962', 'best', 'youtube-dl');
|
||||||
foreach ($video->getUrl() as $videoURL) {
|
foreach ($video->getUrl() as $videoURL) {
|
||||||
$this->assertStringContainsString('vimeocdn.com', $videoURL);
|
$this->assertStringContainsString('vimeocdn.com', $videoURL);
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ class VideoTest extends ContainerTest
|
||||||
public function testgetUrlWithMissingPassword()
|
public function testgetUrlWithMissingPassword()
|
||||||
{
|
{
|
||||||
$this->expectException(PasswordException::class);
|
$this->expectException(PasswordException::class);
|
||||||
$video = new Video($this->downloader, 'http://vimeo.com/68375962', $this->format);
|
$video = new Video($this->downloader, 'https://vimeo.com/68375962', $this->format);
|
||||||
$video->getUrl();
|
$video->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class VideoTest extends ContainerTest
|
||||||
public function testgetUrlWithWrongPassword()
|
public function testgetUrlWithWrongPassword()
|
||||||
{
|
{
|
||||||
$this->expectException(WrongPasswordException::class);
|
$this->expectException(WrongPasswordException::class);
|
||||||
$video = new Video($this->downloader, 'http://vimeo.com/68375962', 'best', 'foo');
|
$video = new Video($this->downloader, 'https://vimeo.com/68375962', 'best', 'foo');
|
||||||
$video->getUrl();
|
$video->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ class VideoTest extends ContainerTest
|
||||||
'googlevideo.com',
|
'googlevideo.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'http://www.bbc.co.uk/programmes/b039g8p7', 'bestaudio/best',
|
'https://www.bbc.co.uk/programmes/b039g8p7', 'bestaudio/best',
|
||||||
'Kaleidoscope_Leonard_Cohen-b039d07m',
|
'Kaleidoscope_Leonard_Cohen-b039d07m',
|
||||||
'flv',
|
'flv',
|
||||||
'bbcodspdns.fcod.llnwd.net',
|
'bbcodspdns.fcod.llnwd.net',
|
||||||
|
@ -247,7 +247,7 @@ class VideoTest extends ContainerTest
|
||||||
public function errorUrlProvider(): array
|
public function errorUrlProvider(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
['http://example.com/video'],
|
['https://example.com/video'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,16 +479,11 @@ class VideoTest extends ContainerTest
|
||||||
* @param string $format Format
|
* @param string $format Format
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @throws AlltubeLibraryException
|
|
||||||
* @dataProvider rtmpUrlProvider
|
* @dataProvider rtmpUrlProvider
|
||||||
*/
|
*/
|
||||||
public function testGetRtmpStream(string $url, string $format)
|
public function testGetRtmpStream(string $url, string $format)
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('We need to find another RTMP video.');
|
$this->markTestIncomplete('We need to find another RTMP video.');
|
||||||
|
|
||||||
$video = new Video($this->downloader, $url, $format);
|
|
||||||
|
|
||||||
$this->assertStream($this->downloader->getRtmpStream($video));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue