From e34b01f2c47df219460c94d28783e6c6bc5b572c Mon Sep 17 00:00:00 2001 From: Pierre Rudloff Date: Thu, 20 Oct 2016 23:01:31 +0200 Subject: [PATCH] Add support for password protected videos --- classes/PasswordException.php | 13 +++++++ classes/VideoDownload.php | 49 +++++++++++++++--------- composer.json | 3 +- composer.lock | 66 ++++++++++++++++++++++++++++++++- controllers/FrontController.php | 41 ++++++++++++++++++-- index.php | 2 +- templates/password.tpl | 13 +++++++ templates/video.tpl | 6 +-- tests/VideoDownloadTest.php | 32 ++++++++++++++++ 9 files changed, 196 insertions(+), 29 deletions(-) create mode 100644 classes/PasswordException.php create mode 100644 templates/password.tpl diff --git a/classes/PasswordException.php b/classes/PasswordException.php new file mode 100644 index 0000000..abf1ce5 --- /dev/null +++ b/classes/PasswordException.php @@ -0,0 +1,13 @@ +procBuilder->setArguments( [ @@ -88,10 +89,21 @@ class VideoDownload if (isset($format)) { $this->procBuilder->add('-f '.$format); } + if (isset($password)) { + $this->procBuilder->add('--video-password'); + $this->procBuilder->add($password); + } $process = $this->procBuilder->getProcess(); $process->run(); 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 { return $process->getOutput(); } @@ -100,40 +112,43 @@ class VideoDownload /** * Get all information about a video. * - * @param string $url URL of page - * @param string $format Format to use for the video + * @param string $url URL of page + * @param string $format Format to use for the video + * @param string $password Video password * * @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)); } /** * Get URL of video from URL of page. * - * @param string $url URL of page - * @param string $format Format to use for the video + * @param string $url URL of page + * @param string $format Format to use for the video + * @param string $password Video password * * @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); } /** * 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 $url URL of page + * @param string $format Format to use for the video + * @param string $password Video password * * @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)); } /** diff --git a/composer.json b/composer.json index 2e26009..c617f5d 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,8 @@ "symfony/yaml": "~3.1.0", "symfony/process": "~3.1.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": { "symfony/var-dumper": "~3.1.0", diff --git a/composer.lock b/composer.lock index 854f2de..547746b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,71 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "2814570fa83cedc8e079c1d236a787d2", - "content-hash": "91057608d6f29b8de8a9761bb419f19c", + "hash": "7feb22c9a83e389562253bd1e7389080", + "content-hash": "0ca3a07c96a159c3a44ae007b56a9fbf", "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", "version": "1.1.0", diff --git a/controllers/FrontController.php b/controllers/FrontController.php index d6b71e6..b25b691 100644 --- a/controllers/FrontController.php +++ b/controllers/FrontController.php @@ -6,6 +6,7 @@ namespace Alltube\Controller; use Alltube\Config; use Alltube\VideoDownload; +use Alltube\PasswordException; use Interop\Container\ContainerInterface; use Slim\Container; use Slim\Http\Request; @@ -48,6 +49,9 @@ class FrontController $this->config = Config::getInstance(); $this->download = new VideoDownload(); $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. * @@ -109,8 +135,11 @@ class FrontController public function video(Request $request, Response $response) { $params = $request->getQueryParams(); - $this->config = Config::getInstance(); if (isset($params['url'])) { + $password = $request->getParam('password'); + if (isset($password)) { + $this->sessionSegment->setFlash($params['url'], $password); + } if (isset($params['audio'])) { try { $url = $this->download->getURL($params['url'], 'mp3[protocol^=http]'); @@ -132,7 +161,11 @@ class FrontController return $response; } } 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) { $this->container->view->render( $response, @@ -190,9 +223,11 @@ class FrontController $params = $request->getQueryParams(); if (isset($params['url'])) { 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); + } catch (PasswordException $e) { + return $response->withRedirect($this->container->get('router')->pathFor('video').'?url='.urlencode($params['url'])); } catch (\Exception $e) { $response->getBody()->write($e->getMessage()); diff --git a/index.php b/index.php index f9fdd7d..6a01bc4 100644 --- a/index.php +++ b/index.php @@ -35,7 +35,7 @@ $app->get( '/extractors', [$controller, 'extractors'] )->setName('extractors'); -$app->get( +$app->any( '/video', [$controller, 'video'] )->setName('video'); diff --git a/templates/password.tpl b/templates/password.tpl new file mode 100644 index 0000000..ab8e302 --- /dev/null +++ b/templates/password.tpl @@ -0,0 +1,13 @@ +{include file='inc/head.tpl'} +
+
+ {include file="inc/logo.tpl"} +

This video is protected

+

You need a password in order to download this video.

+
+ +

+ +
+
+{include file='inc/footer.tpl'} diff --git a/templates/video.tpl b/templates/video.tpl index e3790b1..6f11251 100644 --- a/templates/video.tpl +++ b/templates/video.tpl @@ -28,11 +28,7 @@