Skip to content

Commit

Permalink
renamed data namespace to models and resources into responses
Browse files Browse the repository at this point in the history
  • Loading branch information
Athlon1600 committed Feb 27, 2021
1 parent f9a9d1d commit bf0eb53
Show file tree
Hide file tree
Showing 18 changed files with 505 additions and 70 deletions.
236 changes: 236 additions & 0 deletions etc/links.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion public/video_info.php
Expand Up @@ -22,7 +22,7 @@ function send_json($data)
try {
$links = $youtube->getDownloadLinks($url);

$best = $links->getBestCombinedFormat();
$best = $links->getFirstCombinedFormat();

if ($best) {
send_json([
Expand Down
21 changes: 3 additions & 18 deletions src/Browser.php
Expand Up @@ -23,13 +23,6 @@ public function followRedirects($enabled)
return $this;
}

private function getJson($url)
{
$response = $this->get($url);
$response->body = json_decode($response->body, true);
return $response;
}

public function cachedGet($url)
{
$cache_path = sprintf('%s/%s', static::getStorageDirectory(), $this->getCacheKey($url));
Expand All @@ -44,23 +37,15 @@ public function cachedGet($url)
$response = $this->get($url);

// cache only if successful
if ($response->body) {
if (empty($response->error)) {
file_put_contents($cache_path, serialize($response));
return $response;
}

return null;
return $response;
}

protected function getCacheKey($url)
{
return md5($url);
}

private function postJson($url, $json)
{
return $this->request('POST', $url, $json, [
'Content-Type' => 'application/json'
]);
return md5($url) . '_v3';
}
}
97 changes: 86 additions & 11 deletions src/DownloadOptions.php
Expand Up @@ -2,46 +2,61 @@

namespace YouTube;

use YouTube\Data\StreamFormat;
use YouTube\Models\SplitStream;
use YouTube\Models\StreamFormat;
use YouTube\Models\VideoDetails;
use YouTube\Utils\Utils;

class DownloadOptions
{
private $links;
/** @var StreamFormat[] $formats */
private $formats;

public function __construct($links)
/** @var VideoDetails|null */
private $info;

public function __construct($formats, $info = null)
{
$this->links = $links;
$this->formats = $formats;
$this->info = $info;
}

/**
* @return StreamFormat[]
*/
public function getAllLinks()
public function getAllFormats()
{
return $this->formats;
}

/**
* @return VideoDetails|null
*/
public function getInfo()
{
return $this->links;
return $this->info;
}

// Video only!!!
// Will not include Videos with Audio
public function getVideoFormats()
{
return Utils::arrayFilterReset($this->getAllLinks(), function ($format) {
return Utils::arrayFilterReset($this->getAllFormats(), function ($format) {
/** @var $format StreamFormat */
return strpos($format->mimeType, 'video') === 0 && empty($format->audioQuality);
});
}

public function getAudioFormats()
{
return Utils::arrayFilterReset($this->getAllLinks(), function ($format) {
return Utils::arrayFilterReset($this->getAllFormats(), function ($format) {
/** @var $format StreamFormat */
return strpos($format->mimeType, 'audio') === 0;
});
}

public function getCombinedFormats()
{
return Utils::arrayFilterReset($this->getAllLinks(), function ($format) {
return Utils::arrayFilterReset($this->getAllFormats(), function ($format) {
/** @var $format StreamFormat */
return strpos($format->mimeType, 'video') === 0 && !empty($format->audioQuality);
});
Expand All @@ -50,9 +65,69 @@ public function getCombinedFormats()
/**
* @return StreamFormat|null
*/
public function getBestCombinedFormat()
public function getFirstCombinedFormat()
{
$combined = $this->getCombinedFormats();
return count($combined) ? $combined[0] : null;
}

protected function getLowToHighVideoFormats()
{
$copy = array_values($this->getVideoFormats());

usort($copy, function ($a, $b) {

/** @var StreamFormat $a */
/** @var StreamFormat $b */

return $a->height - $b->height;
});

return $copy;
}

protected function getLowToHighAudioFormats()
{
$copy = array_values($this->getAudioFormats());

// just assume higher filesize => higher quality...
usort($copy, function ($a, $b) {

/** @var StreamFormat $a */
/** @var StreamFormat $b */

return $a->contentLength - $b->contentLength;
});

return $copy;
}

// Combined using: ffmpeg -i video.mp4 -i audio.mp3 output.mp4
public function getSplitFormats($quality = null)
{
// sort formats by quality in desc, and high = first, medium = middle, low = last
$videos = $this->getLowToHighVideoFormats();
$audio = $this->getLowToHighAudioFormats();

if ($quality == 'high' || $quality == 'best') {

return new SplitStream([
'video' => $videos[count($videos) - 1],
'audio' => $audio[count($audio) - 1]
]);

} else if ($quality == 'low' || $quality == 'worst') {

return new SplitStream([
'video' => $videos[0],
'audio' => $audio[0]
]);
}

// something in between!
return new SplitStream([
'video' => $videos[floor(count($videos) / 2)],
'audio' => $audio[floor(count($audio) / 2)]
]);
}
}
2 changes: 1 addition & 1 deletion src/Exception/TooManyRequestsException.php
Expand Up @@ -2,7 +2,7 @@

namespace YouTube\Exception;

use YouTube\Resources\WatchVideoPage;
use YouTube\Responses\WatchVideoPage;

class TooManyRequestsException extends YouTubeException
{
Expand Down
@@ -1,6 +1,6 @@
<?php

namespace YouTube\Data;
namespace YouTube\Models;

abstract class AbstractModel
{
Expand Down
11 changes: 11 additions & 0 deletions src/Models/SplitStream.php
@@ -0,0 +1,11 @@
<?php

namespace YouTube\Models;

class SplitStream extends AbstractModel
{
/** @var StreamFormat */
public $video;
/** @var StreamFormat */
public $audio;
}
7 changes: 6 additions & 1 deletion src/Data/StreamFormat.php → src/Models/StreamFormat.php
@@ -1,6 +1,6 @@
<?php

namespace YouTube\Data;
namespace YouTube\Models;

class StreamFormat extends AbstractModel
{
Expand All @@ -15,4 +15,9 @@ class StreamFormat extends AbstractModel
public $audioSampleRate;
public $url;
public $signatureCipher;

public function getCleanMimeType()
{
return trim(preg_replace('/;.*/', '', $this->mimeType));
}
}
50 changes: 50 additions & 0 deletions src/Models/VideoDetails.php
@@ -0,0 +1,50 @@
<?php

namespace YouTube\Models;

use YouTube\Utils\Utils;

class VideoDetails
{
protected $videoDetails = array();

private function __construct($videoDetails)
{
$this->videoDetails = $videoDetails;
}

/**
* From `videoDetails` array that appears inside JSON on /watch or /get_video_info pages
* @param $array
* @return static
*/
public static function fromPlayerResponseArray($array)
{
return new static(Utils::arrayGet($array, 'videoDetails'));
}

public function getId()
{
return Utils::arrayGet($this->videoDetails, 'videoId');
}

public function getTitle()
{
return Utils::arrayGet($this->videoDetails, 'title');
}

public function getKeywords()
{
return Utils::arrayGet($this->videoDetails, 'keywords');
}

public function getShortDescription()
{
return Utils::arrayGet($this->videoDetails, 'shortDescription');
}

public function getViewCount()
{
return Utils::arrayGet($this->videoDetails, 'viewCount');
}
}
@@ -1,6 +1,6 @@
<?php

namespace YouTube\Resources;
namespace YouTube\Responses;

use YouTube\Utils\Utils;

Expand All @@ -16,6 +16,10 @@ public function isError()
return Utils::arrayGet($this->getJson(), 'errorcode') !== null;
}

/**
* About same as `player_response` that appears on video pages.
* @return array
*/
public function getPlayerResponse()
{
$playerResponse = Utils::arrayGet($this->getJson(), 'player_response');
Expand Down
@@ -1,6 +1,6 @@
<?php

namespace YouTube\Resources;
namespace YouTube\Responses;

use Curl\Response;

Expand Down
@@ -1,6 +1,6 @@
<?php

namespace YouTube\Resources;
namespace YouTube\Responses;

class VideoPlayerJs extends HttpResponse
{
Expand Down
@@ -1,8 +1,7 @@
<?php

namespace YouTube\Resources;
namespace YouTube\Responses;

use YouTube\Browser;
use YouTube\Utils\Utils;

class WatchVideoPage extends HttpResponse
Expand Down Expand Up @@ -31,33 +30,12 @@ public function hasPlayableVideo()
*/
public function getPlayerScriptUrl()
{
$player_url = null;

// check what player version that video is using
if (preg_match('@<script\s*src="([^"]+player[^"]+js)@', $this->getResponseBody(), $matches)) {
$player_url = $matches[1];

// relative protocol?
if (strpos($player_url, '//') === 0) {
$player_url = 'http://' . substr($player_url, 2);
} elseif (strpos($player_url, '/') === 0) {
// relative path?
$player_url = 'http://www.youtube.com' . $player_url;
}
return Utils::relativeToAbsoluteUrl($matches[1], 'https://www.youtube.com');
}

return $player_url;
}

// TODO: this does not belong here
public function getCachedPlayerContents()
{
$url = $this->getPlayerScriptUrl();

$browser = new Browser();
$response = $browser->cachedGet($url);

return new VideoPlayerJs($response);
return null;
}

public function getPlayerResponse()
Expand All @@ -71,6 +49,6 @@ public function getPlayerResponse()
return json_decode($match, true);
}

return null;
return array();
}
}

0 comments on commit bf0eb53

Please sign in to comment.