Add support for password protected videos
This commit is contained in:
parent
621ccfb491
commit
e34b01f2c4
9 changed files with 196 additions and 29 deletions
13
classes/PasswordException.php
Normal file
13
classes/PasswordException.php
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* PasswordException class
|
||||||
|
*/
|
||||||
|
namespace Alltube;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when a video requires a password
|
||||||
|
*/
|
||||||
|
class PasswordException extends \Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
|
@ -74,10 +74,11 @@ class VideoDownload
|
||||||
* @param string $url URL to parse
|
* @param string $url URL to parse
|
||||||
* @param string $format Format
|
* @param string $format Format
|
||||||
* @param string $prop Property
|
* @param string $prop Property
|
||||||
|
* @param string $password Video password
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
private function getProp($url, $format = null, $prop = 'dump-json')
|
private function getProp($url, $format = null, $prop = 'dump-json', $password = null)
|
||||||
{
|
{
|
||||||
$this->procBuilder->setArguments(
|
$this->procBuilder->setArguments(
|
||||||
[
|
[
|
||||||
|
@ -88,10 +89,21 @@ class VideoDownload
|
||||||
if (isset($format)) {
|
if (isset($format)) {
|
||||||
$this->procBuilder->add('-f '.$format);
|
$this->procBuilder->add('-f '.$format);
|
||||||
}
|
}
|
||||||
|
if (isset($password)) {
|
||||||
|
$this->procBuilder->add('--video-password');
|
||||||
|
$this->procBuilder->add($password);
|
||||||
|
}
|
||||||
$process = $this->procBuilder->getProcess();
|
$process = $this->procBuilder->getProcess();
|
||||||
$process->run();
|
$process->run();
|
||||||
if (!$process->isSuccessful()) {
|
if (!$process->isSuccessful()) {
|
||||||
throw new \Exception($process->getErrorOutput());
|
$errorOutput = trim($process->getErrorOutput());
|
||||||
|
if ($errorOutput == 'ERROR: This video is protected by a password, use the --video-password option') {
|
||||||
|
throw new PasswordException($errorOutput);
|
||||||
|
} elseif (substr($errorOutput, 0, 21) == 'ERROR: Wrong password') {
|
||||||
|
throw new \Exception('Wrong password');
|
||||||
|
} else {
|
||||||
|
throw new \Exception($errorOutput);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return $process->getOutput();
|
return $process->getOutput();
|
||||||
}
|
}
|
||||||
|
@ -102,12 +114,13 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
* @param string $url URL of page
|
||||||
* @param string $format Format to use for the video
|
* @param string $format Format to use for the video
|
||||||
|
* @param string $password Video password
|
||||||
*
|
*
|
||||||
* @return object Decoded JSON
|
* @return object Decoded JSON
|
||||||
* */
|
* */
|
||||||
public function getJSON($url, $format = null)
|
public function getJSON($url, $format = null, $password = null)
|
||||||
{
|
{
|
||||||
return json_decode($this->getProp($url, $format, 'dump-json'));
|
return json_decode($this->getProp($url, $format, 'dump-json', $password));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,12 +128,13 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
* @param string $url URL of page
|
||||||
* @param string $format Format to use for the video
|
* @param string $format Format to use for the video
|
||||||
|
* @param string $password Video password
|
||||||
*
|
*
|
||||||
* @return string URL of video
|
* @return string URL of video
|
||||||
* */
|
* */
|
||||||
public function getURL($url, $format = null)
|
public function getURL($url, $format = null, $password = null)
|
||||||
{
|
{
|
||||||
return $this->getProp($url, $format, 'get-url');
|
return $this->getProp($url, $format, 'get-url', $password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,12 +142,13 @@ class VideoDownload
|
||||||
*
|
*
|
||||||
* @param string $url URL of page
|
* @param string $url URL of page
|
||||||
* @param string $format Format to use for the video
|
* @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)
|
public function getFilename($url, $format = null, $password = null)
|
||||||
{
|
{
|
||||||
return trim($this->getProp($url, $format, 'get-filename'));
|
return trim($this->getProp($url, $format, 'get-filename', $password));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
"symfony/yaml": "~3.1.0",
|
"symfony/yaml": "~3.1.0",
|
||||||
"symfony/process": "~3.1.0",
|
"symfony/process": "~3.1.0",
|
||||||
"ptachoire/process-builder-chain": "~1.2.0",
|
"ptachoire/process-builder-chain": "~1.2.0",
|
||||||
"rudloff/smarty-plugin-noscheme": "~0.1.0"
|
"rudloff/smarty-plugin-noscheme": "~0.1.0",
|
||||||
|
"aura/session": "~2.1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"symfony/var-dumper": "~3.1.0",
|
"symfony/var-dumper": "~3.1.0",
|
||||||
|
|
66
composer.lock
generated
66
composer.lock
generated
|
@ -4,9 +4,71 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "2814570fa83cedc8e079c1d236a787d2",
|
"hash": "7feb22c9a83e389562253bd1e7389080",
|
||||||
"content-hash": "91057608d6f29b8de8a9761bb419f19c",
|
"content-hash": "0ca3a07c96a159c3a44ae007b56a9fbf",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "aura/session",
|
||||||
|
"version": "2.1.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/auraphp/Aura.Session.git",
|
||||||
|
"reference": "7d2f7d41ad693970b5b6b83facca0961d3378883"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/auraphp/Aura.Session/zipball/7d2f7d41ad693970b5b6b83facca0961d3378883",
|
||||||
|
"reference": "7d2f7d41ad693970b5b6b83facca0961d3378883",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"aura/di": "~2.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-mcrypt": "Mcrypt generates the next best secure CSRF tokens.",
|
||||||
|
"ext-openssl": "OpenSSL generates the best secure CSRF tokens.",
|
||||||
|
"ircmaxell/random-lib": "A Library For Generating Secure Random Numbers",
|
||||||
|
"paragonie/random_compat": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"aura": {
|
||||||
|
"type": "library",
|
||||||
|
"config": {
|
||||||
|
"common": "Aura\\Session\\_Config\\Common"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Aura\\Session\\": "src/",
|
||||||
|
"Aura\\Session\\_Config\\": "config/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-2-Clause"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Aura.Session Contributors",
|
||||||
|
"homepage": "https://github.com/auraphp/Aura.Session/contributors"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Provides session management functionality, including lazy session starting, session segments, next-request-only (\"flash\") values, and CSRF tools.",
|
||||||
|
"homepage": "https://github.com/auraphp/Aura.Session",
|
||||||
|
"keywords": [
|
||||||
|
"csrf",
|
||||||
|
"flash",
|
||||||
|
"flash message",
|
||||||
|
"session",
|
||||||
|
"sessions"
|
||||||
|
],
|
||||||
|
"time": "2016-10-03 20:28:32"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "container-interop/container-interop",
|
"name": "container-interop/container-interop",
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace Alltube\Controller;
|
||||||
|
|
||||||
use Alltube\Config;
|
use Alltube\Config;
|
||||||
use Alltube\VideoDownload;
|
use Alltube\VideoDownload;
|
||||||
|
use Alltube\PasswordException;
|
||||||
use Interop\Container\ContainerInterface;
|
use Interop\Container\ContainerInterface;
|
||||||
use Slim\Container;
|
use Slim\Container;
|
||||||
use Slim\Http\Request;
|
use Slim\Http\Request;
|
||||||
|
@ -48,6 +49,9 @@ class FrontController
|
||||||
$this->config = Config::getInstance();
|
$this->config = Config::getInstance();
|
||||||
$this->download = new VideoDownload();
|
$this->download = new VideoDownload();
|
||||||
$this->container = $container;
|
$this->container = $container;
|
||||||
|
$session_factory = new \Aura\Session\SessionFactory;
|
||||||
|
$session = $session_factory->newInstance($_COOKIE);
|
||||||
|
$this->sessionSegment = $session->getSegment('Alltube\Controller\FrontController');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,6 +102,28 @@ class FrontController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a password prompt
|
||||||
|
* @param Request $request PSR-7 request
|
||||||
|
* @param Response $response PSR-7 response
|
||||||
|
*
|
||||||
|
* @return Response HTTP response
|
||||||
|
*/
|
||||||
|
public function password(Request $request, Response $response)
|
||||||
|
{
|
||||||
|
if ($this->container instanceof Container) {
|
||||||
|
$this->container->view->render(
|
||||||
|
$response,
|
||||||
|
'password.tpl',
|
||||||
|
[
|
||||||
|
'class' => 'password',
|
||||||
|
'title' => 'Password prompt',
|
||||||
|
'description' => 'You need a password in order to download this video with Alltube Download',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dislay information about the video.
|
* Dislay information about the video.
|
||||||
*
|
*
|
||||||
|
@ -109,8 +135,11 @@ class FrontController
|
||||||
public function video(Request $request, Response $response)
|
public function video(Request $request, Response $response)
|
||||||
{
|
{
|
||||||
$params = $request->getQueryParams();
|
$params = $request->getQueryParams();
|
||||||
$this->config = Config::getInstance();
|
|
||||||
if (isset($params['url'])) {
|
if (isset($params['url'])) {
|
||||||
|
$password = $request->getParam('password');
|
||||||
|
if (isset($password)) {
|
||||||
|
$this->sessionSegment->setFlash($params['url'], $password);
|
||||||
|
}
|
||||||
if (isset($params['audio'])) {
|
if (isset($params['audio'])) {
|
||||||
try {
|
try {
|
||||||
$url = $this->download->getURL($params['url'], 'mp3[protocol^=http]');
|
$url = $this->download->getURL($params['url'], 'mp3[protocol^=http]');
|
||||||
|
@ -132,7 +161,11 @@ class FrontController
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$video = $this->download->getJSON($params['url']);
|
try {
|
||||||
|
$video = $this->download->getJSON($params['url'], null, $password);
|
||||||
|
} catch (PasswordException $e) {
|
||||||
|
return $this->password($request, $response);
|
||||||
|
}
|
||||||
if ($this->container instanceof Container) {
|
if ($this->container instanceof Container) {
|
||||||
$this->container->view->render(
|
$this->container->view->render(
|
||||||
$response,
|
$response,
|
||||||
|
@ -190,9 +223,11 @@ class FrontController
|
||||||
$params = $request->getQueryParams();
|
$params = $request->getQueryParams();
|
||||||
if (isset($params['url'])) {
|
if (isset($params['url'])) {
|
||||||
try {
|
try {
|
||||||
$url = $this->download->getURL($params['url'], $params['format']);
|
$url = $this->download->getURL($params['url'], $request->getParam('format'), $this->sessionSegment->getFlash($params['url']));
|
||||||
|
|
||||||
return $response->withRedirect($url);
|
return $response->withRedirect($url);
|
||||||
|
} catch (PasswordException $e) {
|
||||||
|
return $response->withRedirect($this->container->get('router')->pathFor('video').'?url='.urlencode($params['url']));
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
$response->getBody()->write($e->getMessage());
|
$response->getBody()->write($e->getMessage());
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ $app->get(
|
||||||
'/extractors',
|
'/extractors',
|
||||||
[$controller, 'extractors']
|
[$controller, 'extractors']
|
||||||
)->setName('extractors');
|
)->setName('extractors');
|
||||||
$app->get(
|
$app->any(
|
||||||
'/video',
|
'/video',
|
||||||
[$controller, 'video']
|
[$controller, 'video']
|
||||||
)->setName('video');
|
)->setName('video');
|
||||||
|
|
13
templates/password.tpl
Normal file
13
templates/password.tpl
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
{include file='inc/head.tpl'}
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="main">
|
||||||
|
{include file="inc/logo.tpl"}
|
||||||
|
<h2>This video is protected</h2>
|
||||||
|
<p>You need a password in order to download this video.</p>
|
||||||
|
<form action="" method="POST">
|
||||||
|
<input class="URLinput" type="password" name="password" title="Video password" />
|
||||||
|
<br/><br/>
|
||||||
|
<input class="downloadBtn" type="submit" value="Download" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{include file='inc/footer.tpl'}
|
|
@ -28,11 +28,7 @@
|
||||||
<optgroup label="Generic formats">
|
<optgroup label="Generic formats">
|
||||||
<option value="best[protocol^=http]">
|
<option value="best[protocol^=http]">
|
||||||
{strip}
|
{strip}
|
||||||
Best ({$video->ext}
|
Best ({$video->ext})
|
||||||
{if isset($video->filesize)}
|
|
||||||
{$video->filesize}
|
|
||||||
{/if}
|
|
||||||
)
|
|
||||||
{/strip}
|
{/strip}
|
||||||
</option>
|
</option>
|
||||||
<option value="worst[protocol^=http]">
|
<option value="worst[protocol^=http]">
|
||||||
|
|
|
@ -89,6 +89,38 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
|
||||||
$this->assertContains($domain, $videoURL);
|
$this->assertContains($domain, $videoURL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getURL function with a protected video
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function testGetURLWithPassword()
|
||||||
|
{
|
||||||
|
$this->assertContains('vimeocdn.com', $this->download->getURL('http://vimeo.com/68375962', null, 'youtube-dl'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getURL function with a protected video and no password.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @expectedException \Alltube\PasswordException
|
||||||
|
*/
|
||||||
|
public function testGetURLWithMissingPassword()
|
||||||
|
{
|
||||||
|
$this->download->getURL('http://vimeo.com/68375962');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test getURL function with a protected video and a wrong password.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
* @expectedException Exception
|
||||||
|
*/
|
||||||
|
public function testGetURLWithWrongPassword()
|
||||||
|
{
|
||||||
|
$this->download->getURL('http://vimeo.com/68375962', null, 'foo');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test getURL function errors.
|
* Test getURL function errors.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue