Cleanup playlists

This commit is contained in:
Pierre Rudloff 2017-04-25 01:53:38 +02:00
parent 3f053d9eed
commit 43cbd4f6fe
10 changed files with 175 additions and 121 deletions

View file

@ -38,7 +38,7 @@ class Config
* *
* @var array * @var array
*/ */
public $params = ['--no-playlist', '--no-warnings', '--playlist-end', 1]; public $params = ['--no-warnings'];
/** /**
* Enable audio conversion. * Enable audio conversion.

View file

@ -113,14 +113,7 @@ class VideoDownload
* */ * */
public function getJSON($url, $format = null, $password = null) public function getJSON($url, $format = null, $password = null)
{ {
$jsonArray = preg_split( "/\r|\n/", $this->getProp($url, $format, 'dump-json', $password), -1, return json_decode($this->getProp($url, $format, 'dump-single-json', $password));
PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
$decodedJson = array();
foreach ($jsonArray as $oneJson)
{
array_push($decodedJson, json_decode($oneJson));
}
return $decodedJson;
} }
/** /**

View file

@ -213,7 +213,7 @@ class FrontController
private function getVideoResponse(Request $request, Response $response, array $params, $password = null) private function getVideoResponse(Request $request, Response $response, array $params, $password = null)
{ {
try { try {
$vidarr = $this->download->getJSON($params['url'], $this->defaultFormat, $password); $video = $this->download->getJSON($params['url'], $this->defaultFormat, $password);
} catch (PasswordException $e) { } catch (PasswordException $e) {
return $this->password($request, $response); return $this->password($request, $response);
} }
@ -222,14 +222,19 @@ class FrontController
} else { } else {
$protocol = '[protocol^=http]'; $protocol = '[protocol^=http]';
} }
if (isset($video->entries)) {
$template = 'playlist.tpl';
} else {
$template = 'video.tpl';
}
$this->view->render( $this->view->render(
$response, $response,
'video.tpl', $template,
[ [
'vidarr' => $vidarr, 'video' => $video,
'class' => 'video', 'class' => 'video',
'title' => $vidarr[0]->title, 'title' => $video->title,
'description' => 'Download "'.$vidarr[0]->title.'" from '.$vidarr[0]->extractor_key, 'description' => 'Download "'.$video->title.'" from '.$video->extractor_key,
'protocol' => $protocol, 'protocol' => $protocol,
'config' => $this->config, 'config' => $this->config,
'canonical' => $this->getCanonicalUrl($request), 'canonical' => $this->getCanonicalUrl($request),
@ -327,7 +332,11 @@ class FrontController
$response = $response->withBody($stream->getBody()); $response = $response->withBody($stream->getBody());
} }
} }
$response = $response->withHeader('Content-Disposition', 'attachment; filename="'.$video->_filename.'"'); $response = $response->withHeader(
'Content-Disposition',
'attachment; filename="'.
$this->download->getFilename($url, $format, $password).'"'
);
return $response; return $response;
} }

View file

@ -397,10 +397,34 @@ padding:3px;
/* Playlists */
.playlist-entry .thumb {
float: left;
margin-right: 1em;
}
.playlist-entry {
clear: both;
padding-top: 2em;
text-align: left;
}
.playlist-entry h3 {
margin-top: 0;
}
.playlist-entry h3 a {
text-decoration: none;
}
.playlist-entry h3 a:hover {
text-decoration: underline;
}
.playlist-entry .downloadBtn {
font-size: 16px;
border-width: 2px;
}

View file

@ -1,4 +1,5 @@
<?php <?php
require_once __DIR__.'/vendor/autoload.php'; require_once __DIR__.'/vendor/autoload.php';
use Alltube\Config; use Alltube\Config;
use Alltube\Controller\FrontController; use Alltube\Controller\FrontController;

View file

@ -2,7 +2,7 @@
/*jslint browser: true, nomen: true */ /*jslint browser: true, nomen: true */
var castModule = (function () { var castModule = (function () {
'use strict'; 'use strict';
var launchBtn, disabledBtn, stopBtn, session, videoLink; var launchBtn, disabledBtn, stopBtn, session;
function receiverListener(e) { function receiverListener(e) {
return (e === chrome.cast.ReceiverAvailability.AVAILABLE); return (e === chrome.cast.ReceiverAvailability.AVAILABLE);
@ -51,7 +51,7 @@ var castModule = (function () {
function onRequestSessionSuccess(e) { function onRequestSessionSuccess(e) {
session = e; session = e;
var videoURL = videoLink.dataset.video, mediaInfo = new chrome.cast.media.MediaInfo(videoURL, 'video/' + videoLink.dataset.ext), request = new chrome.cast.media.LoadRequest(mediaInfo); var videoLink = document.getElementById('video_link'), videoURL = videoLink.dataset.video, mediaInfo = new chrome.cast.media.MediaInfo(videoURL, 'video/' + videoLink.dataset.ext), request = new chrome.cast.media.LoadRequest(mediaInfo);
session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onMediaError); session.loadMedia(request, onMediaDiscovered.bind(this, 'loadMedia'), onMediaError);
} }
@ -59,23 +59,19 @@ var castModule = (function () {
throw e.description; throw e.description;
} }
function launchCast(event) { function launchCast() {
videoLink = event.target || event.srcElement;
chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError); chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
} }
function onInitSuccess() { function onInitSuccess() {
launchBtn = document.getElementsByClassName('cast_btn_launch'); launchBtn = document.getElementById('cast_btn_launch');
disabledBtn = document.getElementsByClassName('cast_disabled'); disabledBtn = document.getElementById('cast_disabled');
stopBtn = document.getElementsByClassName('cast_btn_stop'); stopBtn = document.getElementById('cast_btn_stop');
if (launchBtn.length > 0) { if (launchBtn) {
var i; disabledBtn.classList.add('cast_hidden');
for (i = 0; i < launchBtn.length; i++) { launchBtn.classList.remove('cast_hidden');
disabledBtn[i].classList.add('cast_hidden'); launchBtn.addEventListener('click', launchCast, false);
launchBtn[i].classList.remove('cast_hidden'); stopBtn.addEventListener('click', stopCast, false);
launchBtn[i].addEventListener('click', launchCast, false);
stopBtn[i].addEventListener('click', stopCast, false);
}
} }
} }
@ -98,12 +94,12 @@ var castModule = (function () {
return { return {
init: function () { init: function () {
var intro = document.getElementsByClassName('download_intro'), i; var intro = document.getElementById('download_intro');
for (i = 0; i < intro.length; i++) { if (intro) {
intro[i].insertAdjacentHTML('beforeend', '<img class="cast_disabled cast_icon" id="cast_disabled'+i+'" src="img/ic_media_route_disabled_holo_light.png" alt="" title="Google Cast is not supported on this browser." /> <img class="cast_btn_launch cast_btn cast_hidden cast_icon" id="cast_btn_launch'+i+'" src="img/ic_media_route_off_holo_light.png" title="Cast to ChromeCast" alt="Google Cast™" /> <img src="img/ic_media_route_on_holo_light.png" alt="Casting to ChromeCast…" title="Stop casting" id="cast_btn_stop'+i+'" class="cast_btn_stop cast_btn cast_hidden cast_icon" />'); intro.insertAdjacentHTML('beforeend', '<img class="cast_icon" id="cast_disabled" src="img/ic_media_route_disabled_holo_light.png" alt="" title="Google Cast is not supported on this browser." /> <img class="cast_btn cast_hidden cast_icon" id="cast_btn_launch" src="img/ic_media_route_off_holo_light.png" title="Cast to ChromeCast" alt="Google Cast™" /> <img src="img/ic_media_route_on_holo_light.png" alt="Casting to ChromeCast…" title="Stop casting" id="cast_btn_stop" class="cast_btn cast_hidden cast_icon" />');
}
window.__onGCastApiAvailable = loadCastApi; window.__onGCastApiAvailable = loadCastApi;
} }
}
}; };
}()); }());

19
templates/playlist.tpl Normal file
View file

@ -0,0 +1,19 @@
{include file="inc/head.tpl"}
<div class="wrapper">
<div class="main">
{include file="inc/logo.tpl"}
<p>Videos extracted from the<i>
<a href="{$video->webpage_url}">
{$video->title}</a></i> playlist:
</p>
{foreach $video->entries as $video}
<div class="playlist-entry">
<img class="thumb" src="{$video->thumbnail}" alt="" width="200" />
<h3><a href="{$video->webpage_url}">{$video->title}</a></h3>
<a class="downloadBtn" href="{path_for name="redirect"}?url={$video->webpage_url}">Download</a>
</div>
{/foreach}
</div>
</div>
{include file="inc/footer.tpl"}

View file

@ -3,33 +3,31 @@
<div itemscope itemtype="http://schema.org/VideoObject"> <div itemscope itemtype="http://schema.org/VideoObject">
<div class="main"> <div class="main">
{include file="inc/logo.tpl"} {include file="inc/logo.tpl"}
{foreach $vidarr as $video} <p id="download_intro">You are going to download<i itemprop="name">
<p id="download_intro{$video@index}" class="download_intro">You are going to download<i itemprop="name"> <a itemprop="url" id="video_link"
<a itemprop="url" id="video_link{$video@index}"
class="video_link"
data-ext="{$video->ext}" data-ext="{$video->ext}"
data-video="{$video->url|escape}" data-video="{$video->url|escape}"
href="{$video->webpage_url}"> href="{$video->webpage_url}">
{$video->title}</a></i>. {$video->title}</a></i>.
</p> </p>
{if isset($video->thumbnail)} {if isset($video->thumbnail)}
<img itemprop="thumbnailUrl" class="thumb" src="{$video->thumbnail}" alt="" /> <img itemprop="thumbnailUrl" class="thumb" src="{$video->thumbnail}" alt="" />
{/if} {/if}
{if isset($video->description)} {if isset($video->description)}
<meta itemprop="description" content="{$video->description|escape}" /> <meta itemprop="description" content="{$video->description|escape}" />
{/if} {/if}
{if isset($video->upload_date)} {if isset($video->upload_date)}
<meta itemprop="uploadDate" content="{$video->upload_date}" /> <meta itemprop="uploadDate" content="{$video->upload_date}" />
{/if} {/if}
<br/> <br/>
{if isset($video->formats)} {if isset($video->formats)}
<h3><label for="format{$video@index}">Available formats:</label></h3> <h3><label for="format">Available formats:</label></h3>
<form action="{path_for name="redirect"}"> <form action="{path_for name="redirect"}">
<input type="hidden" name="url" value="{$video->webpage_url}" /> <input type="hidden" name="url" value="{$video->webpage_url}" />
{if uglyUrls} {if $uglyUrls}
<input type="hidden" name="page" value="redirect" /> <input type="hidden" name="page" value="redirect" />
{/if} {/if}
<select name="format" id="format{$video@index}" class="formats monospace"> <select name="format" id="format" class="formats monospace">
<optgroup label="Generic formats"> <optgroup label="Generic formats">
<option value="best{$protocol}"> <option value="best{$protocol}">
{strip} {strip}
@ -86,12 +84,11 @@
</select><br/><br/> </select><br/><br/>
<input class="downloadBtn" type="submit" value="Download" /><br/> <input class="downloadBtn" type="submit" value="Download" /><br/>
</form> </form>
{else} {else}
<input type="hidden" name="format" value="best{$protocol}" /> <input type="hidden" name="format" value="best{$protocol}" />
<a class="downloadBtn" href="{$video->url|escape}">Download</a><br/> <a class="downloadBtn"
{/if} href="{$video->url|escape}">Download</a><br/>
<hr /> {/if}
{/foreach}
</div> </div>
</div> </div>
{include file="inc/footer.tpl"} {include file="inc/footer.tpl"}

View file

@ -264,6 +264,22 @@ class FrontControllerTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($result->isOk()); $this->assertTrue($result->isOk());
} }
/**
* Test the video() function with a playlist.
*
* @return void
*/
public function testVideoWithPlaylist()
{
$result = $this->controller->video(
$this->request->withQueryParams(
['url'=>'https://www.youtube.com/playlist?list=PLgdySZU6KUXL_8Jq5aUkyNV7wCa-4wZsC']
),
$this->response
);
$this->assertTrue($result->isOk());
}
/** /**
* Test the error() function. * Test the error() function.
* *

View file

@ -266,7 +266,6 @@ class VideoDownloadTest extends \PHPUnit_Framework_TestCase
$this->assertObjectHasAttribute('title', $info); $this->assertObjectHasAttribute('title', $info);
$this->assertObjectHasAttribute('extractor_key', $info); $this->assertObjectHasAttribute('extractor_key', $info);
$this->assertObjectHasAttribute('formats', $info); $this->assertObjectHasAttribute('formats', $info);
$this->assertObjectHasAttribute('_filename', $info);
} }
/** /**