refactor: New Video class
The news class provides a cleaner object-oriented logic BREAKING CHANGE: The VideoDownload class has been removed and the Config constructor is now private
This commit is contained in:
parent
feb8998188
commit
4c9af8ad1d
18 changed files with 665 additions and 719 deletions
10
README.md
10
README.md
|
@ -162,19 +162,17 @@ You can then use it in your PHP code:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
use Alltube\Config;
|
use Alltube\Config;
|
||||||
use Alltube\VideoDownload;
|
use Alltube\Video;
|
||||||
|
|
||||||
require_once __DIR__.'/vendor/autoload.php';
|
require_once __DIR__.'/vendor/autoload.php';
|
||||||
|
|
||||||
$downloader = new VideoDownload(
|
Config::setOptions(
|
||||||
new Config(
|
|
||||||
[
|
[
|
||||||
'youtubedl' => '/usr/local/bin/youtube-dl',
|
'youtubedl' => '/usr/local/bin/youtube-dl',
|
||||||
]
|
]
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
$video = new Video('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
||||||
$downloader->getURL('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
$video->getUrl();
|
||||||
```
|
```
|
||||||
|
|
||||||
The library documentation is available on [alltube.surge.sh](https://alltube.surge.sh/classes/Alltube.VideoDownload.html).
|
The library documentation is available on [alltube.surge.sh](https://alltube.surge.sh/classes/Alltube.VideoDownload.html).
|
||||||
|
|
|
@ -129,16 +129,49 @@ class Config
|
||||||
/**
|
/**
|
||||||
* Config constructor.
|
* Config constructor.
|
||||||
*
|
*
|
||||||
* @param array $options Options (see `config/config.example.yml` for available options)
|
* @param array $options Options
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options)
|
private function __construct(array $options = [])
|
||||||
|
{
|
||||||
|
$this->applyOptions($options);
|
||||||
|
$this->getEnv();
|
||||||
|
$this->validateOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an exception if some of the options are invalid.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @throws Exception If youtube-dl is missing
|
||||||
|
* @throws Exception If Python is missing
|
||||||
|
*/
|
||||||
|
private function validateOptions()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We don't translate these exceptions because they usually occur before Slim can catch them
|
||||||
|
so they will go to the logs.
|
||||||
|
*/
|
||||||
|
if (!is_file($this->youtubedl)) {
|
||||||
|
throw new Exception("Can't find youtube-dl at ".$this->youtubedl);
|
||||||
|
} elseif (!Video::checkCommand([$this->python, '--version'])) {
|
||||||
|
throw new Exception("Can't find Python at ".$this->python);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the provided options.
|
||||||
|
*
|
||||||
|
* @param array $options Options
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function applyOptions(array $options)
|
||||||
{
|
{
|
||||||
foreach ($options as $option => $value) {
|
foreach ($options as $option => $value) {
|
||||||
if (isset($this->$option) && isset($value)) {
|
if (isset($this->$option) && isset($value)) {
|
||||||
$this->$option = $value;
|
$this->$option = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->getEnv();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,34 +192,51 @@ class Config
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Config singleton instance from YAML config file.
|
* Get Config singleton instance.
|
||||||
*
|
|
||||||
* @param string $yamlfile YAML config file name
|
|
||||||
*
|
*
|
||||||
* @return Config
|
* @return Config
|
||||||
*/
|
*/
|
||||||
public static function getInstance($yamlfile = 'config/config.yml')
|
public static function getInstance()
|
||||||
{
|
{
|
||||||
$yamlPath = __DIR__.'/../'.$yamlfile;
|
if (!isset(self::$instance)) {
|
||||||
if (is_null(self::$instance) || self::$instance->file != $yamlfile) {
|
self::$instance = new self();
|
||||||
if (is_file($yamlfile)) {
|
|
||||||
$options = Yaml::parse(file_get_contents($yamlPath));
|
|
||||||
} 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
|
|
||||||
*/
|
|
||||||
$options = [];
|
|
||||||
} else {
|
|
||||||
throw new Exception("Can't find config file at ".$yamlPath);
|
|
||||||
}
|
|
||||||
self::$instance = new self($options);
|
|
||||||
self::$instance->file = $yamlfile;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$instance;
|
return self::$instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set options from a YAML file.
|
||||||
|
*
|
||||||
|
* @param string $file Path to the YAML file
|
||||||
|
*/
|
||||||
|
public static function setFile($file)
|
||||||
|
{
|
||||||
|
if (is_file($file)) {
|
||||||
|
$options = Yaml::parse(file_get_contents($file));
|
||||||
|
self::$instance = new self($options);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Can't find config file at ".$file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually set some options.
|
||||||
|
*
|
||||||
|
* @param array $options Options (see `config/config.example.yml` for available options)
|
||||||
|
* @param boolean $update True to update an existing instance
|
||||||
|
*/
|
||||||
|
public static function setOptions(array $options, $update = true)
|
||||||
|
{
|
||||||
|
if ($update) {
|
||||||
|
$config = self::getInstance();
|
||||||
|
$config->applyOptions($options);
|
||||||
|
$config->validateOptions();
|
||||||
|
} else {
|
||||||
|
self::$instance = new self($options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy singleton instance.
|
* Destroy singleton instance.
|
||||||
*
|
*
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
namespace Alltube;
|
namespace Alltube;
|
||||||
|
|
||||||
use Barracuda\ArchiveStream\TarArchive;
|
use Barracuda\ArchiveStream\TarArchive;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Psr7\Stream;
|
||||||
use Psr\Http\Message\StreamInterface;
|
use Psr\Http\Message\StreamInterface;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
|
@ -21,7 +21,7 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
/**
|
/**
|
||||||
* videos to add in the archive.
|
* videos to add in the archive.
|
||||||
*
|
*
|
||||||
* @var PlaylistArchiveVideo[]
|
* @var Video[]
|
||||||
*/
|
*/
|
||||||
private $videos = [];
|
private $videos = [];
|
||||||
|
|
||||||
|
@ -32,53 +32,32 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
private $buffer;
|
private $buffer;
|
||||||
|
|
||||||
/**
|
|
||||||
* Guzzle client.
|
|
||||||
*
|
|
||||||
* @var Client
|
|
||||||
*/
|
|
||||||
private $client;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* VideoDownload instance.
|
|
||||||
*
|
|
||||||
* @var VideoDownload
|
|
||||||
*/
|
|
||||||
private $download;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Current video being streamed to the archive.
|
* Current video being streamed to the archive.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var Stream
|
||||||
*/
|
*/
|
||||||
private $curVideo;
|
private $curVideoStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Video format to download.
|
* True if the archive is complete.
|
||||||
*
|
* @var bool
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
private $format;
|
private $isComplete = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PlaylistArchiveStream constructor.
|
* PlaylistArchiveStream constructor.
|
||||||
*
|
*
|
||||||
* @param Config $config Config instance.
|
* @param Video $video Video/playlist to download
|
||||||
* @param stdClass $video Video object returned by youtube-dl
|
|
||||||
* @param string $format Requested format
|
|
||||||
*/
|
*/
|
||||||
public function __construct(Config $config, stdClass $video, $format)
|
public function __construct(Video $video)
|
||||||
{
|
{
|
||||||
$this->client = new Client();
|
|
||||||
$this->download = new VideoDownload($config);
|
|
||||||
|
|
||||||
$this->format = $format;
|
|
||||||
$buffer = fopen('php://temp', 'r+');
|
$buffer = fopen('php://temp', 'r+');
|
||||||
if ($buffer !== false) {
|
if ($buffer !== false) {
|
||||||
$this->buffer = $buffer;
|
$this->buffer = $buffer;
|
||||||
}
|
}
|
||||||
foreach ($video->entries as $entry) {
|
foreach ($video->entries as $entry) {
|
||||||
$this->videos[] = new PlaylistArchiveVideo($entry->url);
|
$this->videos[] = new Video($entry->url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,26 +70,27 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
protected function send($data)
|
protected function send($data)
|
||||||
{
|
{
|
||||||
$pos = ftell($this->buffer);
|
$pos = $this->tell();
|
||||||
|
|
||||||
// Add data to the buffer.
|
// Add data to the end of the buffer.
|
||||||
fwrite($this->buffer, $data);
|
$this->seek(0, SEEK_END);
|
||||||
|
$this->write($data);
|
||||||
if ($pos !== false) {
|
if ($pos !== false) {
|
||||||
// Rewind so that read() can later read this data.
|
// Rewind so that read() can later read this data.
|
||||||
fseek($this->buffer, $pos);
|
$this->seek($pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write data to the stream.
|
* Write data to the stream.
|
||||||
*
|
*
|
||||||
* @param string $string The string that is to be written.
|
* @param string $string The string that is to be written
|
||||||
*
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function write($string)
|
public function write($string)
|
||||||
{
|
{
|
||||||
throw new RuntimeException('This stream is not writeable.');
|
fwrite($this->buffer, $string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,7 +109,7 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function isSeekable()
|
public function isSeekable()
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +119,7 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function rewind()
|
public function rewind()
|
||||||
{
|
{
|
||||||
throw new RuntimeException('This stream is not seekable.');
|
rewind($this->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,7 +129,7 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function isWritable()
|
public function isWritable()
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,6 +161,15 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function getMetadata($key = null)
|
public function getMetadata($key = null)
|
||||||
{
|
{
|
||||||
|
$meta = stream_get_meta_data($this->buffer);
|
||||||
|
|
||||||
|
if (!isset($key)) {
|
||||||
|
return $meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($meta[$key])) {
|
||||||
|
return $meta[$key];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -203,13 +192,7 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function __toString()
|
public function __toString()
|
||||||
{
|
{
|
||||||
$string = '';
|
return $this->getContents();
|
||||||
|
|
||||||
foreach ($this->videos as $file) {
|
|
||||||
$string .= $file->url;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,23 +215,37 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function seek($offset, $whence = SEEK_SET)
|
public function seek($offset, $whence = SEEK_SET)
|
||||||
{
|
{
|
||||||
throw new RuntimeException('This stream is not seekable.');
|
fseek($this->buffer, $offset, $whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the stream is at the end of the stream.
|
* Returns true if the stream is at the end of the archive.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function eof()
|
public function eof()
|
||||||
{
|
{
|
||||||
foreach ($this->videos as $file) {
|
return $this->isComplete && feof($this->buffer);
|
||||||
if (!$file->complete) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
/**
|
||||||
|
* Start streaming a new video.
|
||||||
|
*
|
||||||
|
* @param Video $video Video to stream
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function startVideoStream(Video $video)
|
||||||
|
{
|
||||||
|
$response = $video->getHttpResponse();
|
||||||
|
|
||||||
|
$this->curVideoStream = $response->getBody();
|
||||||
|
$contentLengthHeaders = $response->getHeader('Content-Length');
|
||||||
|
|
||||||
|
$this->init_file_stream_transfer(
|
||||||
|
$video->getFilename(),
|
||||||
|
$contentLengthHeaders[0]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,30 +257,30 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
*/
|
*/
|
||||||
public function read($count)
|
public function read($count)
|
||||||
{
|
{
|
||||||
if (isset($this->curVideo)) {
|
// If the archive is complete, we only read the remaining buffer.
|
||||||
if (isset($this->curVideo->stream)) {
|
if (!$this->isComplete) {
|
||||||
if (!$this->curVideo->stream->eof()) {
|
if (isset($this->curVideoStream)) {
|
||||||
$this->stream_file_part($this->curVideo->stream->read($count));
|
if ($this->curVideoStream->eof()) {
|
||||||
} elseif (!$this->curVideo->complete) {
|
// Stop streaming the current video.
|
||||||
$this->complete_file_stream();
|
$this->complete_file_stream();
|
||||||
$this->curVideo->complete = true;
|
|
||||||
|
$video = next($this->videos);
|
||||||
|
if ($video) {
|
||||||
|
// Start streaming the next video.
|
||||||
|
$this->startVideoStream($video);
|
||||||
} else {
|
} else {
|
||||||
$this->curVideo = next($this->videos);
|
// No video left.
|
||||||
|
$this->finish();
|
||||||
|
$this->isComplete = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$urls = $this->download->getURL($this->curVideo->url, $this->format);
|
// Continue streaming the current video.
|
||||||
$response = $this->client->request('GET', $urls[0], ['stream' => true]);
|
$this->stream_file_part($this->curVideoStream->read($count));
|
||||||
|
|
||||||
$contentLengthHeaders = $response->getHeader('Content-Length');
|
|
||||||
$this->init_file_stream_transfer(
|
|
||||||
$this->download->getFilename($this->curVideo->url, $this->format),
|
|
||||||
$contentLengthHeaders[0]
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->curVideo->stream = $response->getBody();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->curVideo = current($this->videos);
|
// Start streaming the first video.
|
||||||
|
$this->startVideoStream(current($this->videos));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fread($this->buffer, $count);
|
return fread($this->buffer, $count);
|
||||||
|
@ -299,10 +296,8 @@ class PlaylistArchiveStream extends TarArchive implements StreamInterface
|
||||||
if (is_resource($this->buffer)) {
|
if (is_resource($this->buffer)) {
|
||||||
fclose($this->buffer);
|
fclose($this->buffer);
|
||||||
}
|
}
|
||||||
foreach ($this->videos as $file) {
|
if (isset($this->curVideoStream)) {
|
||||||
if (is_resource($file->stream)) {
|
$this->curVideoStream->close();
|
||||||
fclose($file->stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?php
|
|
||||||
/**
|
|
||||||
* PlaylistArchiveVideo class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Alltube;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Video streamed to a PlaylistArchiveStream.
|
|
||||||
*/
|
|
||||||
class PlaylistArchiveVideo
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Video page URL.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has the video been streamed entirely ?
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $complete = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* popen stream containing the video.
|
|
||||||
*
|
|
||||||
* @var resource
|
|
||||||
*/
|
|
||||||
public $stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PlaylistArchiveVideo constructor.
|
|
||||||
*
|
|
||||||
* @param string $url Video page URL
|
|
||||||
*/
|
|
||||||
public function __construct($url)
|
|
||||||
{
|
|
||||||
$this->url = $url;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,13 +6,17 @@
|
||||||
namespace Alltube;
|
namespace Alltube;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Psr7\Response;
|
||||||
use stdClass;
|
use stdClass;
|
||||||
use Symfony\Component\Process\Process;
|
use Symfony\Component\Process\Process;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract info about videos.
|
* Extract info about videos.
|
||||||
|
*
|
||||||
|
* Due to the way youtube-dl, this class can also contain a playlist.
|
||||||
*/
|
*/
|
||||||
class VideoDownload
|
class Video
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Config instance.
|
* Config instance.
|
||||||
|
@ -21,31 +25,38 @@ class VideoDownload
|
||||||
*/
|
*/
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL of the page containing the video
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $webpageUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requested video format
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $requestedFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Password
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $password;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VideoDownload constructor.
|
* VideoDownload constructor.
|
||||||
*
|
*
|
||||||
* @param Config $config Config instance.
|
* @param string $webpageUrl URL of the page containing the video
|
||||||
*
|
* @param string $requestedFormat Requested video format
|
||||||
* @throws Exception If youtube-dl is missing
|
* @param string $password Password
|
||||||
* @throws Exception If Python is missing
|
|
||||||
*/
|
*/
|
||||||
public function __construct(Config $config = null)
|
public function __construct($webpageUrl, $requestedFormat = 'best', $password = null)
|
||||||
{
|
{
|
||||||
if (isset($config)) {
|
$this->webpageUrl = $webpageUrl;
|
||||||
$this->config = $config;
|
$this->requestedFormat = $requestedFormat;
|
||||||
} else {
|
$this->password = $password;
|
||||||
$this->config = Config::getInstance();
|
$this->config = Config::getInstance();
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
We don't translate these exceptions because they always occur before Slim can catch them
|
|
||||||
so they will always go to the logs.
|
|
||||||
*/
|
|
||||||
if (!is_file($this->config->youtubedl)) {
|
|
||||||
throw new Exception("Can't find youtube-dl at ".$this->config->youtubedl);
|
|
||||||
} elseif (!$this->checkCommand([$this->config->python, '--version'])) {
|
|
||||||
throw new Exception("Can't find Python at ".$this->config->python);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a youtube-dl process with the specified arguments.
|
* Return a youtube-dl process with the specified arguments.
|
||||||
|
@ -56,10 +67,11 @@ class VideoDownload
|
||||||
*/
|
*/
|
||||||
private function getProcess(array $arguments)
|
private function getProcess(array $arguments)
|
||||||
{
|
{
|
||||||
|
$config = Config::getInstance();
|
||||||
return new Process(
|
return new Process(
|
||||||
array_merge(
|
array_merge(
|
||||||
[$this->config->python, $this->config->youtubedl],
|
[$config->python, $config->youtubedl],
|
||||||
$this->config->params,
|
$config->params,
|
||||||
$arguments
|
$arguments
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -70,18 +82,15 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @return string[] Extractors
|
* @return string[] Extractors
|
||||||
* */
|
* */
|
||||||
public function listExtractors()
|
public static function getExtractors()
|
||||||
{
|
{
|
||||||
return explode("\n", trim($this->getProp(null, null, 'list-extractors')));
|
return explode("\n", trim(self::getProp('list-extractors')));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a property from youtube-dl.
|
* Get a property from youtube-dl.
|
||||||
*
|
*
|
||||||
* @param string $url URL to parse
|
|
||||||
* @param string $format Format
|
|
||||||
* @param string $prop Property
|
* @param string $prop Property
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @throws PasswordException If the video is protected by a password and no password was specified
|
* @throws PasswordException If the video is protected by a password and no password was specified
|
||||||
* @throws Exception If the password is wrong
|
* @throws Exception If the password is wrong
|
||||||
|
@ -89,23 +98,30 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getProp($url = null, $format = null, $prop = 'dump-json', $password = null)
|
private function getProp($prop = 'dump-json')
|
||||||
{
|
{
|
||||||
|
$config = Config::getInstance();
|
||||||
|
|
||||||
$arguments = ['--'.$prop];
|
$arguments = ['--'.$prop];
|
||||||
if (isset($url)) {
|
|
||||||
$arguments[] = $url;
|
// This function can also be called statically.
|
||||||
|
if (isset($this)) {
|
||||||
|
if (isset($this->webpageUrl)) {
|
||||||
|
$arguments[] = $this->webpageUrl;
|
||||||
}
|
}
|
||||||
if (isset($format)) {
|
if (isset($this->requestedFormat)) {
|
||||||
$arguments[] = '-f '.$format;
|
$arguments[] = '-f';
|
||||||
|
$arguments[] = $this->requestedFormat;
|
||||||
}
|
}
|
||||||
if (isset($password)) {
|
if (isset($this->password)) {
|
||||||
$arguments[] = '--video-password';
|
$arguments[] = '--video-password';
|
||||||
$arguments[] = $password;
|
$arguments[] = $this->password;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$process = $this->getProcess($arguments);
|
$process = self::getProcess($arguments);
|
||||||
//This is needed by the openload extractor because it runs PhantomJS
|
//This is needed by the openload extractor because it runs PhantomJS
|
||||||
$process->setEnv(['PATH'=>$this->config->phantomjsDir]);
|
$process->setEnv(['PATH'=>$config->phantomjsDir]);
|
||||||
$process->inheritEnvironmentVariables();
|
$process->inheritEnvironmentVariables();
|
||||||
$process->run();
|
$process->run();
|
||||||
if (!$process->isSuccessful()) {
|
if (!$process->isSuccessful()) {
|
||||||
|
@ -126,15 +142,41 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get all information about a video.
|
* Get all information about a video.
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
|
||||||
* @return stdClass Decoded JSON
|
* @return stdClass Decoded JSON
|
||||||
* */
|
* */
|
||||||
public function getJSON($url, $format = null, $password = null)
|
public function getJson()
|
||||||
{
|
{
|
||||||
return json_decode($this->getProp($url, $format, 'dump-single-json', $password));
|
if (!isset($this->json)) {
|
||||||
|
$this->json = json_decode($this->getProp('dump-single-json'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->json;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic method to get a property from the JSON object returned by youtube-dl.
|
||||||
|
*
|
||||||
|
* @param string $name Property
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function __get($name)
|
||||||
|
{
|
||||||
|
if (isset($this->$name)) {
|
||||||
|
return $this->getJson()->$name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic method to check if the JSON object returned by youtube-dl has a property.
|
||||||
|
*
|
||||||
|
* @param string $name Property
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function __isset($name)
|
||||||
|
{
|
||||||
|
return isset($this->getJson()->$name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,15 +186,11 @@ class VideoDownload
|
||||||
* But it can return two URLs when multiple formats are specified
|
* But it can return two URLs when multiple formats are specified
|
||||||
* (eg. bestvideo+bestaudio).
|
* (eg. bestvideo+bestaudio).
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
|
||||||
* @return string[] URLs of video
|
* @return string[] URLs of video
|
||||||
* */
|
* */
|
||||||
public function getURL($url, $format = null, $password = null)
|
public function getUrl()
|
||||||
{
|
{
|
||||||
$urls = explode("\n", $this->getProp($url, $format, 'get-url', $password));
|
$urls = explode("\n", $this->getProp('get-url'));
|
||||||
|
|
||||||
if (empty($urls[0])) {
|
if (empty($urls[0])) {
|
||||||
throw new EmptyUrlException(_('youtube-dl returned an empty URL.'));
|
throw new EmptyUrlException(_('youtube-dl returned an empty URL.'));
|
||||||
|
@ -164,32 +202,25 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get filename of video file from URL of page.
|
* Get filename of video file from URL of page.
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
|
||||||
* @return string Filename of extracted video
|
* @return string Filename of extracted video
|
||||||
* */
|
* */
|
||||||
public function getFilename($url, $format = null, $password = null)
|
public function getFilename()
|
||||||
{
|
{
|
||||||
return trim($this->getProp($url, $format, 'get-filename', $password));
|
return trim($this->getProp('get-filename'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get filename of video with the specified extension.
|
* Get filename of video with the specified extension.
|
||||||
*
|
*
|
||||||
* @param string $extension New file extension
|
* @param string $extension New file extension
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @return string Filename of extracted video with specified extension
|
* @return string Filename of extracted video with specified extension
|
||||||
*/
|
*/
|
||||||
public function getFileNameWithExtension($extension, $url, $format = null, $password = null)
|
public function getFileNameWithExtension($extension)
|
||||||
{
|
{
|
||||||
return html_entity_decode(
|
return html_entity_decode(
|
||||||
pathinfo(
|
pathinfo(
|
||||||
$this->getFilename($url, $format, $password),
|
$this->getFilename(),
|
||||||
PATHINFO_FILENAME
|
PATHINFO_FILENAME
|
||||||
).'.'.$extension,
|
).'.'.$extension,
|
||||||
ENT_COMPAT,
|
ENT_COMPAT,
|
||||||
|
@ -197,32 +228,16 @@ class VideoDownload
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get filename of audio from URL of page.
|
|
||||||
*
|
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
|
||||||
* @return string Filename of converted audio file
|
|
||||||
* */
|
|
||||||
public function getAudioFilename($url, $format = null, $password = null)
|
|
||||||
{
|
|
||||||
return $this->getFileNameWithExtension('mp3', $url, $format, $password);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return arguments used to run rtmp for a specific video.
|
* Return arguments used to run rtmp for a specific video.
|
||||||
*
|
*
|
||||||
* @param stdClass $video Video object returned by youtube-dl
|
|
||||||
*
|
|
||||||
* @return array Arguments
|
* @return array Arguments
|
||||||
*/
|
*/
|
||||||
private function getRtmpArguments(stdClass $video)
|
private function getRtmpArguments()
|
||||||
{
|
{
|
||||||
$arguments = [];
|
$arguments = [];
|
||||||
|
|
||||||
if ($video->protocol == 'rtmp') {
|
if ($this->protocol == 'rtmp') {
|
||||||
foreach ([
|
foreach ([
|
||||||
'url' => '-rtmp_tcurl',
|
'url' => '-rtmp_tcurl',
|
||||||
'webpage_url' => '-rtmp_pageurl',
|
'webpage_url' => '-rtmp_pageurl',
|
||||||
|
@ -231,14 +246,14 @@ class VideoDownload
|
||||||
'play_path' => '-rtmp_playpath',
|
'play_path' => '-rtmp_playpath',
|
||||||
'app' => '-rtmp_app',
|
'app' => '-rtmp_app',
|
||||||
] as $property => $option) {
|
] as $property => $option) {
|
||||||
if (isset($video->{$property})) {
|
if (isset($this->{$property})) {
|
||||||
$arguments[] = $option;
|
$arguments[] = $option;
|
||||||
$arguments[] = $video->{$property};
|
$arguments[] = $this->{$property};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($video->rtmp_conn)) {
|
if (isset($this->rtmp_conn)) {
|
||||||
foreach ($video->rtmp_conn as $conn) {
|
foreach ($this->rtmp_conn as $conn) {
|
||||||
$arguments[] = '-rtmp_conn';
|
$arguments[] = '-rtmp_conn';
|
||||||
$arguments[] = $conn;
|
$arguments[] = $conn;
|
||||||
}
|
}
|
||||||
|
@ -255,7 +270,7 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @return bool False if the command returns an error, true otherwise
|
* @return bool False if the command returns an error, true otherwise
|
||||||
*/
|
*/
|
||||||
private function checkCommand(array $command)
|
public static function checkCommand(array $command)
|
||||||
{
|
{
|
||||||
$process = new Process($command);
|
$process = new Process($command);
|
||||||
$process->run();
|
$process->run();
|
||||||
|
@ -266,7 +281,6 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get a process that runs avconv in order to convert a video.
|
* Get a process that runs avconv in order to convert a video.
|
||||||
*
|
*
|
||||||
* @param stdClass $video Video object returned by youtube-dl
|
|
||||||
* @param int $audioBitrate Audio bitrate of the converted file
|
* @param int $audioBitrate Audio bitrate of the converted file
|
||||||
* @param string $filetype Filetype of the converted file
|
* @param string $filetype Filetype of the converted file
|
||||||
* @param bool $audioOnly True to return an audio-only file
|
* @param bool $audioOnly True to return an audio-only file
|
||||||
|
@ -278,7 +292,6 @@ class VideoDownload
|
||||||
* @return Process Process
|
* @return Process Process
|
||||||
*/
|
*/
|
||||||
private function getAvconvProcess(
|
private function getAvconvProcess(
|
||||||
stdClass $video,
|
|
||||||
$audioBitrate,
|
$audioBitrate,
|
||||||
$filetype = 'mp3',
|
$filetype = 'mp3',
|
||||||
$audioOnly = true,
|
$audioOnly = true,
|
||||||
|
@ -317,9 +330,9 @@ class VideoDownload
|
||||||
$this->config->avconv,
|
$this->config->avconv,
|
||||||
'-v', $this->config->avconvVerbosity,
|
'-v', $this->config->avconvVerbosity,
|
||||||
],
|
],
|
||||||
$this->getRtmpArguments($video),
|
$this->getRtmpArguments(),
|
||||||
[
|
[
|
||||||
'-i', $video->url,
|
'-i', $this->url,
|
||||||
'-f', $filetype,
|
'-f', $filetype,
|
||||||
'-b:a', $audioBitrate.'k',
|
'-b:a', $audioBitrate.'k',
|
||||||
],
|
],
|
||||||
|
@ -328,10 +341,10 @@ class VideoDownload
|
||||||
'pipe:1',
|
'pipe:1',
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
if ($video->url != '-') {
|
if ($this->url != '-') {
|
||||||
//Vimeo needs a correct user-agent
|
//Vimeo needs a correct user-agent
|
||||||
$arguments[] = '-user_agent';
|
$arguments[] = '-user_agent';
|
||||||
$arguments[] = $this->getProp(null, null, 'dump-user-agent');
|
$arguments[] = $this->getProp('dump-user-agent');
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Process($arguments);
|
return new Process($arguments);
|
||||||
|
@ -340,34 +353,29 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get audio stream of converted video.
|
* Get audio stream of converted video.
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Format to use for the video
|
|
||||||
* @param string $password Video password
|
|
||||||
* @param string $from Start the conversion at this time
|
* @param string $from Start the conversion at this time
|
||||||
* @param string $to End the conversion at this time
|
* @param string $to End the conversion at this time
|
||||||
*
|
*
|
||||||
* @throws Exception If your try to convert and M3U8 video
|
* @throws Exception If your try to convert an M3U8 video
|
||||||
* @throws Exception If the popen stream was not created correctly
|
* @throws Exception If the popen stream was not created correctly
|
||||||
*
|
*
|
||||||
* @return resource popen stream
|
* @return resource popen stream
|
||||||
*/
|
*/
|
||||||
public function getAudioStream($url, $format, $password = null, $from = null, $to = null)
|
public function getAudioStream($from = null, $to = null)
|
||||||
{
|
{
|
||||||
$video = $this->getJSON($url, $format, $password);
|
if (isset($this->_type) && $this->_type == 'playlist') {
|
||||||
|
|
||||||
if (isset($video->_type) && $video->_type == 'playlist') {
|
|
||||||
throw new Exception(_('Conversion of playlists is not supported.'));
|
throw new Exception(_('Conversion of playlists is not supported.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($video->protocol)) {
|
if (isset($this->protocol)) {
|
||||||
if (in_array($video->protocol, ['m3u8', 'm3u8_native'])) {
|
if (in_array($this->protocol, ['m3u8', 'm3u8_native'])) {
|
||||||
throw new Exception(_('Conversion of M3U8 files is not supported.'));
|
throw new Exception(_('Conversion of M3U8 files is not supported.'));
|
||||||
} elseif ($video->protocol == 'http_dash_segments') {
|
} elseif ($this->protocol == 'http_dash_segments') {
|
||||||
throw new Exception(_('Conversion of DASH segments is not supported.'));
|
throw new Exception(_('Conversion of DASH segments is not supported.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$avconvProc = $this->getAvconvProcess($video, $this->config->audioBitrate, 'mp3', true, $from, $to);
|
$avconvProc = $this->getAvconvProcess($this->config->audioBitrate, 'mp3', true, $from, $to);
|
||||||
|
|
||||||
$stream = popen($avconvProc->getCommandLine(), 'r');
|
$stream = popen($avconvProc->getCommandLine(), 'r');
|
||||||
|
|
||||||
|
@ -381,14 +389,12 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get video stream from an M3U playlist.
|
* Get video stream from an M3U playlist.
|
||||||
*
|
*
|
||||||
* @param stdClass $video Video object returned by getJSON
|
|
||||||
*
|
|
||||||
* @throws Exception If avconv/ffmpeg is missing
|
* @throws Exception If avconv/ffmpeg is missing
|
||||||
* @throws Exception If the popen stream was not created correctly
|
* @throws Exception If the popen stream was not created correctly
|
||||||
*
|
*
|
||||||
* @return resource popen stream
|
* @return resource popen stream
|
||||||
*/
|
*/
|
||||||
public function getM3uStream(stdClass $video)
|
public function getM3uStream()
|
||||||
{
|
{
|
||||||
if (!$this->checkCommand([$this->config->avconv, '-version'])) {
|
if (!$this->checkCommand([$this->config->avconv, '-version'])) {
|
||||||
throw new Exception(_('Can\'t find avconv or ffmpeg at ').$this->config->avconv.'.');
|
throw new Exception(_('Can\'t find avconv or ffmpeg at ').$this->config->avconv.'.');
|
||||||
|
@ -398,8 +404,8 @@ class VideoDownload
|
||||||
[
|
[
|
||||||
$this->config->avconv,
|
$this->config->avconv,
|
||||||
'-v', $this->config->avconvVerbosity,
|
'-v', $this->config->avconvVerbosity,
|
||||||
'-i', $video->url,
|
'-i', $this->url,
|
||||||
'-f', $video->ext,
|
'-f', $this->ext,
|
||||||
'-c', 'copy',
|
'-c', 'copy',
|
||||||
'-bsf:a', 'aac_adtstoasc',
|
'-bsf:a', 'aac_adtstoasc',
|
||||||
'-movflags', 'frag_keyframe+empty_moov',
|
'-movflags', 'frag_keyframe+empty_moov',
|
||||||
|
@ -418,14 +424,18 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get an avconv stream to remux audio and video.
|
* Get an avconv stream to remux audio and video.
|
||||||
*
|
*
|
||||||
* @param array $urls URLs of the video ($urls[0]) and audio ($urls[1]) files
|
|
||||||
*
|
|
||||||
* @throws Exception If the popen stream was not created correctly
|
* @throws Exception If the popen stream was not created correctly
|
||||||
*
|
*
|
||||||
* @return resource popen stream
|
* @return resource popen stream
|
||||||
*/
|
*/
|
||||||
public function getRemuxStream(array $urls)
|
public function getRemuxStream()
|
||||||
{
|
{
|
||||||
|
$urls = $this->getUrl();
|
||||||
|
|
||||||
|
if (!isset($urls[0]) || !isset($urls[1])) {
|
||||||
|
throw new Exception(_('This video does not have two URLs.'));
|
||||||
|
}
|
||||||
|
|
||||||
$process = new Process(
|
$process = new Process(
|
||||||
[
|
[
|
||||||
$this->config->avconv,
|
$this->config->avconv,
|
||||||
|
@ -451,13 +461,11 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get video stream from an RTMP video.
|
* Get video stream from an RTMP video.
|
||||||
*
|
*
|
||||||
* @param stdClass $video Video object returned by getJSON
|
|
||||||
*
|
|
||||||
* @throws Exception If the popen stream was not created correctly
|
* @throws Exception If the popen stream was not created correctly
|
||||||
*
|
*
|
||||||
* @return resource popen stream
|
* @return resource popen stream
|
||||||
*/
|
*/
|
||||||
public function getRtmpStream(stdClass $video)
|
public function getRtmpStream()
|
||||||
{
|
{
|
||||||
$process = new Process(
|
$process = new Process(
|
||||||
array_merge(
|
array_merge(
|
||||||
|
@ -465,10 +473,10 @@ class VideoDownload
|
||||||
$this->config->avconv,
|
$this->config->avconv,
|
||||||
'-v', $this->config->avconvVerbosity,
|
'-v', $this->config->avconvVerbosity,
|
||||||
],
|
],
|
||||||
$this->getRtmpArguments($video),
|
$this->getRtmpArguments(),
|
||||||
[
|
[
|
||||||
'-i', $video->url,
|
'-i', $this->url,
|
||||||
'-f', $video->ext,
|
'-f', $this->ext,
|
||||||
'pipe:1',
|
'pipe:1',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -484,25 +492,21 @@ class VideoDownload
|
||||||
/**
|
/**
|
||||||
* Get the stream of a converted video.
|
* Get the stream of a converted video.
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
|
||||||
* @param string $format Source format to use for the conversion
|
|
||||||
* @param int $audioBitrate Audio bitrate of the converted file
|
* @param int $audioBitrate Audio bitrate of the converted file
|
||||||
* @param string $filetype Filetype of the converted file
|
* @param string $filetype Filetype of the converted file
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @throws Exception If your try to convert and M3U8 video
|
* @throws Exception If your try to convert and M3U8 video
|
||||||
* @throws Exception If the popen stream was not created correctly
|
* @throws Exception If the popen stream was not created correctly
|
||||||
*
|
*
|
||||||
* @return resource popen stream
|
* @return resource popen stream
|
||||||
*/
|
*/
|
||||||
public function getConvertedStream($url, $format, $audioBitrate, $filetype, $password = null)
|
public function getConvertedStream($audioBitrate, $filetype)
|
||||||
{
|
{
|
||||||
$video = $this->getJSON($url, $format, $password);
|
if (in_array($this->protocol, ['m3u8', 'm3u8_native'])) {
|
||||||
if (in_array($video->protocol, ['m3u8', 'm3u8_native'])) {
|
|
||||||
throw new Exception(_('Conversion of M3U8 files is not supported.'));
|
throw new Exception(_('Conversion of M3U8 files is not supported.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$avconvProc = $this->getAvconvProcess($video, $audioBitrate, $filetype, false);
|
$avconvProc = $this->getAvconvProcess($audioBitrate, $filetype, false);
|
||||||
|
|
||||||
$stream = popen($avconvProc->getCommandLine(), 'r');
|
$stream = popen($avconvProc->getCommandLine(), 'r');
|
||||||
|
|
||||||
|
@ -512,4 +516,29 @@ class VideoDownload
|
||||||
|
|
||||||
return $stream;
|
return $stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the same video but with another format.
|
||||||
|
*
|
||||||
|
* @param string $format New format
|
||||||
|
*
|
||||||
|
* @return Video
|
||||||
|
*/
|
||||||
|
public function withFormat($format)
|
||||||
|
{
|
||||||
|
return new Video($this->webpageUrl, $format, $this->password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a HTTP response containing the video.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function getHttpResponse()
|
||||||
|
{
|
||||||
|
$client = new Client();
|
||||||
|
$urls = $this->getUrl();
|
||||||
|
|
||||||
|
return $client->request('GET', $urls[0], ['stream' => true]);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ use Alltube\Locale;
|
||||||
use Alltube\LocaleManager;
|
use Alltube\LocaleManager;
|
||||||
use Alltube\PasswordException;
|
use Alltube\PasswordException;
|
||||||
use Alltube\PlaylistArchiveStream;
|
use Alltube\PlaylistArchiveStream;
|
||||||
use Alltube\VideoDownload;
|
use Alltube\Video;
|
||||||
use Aura\Session\Segment;
|
use Aura\Session\Segment;
|
||||||
use Aura\Session\SessionFactory;
|
use Aura\Session\SessionFactory;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
@ -36,11 +36,11 @@ class FrontController
|
||||||
private $config;
|
private $config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* VideoDownload instance.
|
* Current video.
|
||||||
*
|
*
|
||||||
* @var VideoDownload
|
* @var Video
|
||||||
*/
|
*/
|
||||||
private $download;
|
private $video;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slim dependency container.
|
* Slim dependency container.
|
||||||
|
@ -81,17 +81,11 @@ class FrontController
|
||||||
* FrontController constructor.
|
* FrontController constructor.
|
||||||
*
|
*
|
||||||
* @param ContainerInterface $container Slim dependency container
|
* @param ContainerInterface $container Slim dependency container
|
||||||
* @param Config $config Config instance
|
|
||||||
* @param array $cookies Cookie array
|
* @param array $cookies Cookie array
|
||||||
*/
|
*/
|
||||||
public function __construct(ContainerInterface $container, Config $config = null, array $cookies = [])
|
public function __construct(ContainerInterface $container, array $cookies = [])
|
||||||
{
|
{
|
||||||
if (isset($config)) {
|
|
||||||
$this->config = $config;
|
|
||||||
} else {
|
|
||||||
$this->config = Config::getInstance();
|
$this->config = Config::getInstance();
|
||||||
}
|
|
||||||
$this->download = new VideoDownload($this->config);
|
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
$this->view = $this->container->get('view');
|
$this->view = $this->container->get('view');
|
||||||
$this->localeManager = $this->container->get('locale');
|
$this->localeManager = $this->container->get('locale');
|
||||||
|
@ -162,7 +156,7 @@ class FrontController
|
||||||
'extractors.tpl',
|
'extractors.tpl',
|
||||||
[
|
[
|
||||||
'config' => $this->config,
|
'config' => $this->config,
|
||||||
'extractors' => $this->download->listExtractors(),
|
'extractors' => Video::getExtractors(),
|
||||||
'class' => 'extractors',
|
'class' => 'extractors',
|
||||||
'title' => _('Supported websites'),
|
'title' => _('Supported websites'),
|
||||||
'description' => _('List of all supported websites from which Alltube Download '.
|
'description' => _('List of all supported websites from which Alltube Download '.
|
||||||
|
@ -206,44 +200,28 @@ class FrontController
|
||||||
*
|
*
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param array $params GET query parameters
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getConvertedAudioResponse(Request $request, Response $response, array $params, $password = null)
|
private function getConvertedAudioResponse(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
if (!isset($params['from'])) {
|
$from = $request->getQueryParam('from');
|
||||||
$params['from'] = '';
|
$to = $request->getQueryParam('to');
|
||||||
}
|
|
||||||
if (!isset($params['to'])) {
|
|
||||||
$params['to'] = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $response->withHeader(
|
$response = $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="'.
|
'attachment; filename="'.
|
||||||
$this->download->getAudioFilename($params['url'], 'bestaudio/best', $password).'"'
|
$this->video->getFileNameWithExtension('mp3').'"'
|
||||||
);
|
);
|
||||||
$response = $response->withHeader('Content-Type', 'audio/mpeg');
|
$response = $response->withHeader('Content-Type', 'audio/mpeg');
|
||||||
|
|
||||||
if ($request->isGet() || $request->isPost()) {
|
if ($request->isGet() || $request->isPost()) {
|
||||||
try {
|
try {
|
||||||
$process = $this->download->getAudioStream(
|
$process = $this->video->getAudioStream($from, $to);
|
||||||
$params['url'],
|
|
||||||
'bestaudio/best',
|
|
||||||
$password,
|
|
||||||
$params['from'],
|
|
||||||
$params['to']
|
|
||||||
);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$process = $this->download->getAudioStream(
|
// Fallback to default format.
|
||||||
$params['url'],
|
$this->video = $this->video->withFormat($this->defaultFormat);
|
||||||
$this->defaultFormat,
|
$process = $this->video->getAudioStream($from, $to);
|
||||||
$password,
|
|
||||||
$params['from'],
|
|
||||||
$params['to']
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
$response = $response->withBody(new Stream($process));
|
$response = $response->withBody(new Stream($process));
|
||||||
}
|
}
|
||||||
|
@ -256,31 +234,35 @@ class FrontController
|
||||||
*
|
*
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param array $params GET query parameters
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getAudioResponse(Request $request, Response $response, array $params, $password = null)
|
private function getAudioResponse(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if ((isset($params['from']) && !empty($params['from']))
|
// First, we try to get a MP3 file directly.
|
||||||
|| (isset($params['to']) && !empty($params['to']))
|
if (!empty($request->getQueryParam('from')) || !empty($request->getQueryParam('to'))) {
|
||||||
) {
|
|
||||||
throw new Exception('Force convert when we need to seek.');
|
throw new Exception('Force convert when we need to seek.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->config->stream) {
|
if ($this->config->stream) {
|
||||||
return $this->getStream($params['url'], 'mp3', $response, $request, $password);
|
$this->video = $this->video->withFormat('mp3');
|
||||||
|
|
||||||
|
return $this->getStream($request, $response);
|
||||||
} else {
|
} else {
|
||||||
$urls = $this->download->getURL($params['url'], 'mp3[protocol=https]/mp3[protocol=http]', $password);
|
$this->video = $this->video->withFormat('mp3[protocol=https]/mp3[protocol=http]');
|
||||||
|
|
||||||
|
$urls = $this->video->getUrl();
|
||||||
|
|
||||||
return $response->withRedirect($urls[0]);
|
return $response->withRedirect($urls[0]);
|
||||||
}
|
}
|
||||||
} catch (PasswordException $e) {
|
} catch (PasswordException $e) {
|
||||||
return $this->password($request, $response);
|
return $this->password($request, $response);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return $this->getConvertedAudioResponse($request, $response, $params, $password);
|
// If MP3 is not available, we convert it.
|
||||||
|
$this->video = $this->video->withFormat($this->defaultFormat);
|
||||||
|
|
||||||
|
return $this->getConvertedAudioResponse($request, $response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,35 +271,33 @@ class FrontController
|
||||||
*
|
*
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param array $params GET query parameters
|
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getVideoResponse(Request $request, Response $response, array $params, $password = null)
|
private function getVideoResponse(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$video = $this->download->getJSON($params['url'], $this->defaultFormat, $password);
|
$this->video->getJson();
|
||||||
} catch (PasswordException $e) {
|
} catch (PasswordException $e) {
|
||||||
return $this->password($request, $response);
|
return $this->password($request, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($video->entries)) {
|
if (isset($this->video->entries)) {
|
||||||
$template = 'playlist.tpl';
|
$template = 'playlist.tpl';
|
||||||
} else {
|
} else {
|
||||||
$template = 'video.tpl';
|
$template = 'video.tpl';
|
||||||
}
|
}
|
||||||
$title = _('Video download');
|
$title = _('Video download');
|
||||||
$description = _('Download video from ').$video->extractor_key;
|
$description = _('Download video from ').$this->video->extractor_key;
|
||||||
if (isset($video->title)) {
|
if (isset($this->video->title)) {
|
||||||
$title = $video->title;
|
$title = $this->video->title;
|
||||||
$description = _('Download').' "'.$video->title.'" '._('from').' '.$video->extractor_key;
|
$description = _('Download').' "'.$this->video->title.'" '._('from').' '.$this->video->extractor_key;
|
||||||
}
|
}
|
||||||
$this->view->render(
|
$this->view->render(
|
||||||
$response,
|
$response,
|
||||||
$template,
|
$template,
|
||||||
[
|
[
|
||||||
'video' => $video,
|
'video' => $this->video,
|
||||||
'class' => 'video',
|
'class' => 'video',
|
||||||
'title' => $title,
|
'title' => $title,
|
||||||
'description' => $description,
|
'description' => $description,
|
||||||
|
@ -341,21 +321,20 @@ class FrontController
|
||||||
*/
|
*/
|
||||||
public function video(Request $request, Response $response)
|
public function video(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$params = $request->getQueryParams();
|
$url = $request->getQueryParam('url') ?: $request->getQueryParam('v');
|
||||||
|
|
||||||
if (!isset($params['url']) && isset($params['v'])) {
|
if (isset($url) && !empty($url)) {
|
||||||
$params['url'] = $params['v'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($params['url']) && !empty($params['url'])) {
|
|
||||||
$password = $request->getParam('password');
|
$password = $request->getParam('password');
|
||||||
if (isset($password)) {
|
if (isset($password)) {
|
||||||
$this->sessionSegment->setFlash($params['url'], $password);
|
$this->sessionSegment->setFlash($url, $password);
|
||||||
}
|
}
|
||||||
if (isset($params['audio'])) {
|
|
||||||
return $this->getAudioResponse($request, $response, $params, $password);
|
$this->video = new Video($url, $this->defaultFormat, $password);
|
||||||
|
|
||||||
|
if ($request->getQueryParam('audio')) {
|
||||||
|
return $this->getAudioResponse($request, $response);
|
||||||
} else {
|
} else {
|
||||||
return $this->getVideoResponse($request, $response, $params, $password);
|
return $this->getVideoResponse($request, $response);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return $response->withRedirect($this->container->get('router')->pathFor('index'));
|
return $response->withRedirect($this->container->get('router')->pathFor('index'));
|
||||||
|
@ -392,39 +371,33 @@ class FrontController
|
||||||
/**
|
/**
|
||||||
* Get a video/audio stream piped through the server.
|
* Get a video/audio stream piped through the server.
|
||||||
*
|
*
|
||||||
* @param string $url URL of the video
|
|
||||||
* @param string $format Requested format
|
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
* @param string $password Video password
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getStream($url, $format, Response $response, Request $request, $password = null)
|
private function getStream(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$video = $this->download->getJSON($url, $format, $password);
|
if (isset($this->video->entries)) {
|
||||||
if (isset($video->entries)) {
|
$stream = new PlaylistArchiveStream($this->video);
|
||||||
$stream = new PlaylistArchiveStream($this->config, $video, $format);
|
|
||||||
$response = $response->withHeader('Content-Type', 'application/x-tar');
|
$response = $response->withHeader('Content-Type', 'application/x-tar');
|
||||||
$response = $response->withHeader(
|
$response = $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="'.$video->title.'.tar"'
|
'attachment; filename="'.$this->video->title.'.tar"'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $response->withBody($stream);
|
return $response->withBody($stream);
|
||||||
} elseif ($video->protocol == 'rtmp') {
|
} elseif ($this->video->protocol == 'rtmp') {
|
||||||
$stream = $this->download->getRtmpStream($video);
|
$response = $response->withHeader('Content-Type', 'video/'.$this->video->ext);
|
||||||
$response = $response->withHeader('Content-Type', 'video/'.$video->ext);
|
$body = new Stream($this->video->getRtmpStream());
|
||||||
$body = new Stream($stream);
|
} elseif ($this->video->protocol == 'm3u8' || $this->video->protocol == 'm3u8_native') {
|
||||||
} elseif ($video->protocol == 'm3u8' || $video->protocol == 'm3u8_native') {
|
$response = $response->withHeader('Content-Type', 'video/'.$this->video->ext);
|
||||||
$stream = $this->download->getM3uStream($video);
|
$body = new Stream($this->video->getM3uStream());
|
||||||
$response = $response->withHeader('Content-Type', 'video/'.$video->ext);
|
|
||||||
$body = new Stream($stream);
|
|
||||||
} else {
|
} else {
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
$stream = $client->request(
|
$stream = $client->request(
|
||||||
'GET',
|
'GET',
|
||||||
$video->url,
|
$this->video->url,
|
||||||
[
|
[
|
||||||
'stream' => true,
|
'stream' => true,
|
||||||
'headers' => ['Range' => $request->getHeader('Range')],
|
'headers' => ['Range' => $request->getHeader('Range')],
|
||||||
|
@ -445,7 +418,7 @@ class FrontController
|
||||||
$response = $response->withHeader(
|
$response = $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="'.
|
'attachment; filename="'.
|
||||||
$this->download->getFilename($url, $format, $password).'"'
|
$this->video->getFilename().'"'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
|
@ -454,19 +427,17 @@ class FrontController
|
||||||
/**
|
/**
|
||||||
* Get a remuxed stream piped through the server.
|
* Get a remuxed stream piped through the server.
|
||||||
*
|
*
|
||||||
* @param string[] $urls URLs of the video and audio files
|
|
||||||
* @param string $format Requested format
|
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getRemuxStream(array $urls, $format, Response $response, Request $request)
|
private function getRemuxStream(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
if (!$this->config->remux) {
|
if (!$this->config->remux) {
|
||||||
throw new Exception(_('You need to enable remux mode to merge two formats.'));
|
throw new Exception(_('You need to enable remux mode to merge two formats.'));
|
||||||
}
|
}
|
||||||
$stream = $this->download->getRemuxStream($urls);
|
$stream = $this->video->getRemuxStream();
|
||||||
$response = $response->withHeader('Content-Type', 'video/x-matroska');
|
$response = $response->withHeader('Content-Type', 'video/x-matroska');
|
||||||
if ($request->isGet()) {
|
if ($request->isGet()) {
|
||||||
$response = $response->withBody(new Stream($stream));
|
$response = $response->withBody(new Stream($stream));
|
||||||
|
@ -475,12 +446,7 @@ class FrontController
|
||||||
|
|
||||||
return $response->withHeader(
|
return $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="'.$this->download->getFileNameWithExtension(
|
'attachment; filename="'.$this->video->getFileNameWithExtension('mkv')
|
||||||
'mkv',
|
|
||||||
$webpageUrl,
|
|
||||||
$format,
|
|
||||||
$this->sessionSegment->getFlash($webpageUrl)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,21 +471,15 @@ class FrontController
|
||||||
* Get approriate HTTP response to redirect query
|
* Get approriate HTTP response to redirect query
|
||||||
* Depends on whether we want to stream, remux or simply redirect.
|
* Depends on whether we want to stream, remux or simply redirect.
|
||||||
*
|
*
|
||||||
* @param string $url URL of the video
|
|
||||||
* @param string $format Requested format
|
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getRedirectResponse($url, $format, Response $response, Request $request)
|
private function getRedirectResponse(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$videoUrls = $this->download->getURL(
|
$videoUrls = $this->video->getUrl();
|
||||||
$url,
|
|
||||||
$format,
|
|
||||||
$this->sessionSegment->getFlash($url)
|
|
||||||
);
|
|
||||||
} catch (EmptyUrlException $e) {
|
} catch (EmptyUrlException $e) {
|
||||||
/*
|
/*
|
||||||
If this happens it is probably a playlist
|
If this happens it is probably a playlist
|
||||||
|
@ -528,15 +488,9 @@ class FrontController
|
||||||
$videoUrls = [];
|
$videoUrls = [];
|
||||||
}
|
}
|
||||||
if (count($videoUrls) > 1) {
|
if (count($videoUrls) > 1) {
|
||||||
return $this->getRemuxStream($videoUrls, $format, $response, $request);
|
return $this->getRemuxStream($request, $response);
|
||||||
} elseif ($this->config->stream) {
|
} elseif ($this->config->stream) {
|
||||||
return $this->getStream(
|
return $this->getStream($request, $response);
|
||||||
$url,
|
|
||||||
$format,
|
|
||||||
$response,
|
|
||||||
$request,
|
|
||||||
$this->sessionSegment->getFlash($url)
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
if (empty($videoUrls[0])) {
|
if (empty($videoUrls[0])) {
|
||||||
throw new Exception(_("Can't find URL of video."));
|
throw new Exception(_("Can't find URL of video."));
|
||||||
|
@ -551,33 +505,22 @@ class FrontController
|
||||||
*
|
*
|
||||||
* @param Request $request PSR-7 request
|
* @param Request $request PSR-7 request
|
||||||
* @param Response $response PSR-7 response
|
* @param Response $response PSR-7 response
|
||||||
* @param array $params GET query parameters
|
|
||||||
* @param string $format Requested source format
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getConvertedResponse(Request $request, Response $response, array $params, $format)
|
private function getConvertedResponse(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$password = $request->getParam('password');
|
|
||||||
$response = $response->withHeader(
|
$response = $response->withHeader(
|
||||||
'Content-Disposition',
|
'Content-Disposition',
|
||||||
'attachment; filename="'.
|
'attachment; filename="'.
|
||||||
$this->download->getFileNameWithExtension(
|
$this->video->getFileNameWithExtension($request->getQueryParam('customFormat')).'"'
|
||||||
$params['customFormat'],
|
|
||||||
$params['url'],
|
|
||||||
$format,
|
|
||||||
$password
|
|
||||||
).'"'
|
|
||||||
);
|
);
|
||||||
$response = $response->withHeader('Content-Type', 'video/'.$params['customFormat']);
|
$response = $response->withHeader('Content-Type', 'video/'.$request->getQueryParam('customFormat'));
|
||||||
|
|
||||||
if ($request->isGet() || $request->isPost()) {
|
if ($request->isGet() || $request->isPost()) {
|
||||||
$process = $this->download->getConvertedStream(
|
$process = $this->video->getConvertedStream(
|
||||||
$params['url'],
|
$request->getQueryParam('customBitrate'),
|
||||||
$format,
|
$request->getQueryParam('customFormat')
|
||||||
$params['customBitrate'],
|
|
||||||
$params['customFormat'],
|
|
||||||
$password
|
|
||||||
);
|
);
|
||||||
$response = $response->withBody(new Stream($process));
|
$response = $response->withBody(new Stream($process));
|
||||||
}
|
}
|
||||||
|
@ -595,18 +538,21 @@ class FrontController
|
||||||
*/
|
*/
|
||||||
public function redirect(Request $request, Response $response)
|
public function redirect(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$params = $request->getQueryParams();
|
|
||||||
$format = $this->getFormat($request);
|
$format = $this->getFormat($request);
|
||||||
if (isset($params['url'])) {
|
$url = $request->getQueryParam('url');
|
||||||
|
|
||||||
|
if (isset($url)) {
|
||||||
|
$this->video = new Video($url, $format, $this->sessionSegment->getFlash($url));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->config->convertAdvanced && !is_null($request->getQueryParam('customConvert'))) {
|
if ($this->config->convertAdvanced && !is_null($request->getQueryParam('customConvert'))) {
|
||||||
return $this->getConvertedResponse($request, $response, $params, $format);
|
return $this->getConvertedResponse($request, $response);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getRedirectResponse($params['url'], $format, $response, $request);
|
return $this->getRedirectResponse($request, $response);
|
||||||
} catch (PasswordException $e) {
|
} catch (PasswordException $e) {
|
||||||
return $response->withRedirect(
|
return $response->withRedirect(
|
||||||
$this->container->get('router')->pathFor('video').'?url='.urlencode($params['url'])
|
$this->container->get('router')->pathFor('video').'?url='.urlencode($url)
|
||||||
);
|
);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$response->getBody()->write($e->getMessage());
|
$response->getBody()->write($e->getMessage());
|
||||||
|
@ -628,16 +574,14 @@ class FrontController
|
||||||
*/
|
*/
|
||||||
public function json(Request $request, Response $response)
|
public function json(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$params = $request->getQueryParams();
|
|
||||||
$format = $this->getFormat($request);
|
$format = $this->getFormat($request);
|
||||||
if (isset($params['url'])) {
|
$url = $request->getQueryParam('url');
|
||||||
|
|
||||||
|
if (isset($url)) {
|
||||||
try {
|
try {
|
||||||
return $response->withJson(
|
$this->video = new Video($url, $format);
|
||||||
$this->download->getJSON(
|
|
||||||
$params['url'],
|
return $response->withJson($this->video->getJson());
|
||||||
$format
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return $response->withJson(['error' => $e->getMessage()])
|
return $response->withJson(['error' => $e->getMessage()])
|
||||||
->withStatus(500);
|
->withStatus(500);
|
||||||
|
|
|
@ -14,6 +14,10 @@ if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '/index.ph
|
||||||
die;
|
die;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_file(__DIR__.'/config/config.yml')) {
|
||||||
|
Config::setFile(__DIR__.'/config/config.yml');
|
||||||
|
}
|
||||||
|
|
||||||
$app = new App();
|
$app = new App();
|
||||||
$container = $app->getContainer();
|
$container = $app->getContainer();
|
||||||
$config = Config::getInstance();
|
$config = Config::getInstance();
|
||||||
|
@ -28,7 +32,7 @@ if (!class_exists('Locale')) {
|
||||||
$container['locale'] = new LocaleManager($_COOKIE);
|
$container['locale'] = new LocaleManager($_COOKIE);
|
||||||
$app->add(new LocaleMiddleware($container));
|
$app->add(new LocaleMiddleware($container));
|
||||||
|
|
||||||
$controller = new FrontController($container, null, $_COOKIE);
|
$controller = new FrontController($container, $_COOKIE);
|
||||||
|
|
||||||
$container['errorHandler'] = [$controller, 'error'];
|
$container['errorHandler'] = [$controller, 'error'];
|
||||||
|
|
||||||
|
|
42
tests/BaseTest.php
Normal file
42
tests/BaseTest.php
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PlaylistArchiveStreamTest class.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Alltube\Test;
|
||||||
|
|
||||||
|
use Alltube\Config;
|
||||||
|
use Alltube\Video;
|
||||||
|
use Alltube\PlaylistArchiveStream;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use RuntimeException;
|
||||||
|
use stdClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the ViewFactory class.
|
||||||
|
*/
|
||||||
|
abstract class BaseTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare tests.
|
||||||
|
*/
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
if (PHP_OS == 'WINNT') {
|
||||||
|
$configFile = 'config_test_windows.yml';
|
||||||
|
} else {
|
||||||
|
$configFile = 'config_test.yml';
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::setFile(__DIR__.'/../config/'.$configFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy properties after test.
|
||||||
|
*/
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
Config::destroyInstance();
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,7 @@ use PHPUnit\Framework\TestCase;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the Config class.
|
* Unit tests for the Config class.
|
||||||
*/
|
*/
|
||||||
class ConfigTest extends TestCase
|
class ConfigTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Config class instance.
|
* Config class instance.
|
||||||
|
@ -25,17 +25,7 @@ class ConfigTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
$this->config = Config::getInstance('config/config_test.yml');
|
$this->config = Config::getInstance();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy variables created by setUp().
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
Config::destroyInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,27 +60,79 @@ class ConfigTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the getInstance function with a missing config file.
|
* Test the setFile function.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSetFile()
|
||||||
|
{
|
||||||
|
if (PHP_OS == 'WINNT') {
|
||||||
|
$configFile = 'config_test_windows.yml';
|
||||||
|
} else {
|
||||||
|
$configFile = 'config_test.yml';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertNull(Config::setFile(__DIR__.'/../config/'.$configFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the setFile function with a missing config file.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException Exception
|
* @expectedException Exception
|
||||||
*/
|
*/
|
||||||
public function testGetInstanceWithMissingFile()
|
public function testSetFileWithMissingFile()
|
||||||
{
|
{
|
||||||
Config::getInstance('foo');
|
Config::setFile('foo');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the getInstance function with an empty filename.
|
* Test the setOptions function.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function testGetInstanceWithEmptyFile()
|
public function testSetOptions()
|
||||||
{
|
{
|
||||||
$config = Config::getInstance('');
|
Config::setOptions(['appName' => 'foo']);
|
||||||
$this->assertConfig($config);
|
$config = Config::getInstance();
|
||||||
|
$this->assertEquals($config->appName, 'foo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the setOptions function.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testSetOptionsWithoutUpdate()
|
||||||
|
{
|
||||||
|
Config::setOptions(['appName' => 'foo'], false);
|
||||||
|
$config = Config::getInstance();
|
||||||
|
$this->assertEquals($config->appName, 'foo');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the setOptions function.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @expectedException Exception
|
||||||
|
*/
|
||||||
|
public function testSetOptionsWithBadYoutubedl()
|
||||||
|
{
|
||||||
|
Config::setOptions(['youtubedl' => 'foo']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the setOptions function.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @expectedException Exception
|
||||||
|
*/
|
||||||
|
public function testSetOptionsWithBadPython()
|
||||||
|
{
|
||||||
|
Config::setOptions(['python' => 'foo']);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the getInstance function with the CONVERT and PYTHON environment variables.
|
* Test the getInstance function with the CONVERT and PYTHON environment variables.
|
||||||
*
|
*
|
||||||
|
@ -100,11 +142,8 @@ class ConfigTest extends TestCase
|
||||||
{
|
{
|
||||||
Config::destroyInstance();
|
Config::destroyInstance();
|
||||||
putenv('CONVERT=1');
|
putenv('CONVERT=1');
|
||||||
putenv('PYTHON=foo');
|
$config = Config::getInstance();
|
||||||
$config = Config::getInstance('config/config_test.yml');
|
|
||||||
$this->assertEquals($config->convert, true);
|
$this->assertEquals($config->convert, true);
|
||||||
$this->assertEquals($config->python, 'foo');
|
|
||||||
putenv('CONVERT');
|
putenv('CONVERT');
|
||||||
putenv('PYTHON');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ use Slim\Http\Response;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the FrontController class.
|
* Unit tests for the FrontController class.
|
||||||
*/
|
*/
|
||||||
class FrontControllerTest extends TestCase
|
class FrontControllerTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Slim dependency container.
|
* Slim dependency container.
|
||||||
|
@ -61,19 +61,15 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
$this->container = new Container();
|
$this->container = new Container();
|
||||||
$this->request = Request::createFromEnvironment(Environment::mock());
|
$this->request = Request::createFromEnvironment(Environment::mock());
|
||||||
$this->response = new Response();
|
$this->response = new Response();
|
||||||
$this->container['view'] = ViewFactory::create($this->container, $this->request);
|
$this->container['view'] = ViewFactory::create($this->container, $this->request);
|
||||||
$this->container['locale'] = new LocaleManager();
|
$this->container['locale'] = new LocaleManager();
|
||||||
|
|
||||||
if (PHP_OS == 'WINNT') {
|
$this->controller = new FrontController($this->container);
|
||||||
$configFile = 'config_test_windows.yml';
|
|
||||||
} else {
|
|
||||||
$configFile = 'config_test.yml';
|
|
||||||
}
|
|
||||||
$this->config = Config::getInstance('config/'.$configFile);
|
|
||||||
$this->controller = new FrontController($this->container, $this->config);
|
|
||||||
|
|
||||||
$this->container['router']->map(['GET'], '/', [$this->controller, 'index'])
|
$this->container['router']->map(['GET'], '/', [$this->controller, 'index'])
|
||||||
->setName('index');
|
->setName('index');
|
||||||
|
@ -87,32 +83,17 @@ class FrontControllerTest extends TestCase
|
||||||
->setName('locale');
|
->setName('locale');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy properties after test.
|
|
||||||
*/
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
Config::destroyInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run controller function with custom query parameters and return the result.
|
* Run controller function with custom query parameters and return the result.
|
||||||
*
|
*
|
||||||
* @param string $request Controller function to call
|
* @param string $request Controller function to call
|
||||||
* @param array $params Query parameters
|
* @param array $params Query parameters
|
||||||
* @param Config $config Custom config
|
|
||||||
*
|
*
|
||||||
* @return Response HTTP response
|
* @return Response HTTP response
|
||||||
*/
|
*/
|
||||||
private function getRequestResult($request, array $params, Config $config = null)
|
private function getRequestResult($request, array $params)
|
||||||
{
|
{
|
||||||
if (isset($config)) {
|
return $this->controller->$request(
|
||||||
$controller = new FrontController($this->container, $config);
|
|
||||||
} else {
|
|
||||||
$controller = $this->controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $controller->$request(
|
|
||||||
$this->request->withQueryParams($params),
|
$this->request->withQueryParams($params),
|
||||||
$this->response
|
$this->response
|
||||||
);
|
);
|
||||||
|
@ -123,13 +104,12 @@ class FrontControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @param string $request Controller function to call
|
* @param string $request Controller function to call
|
||||||
* @param array $params Query parameters
|
* @param array $params Query parameters
|
||||||
* @param Config $config Custom config
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assertRequestIsOk($request, array $params = [], Config $config = null)
|
private function assertRequestIsOk($request, array $params = [])
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->getRequestResult($request, $params, $config)->isOk());
|
$this->assertTrue($this->getRequestResult($request, $params)->isOk());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,13 +117,12 @@ class FrontControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @param string $request Controller function to call
|
* @param string $request Controller function to call
|
||||||
* @param array $params Query parameters
|
* @param array $params Query parameters
|
||||||
* @param Config $config Custom config
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assertRequestIsRedirect($request, array $params = [], Config $config = null)
|
private function assertRequestIsRedirect($request, array $params = [])
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->getRequestResult($request, $params, $config)->isRedirect());
|
$this->assertTrue($this->getRequestResult($request, $params)->isRedirect());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -151,13 +130,12 @@ class FrontControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @param string $request Controller function to call
|
* @param string $request Controller function to call
|
||||||
* @param array $params Query parameters
|
* @param array $params Query parameters
|
||||||
* @param Config $config Custom config
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assertRequestIsServerError($request, array $params = [], Config $config = null)
|
private function assertRequestIsServerError($request, array $params = [])
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->getRequestResult($request, $params, $config)->isServerError());
|
$this->assertTrue($this->getRequestResult($request, $params)->isServerError());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -165,13 +143,12 @@ class FrontControllerTest extends TestCase
|
||||||
*
|
*
|
||||||
* @param string $request Controller function to call
|
* @param string $request Controller function to call
|
||||||
* @param array $params Query parameters
|
* @param array $params Query parameters
|
||||||
* @param Config $config Custom config
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
private function assertRequestIsClientError($request, array $params = [], Config $config = null)
|
private function assertRequestIsClientError($request, array $params = [])
|
||||||
{
|
{
|
||||||
$this->assertTrue($this->getRequestResult($request, $params, $config)->isClientError());
|
$this->assertTrue($this->getRequestResult($request, $params)->isClientError());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,20 +158,7 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testConstructor()
|
public function testConstructor()
|
||||||
{
|
{
|
||||||
$controller = new FrontController($this->container, $this->config);
|
$this->assertInstanceOf(FrontController::class, new FrontController($this->container));
|
||||||
$this->assertInstanceOf(FrontController::class, $controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the constructor with a default config.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @requires OS Linux
|
|
||||||
*/
|
|
||||||
public function testConstructorWithDefaultConfig()
|
|
||||||
{
|
|
||||||
$controller = new FrontController($this->container);
|
|
||||||
$this->assertInstanceOf(FrontController::class, $controller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -204,9 +168,8 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testConstructorWithStream()
|
public function testConstructorWithStream()
|
||||||
{
|
{
|
||||||
$this->config->stream = true;
|
Config::setOptions(['stream' => true]);
|
||||||
$controller = new FrontController($this->container, $this->config);
|
$this->assertInstanceOf(FrontController::class, new FrontController($this->container));
|
||||||
$this->assertInstanceOf(FrontController::class, $controller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -354,12 +317,12 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testVideoWithStream()
|
public function testVideoWithStream()
|
||||||
{
|
{
|
||||||
$this->config->stream = true;
|
Config::setOptions(['stream' => true]);
|
||||||
$this->assertRequestIsOk('video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU'], $this->config);
|
|
||||||
|
$this->assertRequestIsOk('video', ['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU']);
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'video',
|
'video',
|
||||||
['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'audio' => true],
|
['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU', 'audio' => true]
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,11 +390,11 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testRedirectWithStream()
|
public function testRedirectWithStream()
|
||||||
{
|
{
|
||||||
$this->config->stream = true;
|
Config::setOptions(['stream' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU'],
|
['url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU']
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,14 +408,15 @@ class FrontControllerTest extends TestCase
|
||||||
if (getenv('CI')) {
|
if (getenv('CI')) {
|
||||||
$this->markTestSkipped('Twitter returns a 429 error when the test is ran too many times.');
|
$this->markTestSkipped('Twitter returns a 429 error when the test is ran too many times.');
|
||||||
}
|
}
|
||||||
$this->config->stream = true;
|
|
||||||
|
Config::setOptions(['stream' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
[
|
[
|
||||||
'url' => 'https://twitter.com/verge/status/813055465324056576/video/1',
|
'url' => 'https://twitter.com/verge/status/813055465324056576/video/1',
|
||||||
'format' => 'hls-2176',
|
'format' => 'hls-2176',
|
||||||
],
|
]
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,11 +429,11 @@ class FrontControllerTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('We need to find another RTMP video.');
|
$this->markTestIncomplete('We need to find another RTMP video.');
|
||||||
|
|
||||||
$this->config->stream = true;
|
Config::setOptions(['stream' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
['url' => 'http://www.rtvnh.nl/video/131946', 'format' => 'rtmp-264'],
|
['url' => 'http://www.rtvnh.nl/video/131946', 'format' => 'rtmp-264']
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,14 +444,14 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testRedirectWithRemux()
|
public function testRedirectWithRemux()
|
||||||
{
|
{
|
||||||
$this->config->remux = true;
|
Config::setOptions(['remux' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
[
|
[
|
||||||
'url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU',
|
'url' => 'https://www.youtube.com/watch?v=M7IpKCZ47pU',
|
||||||
'format' => 'bestvideo+bestaudio',
|
'format' => 'bestvideo+bestaudio',
|
||||||
],
|
]
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,11 +516,11 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testRedirectWithPlaylist()
|
public function testRedirectWithPlaylist()
|
||||||
{
|
{
|
||||||
$this->config->stream = true;
|
Config::setOptions(['stream' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
['url' => 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC'],
|
['url' => 'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC']
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +531,8 @@ class FrontControllerTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testRedirectWithAdvancedConversion()
|
public function testRedirectWithAdvancedConversion()
|
||||||
{
|
{
|
||||||
$this->config->convertAdvanced = true;
|
Config::setOptions(['convertAdvanced' => true]);
|
||||||
|
|
||||||
$this->assertRequestIsOk(
|
$this->assertRequestIsOk(
|
||||||
'redirect',
|
'redirect',
|
||||||
[
|
[
|
||||||
|
@ -576,8 +541,7 @@ class FrontControllerTest extends TestCase
|
||||||
'customConvert' => 'on',
|
'customConvert' => 'on',
|
||||||
'customBitrate' => 32,
|
'customBitrate' => 32,
|
||||||
'customFormat' => 'flv',
|
'customFormat' => 'flv',
|
||||||
],
|
]
|
||||||
$this->config
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ use PHPUnit\Framework\TestCase;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the LocaleManagerTest class.
|
* Unit tests for the LocaleManagerTest class.
|
||||||
*/
|
*/
|
||||||
class LocaleManagerTest extends TestCase
|
class LocaleManagerTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* LocaleManager class instance.
|
* LocaleManager class instance.
|
||||||
|
|
|
@ -17,7 +17,7 @@ use Slim\Http\Response;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the FrontController class.
|
* Unit tests for the FrontController class.
|
||||||
*/
|
*/
|
||||||
class LocaleMiddlewareTest extends TestCase
|
class LocaleMiddlewareTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* LocaleMiddleware instance.
|
* LocaleMiddleware instance.
|
||||||
|
|
|
@ -11,7 +11,7 @@ use PHPUnit\Framework\TestCase;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the LocaleTest class.
|
* Unit tests for the LocaleTest class.
|
||||||
*/
|
*/
|
||||||
class LocaleTest extends TestCase
|
class LocaleTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Locale class instance.
|
* Locale class instance.
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
namespace Alltube\Test;
|
namespace Alltube\Test;
|
||||||
|
|
||||||
use Alltube\Config;
|
use Alltube\Config;
|
||||||
|
use Alltube\Video;
|
||||||
use Alltube\PlaylistArchiveStream;
|
use Alltube\PlaylistArchiveStream;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
|
@ -14,7 +15,7 @@ use stdClass;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the ViewFactory class.
|
* Unit tests for the ViewFactory class.
|
||||||
*/
|
*/
|
||||||
class PlaylistArchiveStreamTest extends TestCase
|
class PlaylistArchiveStreamTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* PlaylistArchiveStream instance.
|
* PlaylistArchiveStream instance.
|
||||||
|
@ -28,19 +29,11 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
*/
|
*/
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
if (PHP_OS == 'WINNT') {
|
parent::setUp();
|
||||||
$configFile = 'config_test_windows.yml';
|
|
||||||
} else {
|
|
||||||
$configFile = 'config_test.yml';
|
|
||||||
}
|
|
||||||
|
|
||||||
$entry = new stdClass();
|
$video = new Video('https://www.youtube.com/playlist?list=PL1j4Ff8cAqPu5iowaeUAY8lRgkfT4RybJ');
|
||||||
$entry->url = 'BaW_jenozKc';
|
|
||||||
|
|
||||||
$video = new stdClass();
|
$this->stream = new PlaylistArchiveStream($video);
|
||||||
$video->entries = [$entry, $entry];
|
|
||||||
|
|
||||||
$this->stream = new PlaylistArchiveStream(Config::getInstance('config/'.$configFile), $video, 'worst');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,11 +50,10 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
* Test the write() function.
|
* Test the write() function.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException RuntimeException
|
|
||||||
*/
|
*/
|
||||||
public function testWrite()
|
public function testWrite()
|
||||||
{
|
{
|
||||||
$this->stream->write('foo');
|
$this->assertNull($this->stream->write('foo'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,11 +70,12 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
* Test the seek() function.
|
* Test the seek() function.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException RuntimeException
|
|
||||||
*/
|
*/
|
||||||
public function testSeek()
|
public function testSeek()
|
||||||
{
|
{
|
||||||
$this->stream->seek(42);
|
$this->stream->write('foobar');
|
||||||
|
$this->stream->seek(3);
|
||||||
|
$this->assertEquals(3, $this->stream->tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,14 +85,10 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testRead()
|
public function testRead()
|
||||||
{
|
{
|
||||||
while (!$this->stream->eof()) {
|
|
||||||
$result = $this->stream->read(8192);
|
$result = $this->stream->read(8192);
|
||||||
$this->assertInternalType('string', $result);
|
$this->assertInternalType('string', $result);
|
||||||
if (is_string($result)) {
|
|
||||||
$this->assertLessThanOrEqual(8192, strlen($result));
|
$this->assertLessThanOrEqual(8192, strlen($result));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the eof() function.
|
* Test the eof() function.
|
||||||
|
@ -128,18 +117,18 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testIsSeekable()
|
public function testIsSeekable()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->stream->isSeekable());
|
$this->assertTrue($this->stream->isSeekable());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the rewind() function.
|
* Test the rewind() function.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException RuntimeException
|
|
||||||
*/
|
*/
|
||||||
public function testRewind()
|
public function testRewind()
|
||||||
{
|
{
|
||||||
$this->stream->rewind();
|
$this->stream->rewind();
|
||||||
|
$this->assertEquals(0, $this->stream->tell());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,7 +138,7 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testIsWritable()
|
public function testIsWritable()
|
||||||
{
|
{
|
||||||
$this->assertFalse($this->stream->isWritable());
|
$this->assertTrue($this->stream->isWritable());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,7 +168,7 @@ class PlaylistArchiveStreamTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetMetadata()
|
public function testGetMetadata()
|
||||||
{
|
{
|
||||||
$this->assertNull($this->stream->getMetadata());
|
$this->assertInternalType('array', $this->stream->getMetadata());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -13,7 +13,7 @@ use Slim\Http\Request;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the UglyRouter class.
|
* Unit tests for the UglyRouter class.
|
||||||
*/
|
*/
|
||||||
class UglyRouterTest extends TestCase
|
class UglyRouterTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* UglyRouter instance.
|
* UglyRouter instance.
|
||||||
|
|
|
@ -1,59 +1,40 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* VideoDownloadStubsTest class.
|
* VideoStubsTest class.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Alltube\Test;
|
namespace Alltube\Test;
|
||||||
|
|
||||||
use Alltube\Config;
|
use Alltube\Config;
|
||||||
use Alltube\VideoDownload;
|
use Alltube\Video;
|
||||||
use Mockery;
|
use Mockery;
|
||||||
use phpmock\mockery\PHPMockery;
|
use phpmock\mockery\PHPMockery;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for the VideoDownload class.
|
* Unit tests for the Video class.
|
||||||
* They are in a separate file so they can safely replace PHP functions with stubs.
|
* They are in a separate file so they can safely replace PHP functions with stubs.
|
||||||
*/
|
*/
|
||||||
class VideoDownloadStubsTest extends TestCase
|
class VideoStubsTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* VideoDownload instance.
|
|
||||||
*
|
|
||||||
* @var VideoDownload
|
|
||||||
*/
|
|
||||||
private $download;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Config class instance.
|
|
||||||
*
|
|
||||||
* @var Config
|
|
||||||
*/
|
|
||||||
private $config;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Video URL used in many tests.
|
* Video URL used in many tests.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var Video
|
||||||
*/
|
*/
|
||||||
private $url;
|
private $video;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize properties used by test.
|
* Initialize properties used by test.
|
||||||
*/
|
*/
|
||||||
protected function setUp()
|
protected function setUp()
|
||||||
{
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
PHPMockery::mock('Alltube', 'popen');
|
PHPMockery::mock('Alltube', 'popen');
|
||||||
PHPMockery::mock('Alltube', 'fopen');
|
PHPMockery::mock('Alltube', 'fopen');
|
||||||
|
|
||||||
if (PHP_OS == 'WINNT') {
|
$this->video = new Video('https://www.youtube.com/watch?v=XJC9_JkzugE');
|
||||||
$configFile = 'config_test_windows.yml';
|
|
||||||
} else {
|
|
||||||
$configFile = 'config_test.yml';
|
|
||||||
}
|
|
||||||
$this->config = Config::getInstance('config/'.$configFile);
|
|
||||||
$this->download = new VideoDownload($this->config);
|
|
||||||
$this->url = 'https://www.youtube.com/watch?v=XJC9_JkzugE';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +55,7 @@ class VideoDownloadStubsTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStreamWithPopenError()
|
public function testGetAudioStreamWithPopenError()
|
||||||
{
|
{
|
||||||
$this->download->getAudioStream($this->url, 'best');
|
$this->video->getAudioStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +66,7 @@ class VideoDownloadStubsTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetM3uStreamWithPopenError()
|
public function testGetM3uStreamWithPopenError()
|
||||||
{
|
{
|
||||||
$this->download->getM3uStream($this->download->getJSON($this->url, 'best'));
|
$this->video->getM3uStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +77,7 @@ class VideoDownloadStubsTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetRtmpStreamWithPopenError()
|
public function testGetRtmpStreamWithPopenError()
|
||||||
{
|
{
|
||||||
$this->download->getRtmpStream($this->download->getJSON($this->url, 'best'));
|
$this->video->getRtmpStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +88,8 @@ class VideoDownloadStubsTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetRemuxStreamWithPopenError()
|
public function testGetRemuxStreamWithPopenError()
|
||||||
{
|
{
|
||||||
$this->download->getRemuxStream([$this->url, $this->url]);
|
$video = $this->video->withFormat('bestvideo+bestaudio');
|
||||||
|
$video->getRemuxStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,6 +100,6 @@ class VideoDownloadStubsTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetConvertedStreamWithPopenError()
|
public function testGetConvertedStreamWithPopenError()
|
||||||
{
|
{
|
||||||
$this->download->getConvertedStream($this->url, 'best', 32, 'flv');
|
$this->video->getConvertedStream(32, 'flv');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,92 +1,32 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* VideoDownloadTest class.
|
* VideoTest class.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Alltube\Test;
|
namespace Alltube\Test;
|
||||||
|
|
||||||
use Alltube\Config;
|
use Alltube\Config;
|
||||||
use Alltube\VideoDownload;
|
use Alltube\Video;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for the VideoDownload class.
|
* Unit tests for the Video class.
|
||||||
*/
|
*/
|
||||||
class VideoDownloadTest extends TestCase
|
class VideoTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* VideoDownload instance.
|
|
||||||
*
|
|
||||||
* @var VideoDownload
|
|
||||||
*/
|
|
||||||
private $download;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config class instance.
|
* Test getExtractors function.
|
||||||
*
|
|
||||||
* @var Config
|
|
||||||
*/
|
|
||||||
private $config;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize properties used by test.
|
|
||||||
*/
|
|
||||||
protected function setUp()
|
|
||||||
{
|
|
||||||
if (PHP_OS == 'WINNT') {
|
|
||||||
$configFile = 'config_test_windows.yml';
|
|
||||||
} else {
|
|
||||||
$configFile = 'config_test.yml';
|
|
||||||
}
|
|
||||||
$this->config = Config::getInstance('config/'.$configFile);
|
|
||||||
$this->download = new VideoDownload($this->config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy properties after test.
|
|
||||||
*/
|
|
||||||
protected function tearDown()
|
|
||||||
{
|
|
||||||
Config::destroyInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test VideoDownload constructor with wrong youtube-dl path.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testConstructorWithMissingYoutubedl()
|
|
||||||
{
|
|
||||||
$this->config->youtubedl = 'foo';
|
|
||||||
new VideoDownload($this->config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test VideoDownload constructor with wrong Python path.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @expectedException Exception
|
|
||||||
*/
|
|
||||||
public function testConstructorWithMissingPython()
|
|
||||||
{
|
|
||||||
$this->config->python = 'foo';
|
|
||||||
new VideoDownload($this->config);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test listExtractors function.
|
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function testListExtractors()
|
public function testGetExtractors()
|
||||||
{
|
{
|
||||||
$extractors = $this->download->listExtractors();
|
$this->assertContains('youtube', Video::getExtractors());
|
||||||
$this->assertContains('youtube', $extractors);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function.
|
* Test getUrl function.
|
||||||
*
|
*
|
||||||
* @param string $url URL
|
* @param string $url URL
|
||||||
* @param string $format Format
|
* @param string $format Format
|
||||||
|
@ -99,61 +39,70 @@ class VideoDownloadTest extends TestCase
|
||||||
* @dataProvider m3uUrlProvider
|
* @dataProvider m3uUrlProvider
|
||||||
* @dataProvider remuxUrlProvider
|
* @dataProvider remuxUrlProvider
|
||||||
*/
|
*/
|
||||||
public function testGetURL(
|
public function testgetUrl(
|
||||||
$url,
|
$url,
|
||||||
$format,
|
$format,
|
||||||
/* @scrutinizer ignore-unused */ $filename,
|
/* @scrutinizer ignore-unused */ $filename,
|
||||||
/* @scrutinizer ignore-unused */ $extension,
|
/* @scrutinizer ignore-unused */ $extension,
|
||||||
$domain
|
$domain
|
||||||
) {
|
) {
|
||||||
$videoURL = $this->download->getURL($url, $format);
|
$video = new Video($url, $format);
|
||||||
$this->assertContains($domain, $videoURL[0]);
|
foreach ($video->getUrl() as $videoURL) {
|
||||||
|
$this->assertContains($domain, $videoURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function with a protected video.
|
* Test getUrl function with a protected video.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function testGetURLWithPassword()
|
public function testgetUrlWithPassword()
|
||||||
{
|
{
|
||||||
if (getenv('CI')) {
|
if (getenv('CI')) {
|
||||||
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
||||||
}
|
}
|
||||||
$videoURL = $this->download->getURL('http://vimeo.com/68375962', null, 'youtube-dl');
|
|
||||||
$this->assertContains('vimeocdn.com', $videoURL[0]);
|
$video = new Video('http://vimeo.com/68375962', 'best', 'youtube-dl');
|
||||||
|
foreach ($video->getUrl() as $videoURL) {
|
||||||
|
$this->assertContains('vimeocdn.com', $videoURL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function with a protected video and no password.
|
* Test getUrl function with a protected video and no password.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException Alltube\PasswordException
|
* @expectedException Alltube\PasswordException
|
||||||
*/
|
*/
|
||||||
public function testGetURLWithMissingPassword()
|
public function testgetUrlWithMissingPassword()
|
||||||
{
|
{
|
||||||
if (getenv('CI')) {
|
if (getenv('CI')) {
|
||||||
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
||||||
}
|
}
|
||||||
$this->download->getURL('http://vimeo.com/68375962');
|
|
||||||
|
$video = new Video('http://vimeo.com/68375962');
|
||||||
|
$video->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function with a protected video and a wrong password.
|
* Test getUrl function with a protected video and a wrong password.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
* @expectedException Exception
|
* @expectedException Exception
|
||||||
*/
|
*/
|
||||||
public function testGetURLWithWrongPassword()
|
public function testgetUrlWithWrongPassword()
|
||||||
{
|
{
|
||||||
if (getenv('CI')) {
|
if (getenv('CI')) {
|
||||||
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
||||||
}
|
}
|
||||||
$this->download->getURL('http://vimeo.com/68375962', null, 'foo');
|
|
||||||
|
$video = new Video('http://vimeo.com/68375962', 'best', 'foo');
|
||||||
|
$video->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function errors.
|
* Test getUrl function errors.
|
||||||
*
|
*
|
||||||
* @param string $url URL
|
* @param string $url URL
|
||||||
*
|
*
|
||||||
|
@ -161,9 +110,10 @@ class VideoDownloadTest extends TestCase
|
||||||
* @expectedException Exception
|
* @expectedException Exception
|
||||||
* @dataProvider ErrorUrlProvider
|
* @dataProvider ErrorUrlProvider
|
||||||
*/
|
*/
|
||||||
public function testGetURLError($url)
|
public function testgetUrlError($url)
|
||||||
{
|
{
|
||||||
$this->download->getURL($url);
|
$video = new Video($url);
|
||||||
|
$video->getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,9 +248,10 @@ class VideoDownloadTest extends TestCase
|
||||||
* @dataProvider urlProvider
|
* @dataProvider urlProvider
|
||||||
* @dataProvider m3uUrlProvider
|
* @dataProvider m3uUrlProvider
|
||||||
*/
|
*/
|
||||||
public function testGetJSON($url, $format)
|
public function testGetJson($url, $format)
|
||||||
{
|
{
|
||||||
$info = $this->download->getJSON($url, $format);
|
$video = new Video($url, $format);
|
||||||
|
$info = $video->getJson();
|
||||||
$this->assertObjectHasAttribute('webpage_url', $info);
|
$this->assertObjectHasAttribute('webpage_url', $info);
|
||||||
$this->assertObjectHasAttribute('url', $info);
|
$this->assertObjectHasAttribute('url', $info);
|
||||||
$this->assertObjectHasAttribute('ext', $info);
|
$this->assertObjectHasAttribute('ext', $info);
|
||||||
|
@ -318,9 +269,10 @@ class VideoDownloadTest extends TestCase
|
||||||
* @expectedException Exception
|
* @expectedException Exception
|
||||||
* @dataProvider ErrorURLProvider
|
* @dataProvider ErrorURLProvider
|
||||||
*/
|
*/
|
||||||
public function testGetJSONError($url)
|
public function testGetJsonError($url)
|
||||||
{
|
{
|
||||||
$this->download->getJSON($url);
|
$video = new Video($url);
|
||||||
|
$video->getJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -338,8 +290,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetFilename($url, $format, $filename, $extension)
|
public function testGetFilename($url, $format, $filename, $extension)
|
||||||
{
|
{
|
||||||
$videoFilename = $this->download->getFilename($url, $format);
|
$video = new Video($url, $format);
|
||||||
$this->assertEquals($videoFilename, $filename.'.'.$extension);
|
$this->assertEquals($video->getFilename(), $filename.'.'.$extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -353,25 +305,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetFilenameError($url)
|
public function testGetFilenameError($url)
|
||||||
{
|
{
|
||||||
$this->download->getFilename($url);
|
$video = new Video($url);
|
||||||
}
|
$video->getFilename();
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getAudioFilename function.
|
|
||||||
*
|
|
||||||
* @param string $url URL
|
|
||||||
* @param string $format Format
|
|
||||||
* @param string $filename Filename
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
* @dataProvider urlProvider
|
|
||||||
* @dataProvider m3uUrlProvider
|
|
||||||
* @dataProvider remuxUrlProvider
|
|
||||||
*/
|
|
||||||
public function testGetAudioFilename($url, $format, $filename)
|
|
||||||
{
|
|
||||||
$videoFilename = $this->download->getAudioFilename($url, $format);
|
|
||||||
$this->assertEquals($videoFilename, $filename.'.mp3');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -385,9 +320,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStream($url, $format)
|
public function testGetAudioStream($url, $format)
|
||||||
{
|
{
|
||||||
$stream = $this->download->getAudioStream($url, $format);
|
$video = new Video($url, $format);
|
||||||
$this->assertInternalType('resource', $stream);
|
$this->assertStream($video->getAudioStream());
|
||||||
$this->assertFalse(feof($stream));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -402,9 +336,10 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStreamAvconvError($url, $format)
|
public function testGetAudioStreamAvconvError($url, $format)
|
||||||
{
|
{
|
||||||
$this->config->avconv = 'foobar';
|
Config::setOptions(['avconv' => 'foobar']);
|
||||||
$download = new VideoDownload($this->config);
|
|
||||||
$download->getAudioStream($url, $format);
|
$video = new Video($url, $format);
|
||||||
|
$video->getAudioStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -419,7 +354,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStreamM3uError($url, $format)
|
public function testGetAudioStreamM3uError($url, $format)
|
||||||
{
|
{
|
||||||
$this->download->getAudioStream($url, $format);
|
$video = new Video($url, $format);
|
||||||
|
$video->getAudioStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -430,7 +366,12 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStreamDashError()
|
public function testGetAudioStreamDashError()
|
||||||
{
|
{
|
||||||
$this->download->getAudioStream('https://vimeo.com/251997032', 'bestaudio/best');
|
if (getenv('CI')) {
|
||||||
|
$this->markTestSkipped('Travis is blacklisted by Vimeo.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$video = new Video('https://vimeo.com/251997032', 'bestaudio/best');
|
||||||
|
$video->getAudioStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -441,10 +382,11 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetAudioStreamPlaylistError()
|
public function testGetAudioStreamPlaylistError()
|
||||||
{
|
{
|
||||||
$this->download->getAudioStream(
|
$video = new Video(
|
||||||
'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC',
|
'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC',
|
||||||
'best'
|
'best'
|
||||||
);
|
);
|
||||||
|
$video->getAudioStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,11 +413,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetM3uStream($url, $format)
|
public function testGetM3uStream($url, $format)
|
||||||
{
|
{
|
||||||
$this->assertStream(
|
$video = new Video($url, $format);
|
||||||
$this->download->getM3uStream(
|
$this->assertStream($video->getM3uStream());
|
||||||
$this->download->getJSON($url, $format)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,10 +428,24 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetRemuxStream($url, $format)
|
public function testGetRemuxStream($url, $format)
|
||||||
{
|
{
|
||||||
$urls = $this->download->getURL($url, $format);
|
$video = new Video($url, $format);
|
||||||
if (count($urls) > 1) {
|
$this->assertStream($video->getRemuxStream());
|
||||||
$this->assertStream($this->download->getRemuxStream($urls));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getRemuxStream function with a video with only one URL.
|
||||||
|
*
|
||||||
|
* @param string $url URL
|
||||||
|
* @param string $format Format
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @dataProvider urlProvider
|
||||||
|
* @expectedException Exception
|
||||||
|
*/
|
||||||
|
public function testGetRemuxStreamWithWrongVideo($url, $format)
|
||||||
|
{
|
||||||
|
$video = new Video($url, $format);
|
||||||
|
$video->getRemuxStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -508,11 +461,9 @@ class VideoDownloadTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->markTestIncomplete('We need to find another RTMP video.');
|
$this->markTestIncomplete('We need to find another RTMP video.');
|
||||||
|
|
||||||
$this->assertStream(
|
$video = new Video($url, $format);
|
||||||
$this->download->getRtmpStream(
|
|
||||||
$this->download->getJSON($url, $format)
|
$this->assertStream($video->getRtmpStream());
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -527,10 +478,10 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetM3uStreamAvconvError($url, $format)
|
public function testGetM3uStreamAvconvError($url, $format)
|
||||||
{
|
{
|
||||||
$this->config->avconv = 'foobar';
|
Config::setOptions(['avconv' => 'foobar']);
|
||||||
$download = new VideoDownload($this->config);
|
|
||||||
$video = $download->getJSON($url, $format);
|
$video = new Video($url, $format);
|
||||||
$download->getM3uStream($video);
|
$video->getM3uStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -544,7 +495,8 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetConvertedStream($url, $format)
|
public function testGetConvertedStream($url, $format)
|
||||||
{
|
{
|
||||||
$this->assertStream($this->download->getConvertedStream($url, $format, 32, 'flv'));
|
$video = new Video($url, $format);
|
||||||
|
$this->assertStream($video->getConvertedStream(32, 'flv'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,6 +511,7 @@ class VideoDownloadTest extends TestCase
|
||||||
*/
|
*/
|
||||||
public function testGetConvertedStreamM3uError($url, $format)
|
public function testGetConvertedStreamM3uError($url, $format)
|
||||||
{
|
{
|
||||||
$this->download->getConvertedStream($url, $format, 32, 'flv');
|
$video = new Video($url, $format);
|
||||||
|
$video->getConvertedStream(32, 'flv');
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,7 @@ use Slim\Views\Smarty;
|
||||||
/**
|
/**
|
||||||
* Unit tests for the ViewFactory class.
|
* Unit tests for the ViewFactory class.
|
||||||
*/
|
*/
|
||||||
class ViewFactoryTest extends TestCase
|
class ViewFactoryTest extends BaseTest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Test the create() function.
|
* Test the create() function.
|
||||||
|
|
Loading…
Reference in a new issue