4get/scraper/yt.php

1735 lines
32 KiB
PHP
Raw Permalink Normal View History

2023-07-22 18:41:14 +00:00
<?php
//$yt = new youtube();
//header("Content-Type: application/json");
//echo json_encode($yt->video("minecraft", null, "today", "any", "any", "live", "relevance"));
2024-04-21 23:48:14 +00:00
class yt{
2023-07-22 18:41:14 +00:00
public function __construct(){
2023-11-07 13:04:56 +00:00
include "lib/backend.php";
$this->backend = new backend("yt");
2023-07-22 18:41:14 +00:00
}
public function getfilters($page){
if($page != "videos"){
return [];
}
return [
"date" => [
"display" => "Time posted",
"option" => [
"any" => "Any time",
"hour" => "Last hour",
"today" => "Today",
"week" => "This week",
"month" => "This month",
"year" => "This year"
]
],
"type" => [
"display" => "Type",
"option" => [
"video" => "Video",
"channel" => "Channel",
"playlist" => "Playlist",
"Movie" => "Movie"
]
],
"duration" => [
"display" => "Duration",
"option" => [
"any" => "Any duration",
"short" => "Short (>4min)",
"medium" => "Medium (4-20min)",
"long" => "Long (<20min)"
]
],
"feature" => [
"display" => "Feature",
"option" => [
"any" => "No features",
"live" => "Live",
"4k" => "4K",
"hd" => "HD",
"subtitles" => "Subtitles/CC",
"creativecommons" => "Creative Commons",
"360" => "VR 360°",
"vr180" => "VR 180°",
"3d" => "3D",
"hdr" => "HDR"
]
],
"sort" => [
"display" => "Sort by",
"option" => [
"relevance" => "Relevance",
"upload_date" => "Upload date",
"view_count" => "View count",
"rating" => "Rating"
]
]
];
}
private function ytfilter($date, $type, $duration, $feature, $sort){
// ------------
// INCOMPATIBLE FILTERS
// channel,playlist DURATION, FEATURES, SORT BY
// Movie Features=[live, subtitles, creative commons, 3d]
// live, 3D
// Type[channel, playlist, movie]
// UPLOAD DATE, DURATION, 4k, 360, VR180, HDR
// Type[channel, playlist]
// -----------
// MUST BE TOGETHER
// Relevance,upload date Type=Video
switch($type){
case "channel":
case "playlist":
if($duration != "any"){ $duration = "any"; }
if($feature != "any"){ $feature = "any"; }
if($sort != "any"){ $sort = "any"; }
break;
case "movie":
if(
in_array(
$feature,
[
"live",
"subtitles",
"creative_commons",
"3d"
],
)
){
$feature = "any";
}
break;
}
switch($feature){
case "live":
case "3d":
if(
in_array(
$type,
[
"channel",
"playlist",
"movie"
],
)
){
$type = "video";
}
break;
}
if(
(
$date != "any" ||
$duration != "any" ||
$feature == "4k" ||
$feature == "360" ||
$feature == "vr180" ||
$feature == "hdr"
) &&
(
$type == "channel" ||
$type == "playlist"
)
){
$type = "video";
}
if(
$date == "any" &&
$type == "video" &&
$duration == "any" &&
$feature == "any" &&
$sort == "relevance"
){
return null;
}
//print_r([$date, $type, $duration, $feature, $sort]);
/*
Encode hex data
*/
// UPLOAD DATE
// hour EgQIARAB 12 04 08 01 10 01
// today EgQIAhAB 12 04 08 02 10 01
// week EgQIAxAB 12 04 08 03 10 01
// month EgQIBBAB 12 04 08 04 10 01
// year EgQIBRAB 12 04 08 05 10 01
// TYPE
// video EgIQAQ%253D%253D 12 02 10 01
// channel EgIQAg%253D%253D 12 02 10 02
// playlist EgIQAw%253D%253D 12 02 10 03
// movie EgIQBA%253D%253D 12 02 10 04
// DURATION
// -4min EgIYAQ%253D%253D 12 02 18 01
// 4-20min EgIYAw%253D%253D 12 02 18 03
// 20+min EgIYAg%253D%253D 12 02 18 02
// FEATURE
// live EgJAAQ%253D%253D 12 02 40 01
// 4K EgJwAQ%253D%253D 12 02 70 01
// HD EgIgAQ%253D%253D 12 02 20 01
// Subtitles/CC EgIoAQ%253D%253D 12 02 28 01
// Creative Commons EgIwAQ%253D%253D 12 02 30 01
// 360 EgJ4AQ%253D%253D 12 02 78 01
// VR180 EgPQAQE%253D 12 03 d0 01 01
// 3D EgI4AQ%253D%253D 12 02 38 01
// HDR EgPIAQE%253D 12 03 c8 01 01
// (location & purchased unused)
// SORT BY
// Relevance CAASAhAB 08 00 12 02 10 01 (is nothing by default)
// Upload date CAI%253D 08 02
// View count CAM%253D 08 03
// Rating CAE%253D 08 01
// video
// 12 02 10 01
// under 4 minutes
// 12 02 18 01
// video + under 4 minutes
// 12 04 10 01 18 01
// video + under 4 minutes + HD
// 08 00 12 06 10 01 18 01 20 01
// video + under 4 minutes + upload date
// 08 02 12 04 10 01 18 01
// video + under 4 minutes + HD + upload date
// 08 02 12 06 10 01 18 01 20 01
// this year + video + under 4 minutes + HD + upload date
// 08 02 12 08 08 05 10 01 18 01 20 01
// this week + video + over 20 minutes + HD + view count
// 08 03 12 08 08 03 10 01 18 02 20 01
//echo urlencode(urlencode(base64_encode(hex2bin($str))));
//echo bin2hex(base64_decode(urldecode(urldecode("CAI%253D"))));
// week + video + 20min + rating
// 08 01 12 06 08 03 10 01 18 02
// week + video + 20min + live + rating
// 08 01 12 08 08 03 10 01 18 02 40 01
// live 12 02 40 01
$hex = null;
if(
$date == "any" &&
$type == "video" &&
$duration == "any" &&
$feature == "any" &&
$sort == "relevance"
){
return $hex;
}
$opcode = 0;
if($date != "any"){ $opcode += 2; }
if($type != "any"){ $opcode += 2; }
if($duration != "any"){ $opcode += 2; }
switch($feature){
case "live":
case "4k":
case "hd":
case "subtitles":
case "creativecommons":
case "360":
case "3d":
$opcode += 2;
break;
case "hdr":
case "vr180":
$opcode += 3;
break;
}
switch($sort){
case "relevance": $hex .= "0800"; break;
case "upload_date": $hex .= "0802"; break;
case "view_count": $hex .= "0803"; break;
case "rating": $hex .= "0801"; break;
}
$hex .= "12" . "0".$opcode;
switch($date){
case "hour": $hex .= "0801"; break;
case "today": $hex .= "0802"; break;
case "week": $hex .= "0803"; break;
case "month": $hex .= "0804"; break;
case "year": $hex .= "0805"; break;
}
switch($type){
case "video": $hex .= "1001"; break;
case "channel": $hex .= "1002"; break;
case "playlist": $hex .= "1003"; break;
case "movie": $hex .= "1004"; break;
}
switch($duration){
case "short": $hex .= "1801"; break;
case "medium": $hex .= "1803"; break;
case "long": $hex .= "1802"; break;
}
switch($feature){
case "live": $hex .= "4001"; break;
case "4k": $hex .= "7001"; break;
case "hd": $hex .= "2001"; break;
case "subtitles": $hex .= "2801"; break;
case "creativecommons": $hex .= "3001"; break;
case "360": $hex .= "7801"; break;
case "vr180": $hex .= "d00101"; break;
case "3d": $hex .= "3801"; break;
case "hdr": $hex .= "c80101"; break;
}
//echo $hex . "\n\n";
return urlencode(base64_encode(hex2bin($hex)));
}
// me reading youtube's json
// https://imgur.com/X9hVlFX
const req_web = 0;
const req_xhr = 1;
2023-11-07 13:04:56 +00:00
private function get($proxy, $url, $get = [], $reqtype = self::req_web, $continuation = null){
2023-07-22 18:41:14 +00:00
$curlproc = curl_init();
if($get !== []){
$get = http_build_query($get);
$url .= "?" . $get;
}
curl_setopt($curlproc, CURLOPT_URL, $url);
switch($reqtype){
case self::req_web:
$headers =
2023-11-07 13:04:56 +00:00
["User-Agent: " . config::USER_AGENT,
2023-07-22 18:41:14 +00:00
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language: en-US,en;q=0.5",
"Accept-Encoding: gzip",
"Cookie: PREF=tz=America.New_York",
"DNT: 1",
"Connection: keep-alive",
"Upgrade-Insecure-Requests: 1",
"Sec-Fetch-Dest: document",
"Sec-Fetch-Mode: navigate",
"Sec-Fetch-Site: none",
"Sec-Fetch-User: ?1"];
break;
case self::req_xhr:
$headers =
2023-11-07 13:04:56 +00:00
["User-Agent: " . config::USER_AGENT,
2023-07-22 18:41:14 +00:00
"Accept: */*",
"Accept-Language: en-US,en;q=0.5",
"Accept-Encoding: gzip",
"Cookie: PREF=tz=America.New_York",
"Referer: https://youtube.com.com/",
"Content-Type: application/json",
"Content-Length: " . strlen($continuation),
"DNT: 1",
"Connection: keep-alive",
"Sec-Fetch-Dest: empty",
"Sec-Fetch-Mode: same-origin",
"Sec-Fetch-Site: same-origin"];
curl_setopt($curlproc, CURLOPT_POST, true);
curl_setopt($curlproc, CURLOPT_POSTFIELDS, $continuation);
break;
}
curl_setopt($curlproc, CURLOPT_ENCODING, ""); // default encoding
curl_setopt($curlproc, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curlproc, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curlproc, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curlproc, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($curlproc, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($curlproc, CURLOPT_TIMEOUT, 30);
2023-11-07 13:04:56 +00:00
$this->backend->assign_proxy($curlproc, $proxy);
2023-07-22 18:41:14 +00:00
$data = curl_exec($curlproc);
if(curl_errno($curlproc)){
throw new Exception(curl_error($curlproc));
}
curl_close($curlproc);
return $data;
}
public function video($get){
$this->out = [
"status" => "ok",
"npt" => null,
"video" => [],
"author" => [],
"livestream" => [],
"playlist" => [],
"reel" => []
];
if($get["npt"]){
// parse nextPage
// https://www.youtube.com/youtubei/v1/search?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8&prettyPrint=false
/*
$handle = fopen("nextpage.json", "r");
$json = fread($handle, filesize("nextpage.json"));
fclose($handle);*/
2023-11-07 13:04:56 +00:00
[$npt, $proxy] =
$this->backend->get(
$get["npt"],
"videos"
2023-07-22 18:41:14 +00:00
);
2023-11-07 13:04:56 +00:00
$npt = json_decode($npt, true);
2023-07-22 18:41:14 +00:00
try{
$json = $this->get(
2023-11-07 13:04:56 +00:00
$proxy,
2023-07-22 18:41:14 +00:00
"https://www.youtube.com/youtubei/v1/search",
[
"key" => $npt["key"],
"prettyPrint" => "false"
],
self::req_xhr,
json_encode($npt["post"])
);
}catch(Exception $error){
throw new Exception("Could not fetch results page");
}
$json = json_decode($json);
foreach(
$json
->onResponseReceivedCommands[0]
->appendContinuationItemsAction
->continuationItems[0]
->itemSectionRenderer
->contents
as $video
){
$this->parsevideoobject($video);
}
if(
!isset(
$json
->onResponseReceivedCommands[0]
->appendContinuationItemsAction
->continuationItems[1]
->continuationItemRenderer
->continuationEndpoint
->continuationCommand
->token
)
){
$npt = null;
}else{
// prepare nextpage for later..
$npt["post"]["continuation"] =
$json
->onResponseReceivedCommands[0]
->appendContinuationItemsAction
->continuationItems[1]
->continuationItemRenderer
->continuationEndpoint
->continuationCommand
->token;
}
$this->out["npt"] = $npt;
}else{
$search = $get["s"];
if(strlen($search) === 0){
throw new Exception("Search term is empty!");
}
2023-11-07 13:04:56 +00:00
$proxy = $this->backend->get_ip();
2023-07-22 18:41:14 +00:00
$date = $get["date"];
$type = $get["type"];
$duration = $get["duration"];
$feature = $get["feature"];
$sort = $get["sort"];
// parse ytInitialData
$get = [
"search_query" => $search
];
if(
(
$filter =
$this->ytfilter(
$date,
$type,
$duration,
$feature,
$sort
)
) !== null
){
$get["sp"] = $filter;
}
try{
$json = $this->get(
2023-11-07 13:04:56 +00:00
$proxy,
2023-07-22 18:41:14 +00:00
"https://www.youtube.com/results",
$get
);
}catch(Exception $error){
throw new Exception("Could not fetch results page");
}
/*
$handle = fopen("test.html", "r");
$json = fread($handle, filesize("test.html"));
fclose($handle);
*/
if(
!preg_match(
'/ytcfg\.set\(({".*})\); *window\.ytcfg/',
$json,
$ytconfig
)
){
throw new Exception("Could not get ytcfg");
}
$ytconfig = json_decode($ytconfig[1]);
if(
!preg_match(
'/ytInitialData *= *({.*});<\/script>/',
$json,
$json
)
){
throw new Exception("Could not get ytInitialData");
}
$json = json_decode($json[1]);
// generate POST data for nextpage
$ytconfig->INNERTUBE_CONTEXT->client->screenWidthPoints = 1239;
$ytconfig->INNERTUBE_CONTEXT->client->screenHeightPoints = 999;
$ytconfig->INNERTUBE_CONTEXT->client->screenPixelDensity = 1;
$ytconfig->INNERTUBE_CONTEXT->client->screenDensityFloat = 1;
$ytconfig->INNERTUBE_CONTEXT->client->utcOffsetMinutes = -240;
$ytconfig->INNERTUBE_CONTEXT->request->internalExperimentFlags = [];
$ytconfig->INNERTUBE_CONTEXT->request->consistencyTokenJars = [];
$ytconfig->INNERTUBE_CONTEXT->client->mainAppWebInfo = [
"graftUrl" => $ytconfig->INNERTUBE_CONTEXT->client->originalUrl,
"webDisplayMode" => "WEB_DISPLAY_MODE_BROWSER",
"isWebNativeShareAvailable" => false
];
$ytconfig->INNERTUBE_CONTEXT->adSignalsInfo = [
"params" => [
[
"key" => "dt",
"value" => (string)$ytconfig->TIME_CREATED_MS
],
[
"key" => "flash",
"value" => "0"
],
[
"key" => "frm",
"value" => "0"
],
[
"key" => "u_tz",
"value" => "-240"
],
[
"key" => "u_his",
"value" => "3"
],
[
"key" => "u_h",
"value" => "1080"
],
[
"key" => "u_w",
"value" => "1920"
],
[
"key" => "u_ah",
"value" => "1080"
],
[
"key" => "u_cd",
"value" => "24"
],
[
"key" => "bc",
"value" => "31"
],
[
"key" => "bih",
"value" => "999"
],
[
"key" => "biw",
"value" => "1239"
],
[
"key" => "brdim",
"value" => "0,0,0,0,1920,0,1920,1061,1239,999"
],
[
"key" => "vis",
"value" => "1"
],
[
"key" => "wgl",
"value" => "true"
],
[
"key" => "ca_type",
"value" => "image"
]
]
];
/*
echo json_encode($json);
die();*/
// *inhales*
foreach(
$json
->contents
->twoColumnSearchResultsRenderer
->primaryContents
->sectionListRenderer
->contents[0]
->itemSectionRenderer
->contents
as $video
){
$this->parsevideoobject($video);
}
// get additional data from secondaryContents
if(
isset(
$json
->contents
->twoColumnSearchResultsRenderer
->secondaryContents
->secondarySearchContainerRenderer
->contents[0]
->universalWatchCardRenderer
)
){
$video =
$json
->contents
->twoColumnSearchResultsRenderer
->secondaryContents
->secondarySearchContainerRenderer
->contents[0]
->universalWatchCardRenderer;
/*
echo json_encode($video);
die();*/
$author =
[
"name" =>
$video
->header
->watchCardRichHeaderRenderer
->title
->simpleText,
"url" =>
"https://www.youtube.com/channel/" .
$video
->header
->watchCardRichHeaderRenderer
->titleNavigationEndpoint
->browseEndpoint
->browseId,
"avatar" => null
];
if(
isset(
$video
->header
->watchCardRichHeaderRenderer
->avatar
->thumbnails[0]
->url
)
){
$author["avatar"] =
$video
->header
->watchCardRichHeaderRenderer
->avatar
->thumbnails[0]
->url;
}
// add video in callToAction if present
if(
isset(
$video
->callToAction
->watchCardHeroVideoRenderer
->lengthText
)
){
array_push(
$this->out["video"],
[
"title" =>
$video
->callToAction
->watchCardHeroVideoRenderer
->title
->simpleText,
"description" => null,
"author" => $author,
"date" =>
$this->textualdate2unix(
trim(
explode(
"",
$video
->callToAction
->watchCardHeroVideoRenderer
->subtitle
->simpleText
)[2]
)
),
"duration" =>
$this->hms2int(
$video
->callToAction
->watchCardHeroVideoRenderer
->lengthText
->simpleText
),
"views" =>
$this->truncatedcount2int(
trim(
explode(
"",
$video
->callToAction
->watchCardHeroVideoRenderer
->subtitle
->simpleText,
2
)[1]
)
),
"thumb" => [
"url" =>
$video
->callToAction
->watchCardHeroVideoRenderer
->heroImage
->singleHeroImageRenderer
->thumbnail
->thumbnails[0]
->url,
"ratio" => "16:9"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$video
->callToAction
->watchCardHeroVideoRenderer
->navigationEndpoint
->watchEndpoint
->videoId
]
);
}
// get all playlists, ignore videos
$out = null;
foreach(
$video
->sections
as $section
){
if(
isset(
$section
->watchCardSectionSequenceRenderer
->lists[0]
->horizontalCardListRenderer
->cards
)
){
$out =
$section
->watchCardSectionSequenceRenderer
->lists[0]
->horizontalCardListRenderer
->cards;
break;
}
}
if($out !== null){
foreach(
$out as $video
){
if(
!isset(
$video
->searchRefinementCardRenderer
)
){
continue;
}
$video =
$video
->searchRefinementCardRenderer;
array_push(
$this->out["playlist"],
[
"title" =>
$video
->query
->runs[0]
->text,
"description" => null,
"author" => $author,
"date" => null,
"duration" => null,
"views" => null,
"thumb" => [
"url" =>
$video
->thumbnail
->thumbnails[0]
->url,
"ratio" => "1:1"
],
"url" =>
"https://www.youtube.com" .
$video
->searchEndpoint
->commandMetadata
->webCommandMetadata
->url
]
);
}
}
}
foreach(
$json
->contents
->twoColumnSearchResultsRenderer
->primaryContents
->sectionListRenderer
->contents
as $cont
){
if(isset($cont->continuationItemRenderer)){
$this->out["npt"] = [
"key" =>
$ytconfig
->INNERTUBE_API_KEY,
"post" => [
"context" =>
$ytconfig
->INNERTUBE_CONTEXT,
"continuation" =>
$cont
->continuationItemRenderer
->continuationEndpoint
->continuationCommand
->token
]
];
break;
}
}
}
if($this->out["npt"] !== null){
2023-11-07 13:04:56 +00:00
$this->out["npt"] =
$this->backend->store(
json_encode(
$this->out["npt"]
),
"videos",
$proxy
);
2023-07-22 18:41:14 +00:00
}
return $this->out;
}
private function parsevideoobject($video){
if(isset($video->videoRenderer)){
$video = $video->videoRenderer;
$description = null;
if(isset($video->detailedMetadataSnippets)){
foreach(
$video
->detailedMetadataSnippets[0]
->snippetText
->runs
as $description_part
){
$description .= $description_part->text;
}
}
if(
isset(
$video
->badges[0]
->metadataBadgeRenderer
->icon
->iconType
) &&
$video
->badges[0]
->metadataBadgeRenderer
->icon
->iconType
== "LIVE"
){
$type = "livestream";
$date = null;
$duration = "_LIVE";
if(isset($video->viewCountText->runs[0]->text)){
$views =
$this->views2int(
$video
->viewCountText
->runs[0]
->text
);
}else{
$views = null;
}
}else{
$type = "video";
if(isset($video->publishedTimeText->simpleText)){
$date = $this->textualdate2unix(
$video
->publishedTimeText
->simpleText
);
}else{
$date = null;
}
if(isset($video->lengthText->simpleText)){
$duration =
$this->hms2int(
$video
->lengthText
->simpleText
);
}else{
$duration = null;
}
if(isset($video->viewCountText->simpleText)){
$views =
$this->views2int(
$video
->viewCountText
->simpleText
);
}else{
$views = null;
}
}
if(
$video
->navigationEndpoint
->commandMetadata
->webCommandMetadata
->webPageType
== "WEB_PAGE_TYPE_SHORTS"
){
// haha you thought you could get me, youtube
// jokes on you i dont go outside
$type = "reel";
}
array_push(
$this->out[$type],
[
"title" =>
$video
->title
->runs[0]
->text,
"description" =>
$this->titledots($description),
"author" => [
"name" =>
$video
->longBylineText
->runs[0]
->text,
"url" =>
"https://www.youtube.com/channel/" .
$video
->longBylineText
->runs[0]
->navigationEndpoint
->browseEndpoint
->browseId,
"avatar" =>
$this->checkhttpspresence(
$video
->channelThumbnailSupportedRenderers
->channelThumbnailWithLinkRenderer
->thumbnail
->thumbnails[0]
->url
)
],
"date" => $date,
"duration" => $duration,
"views" => $views,
"thumb" => [
"url" =>
$video
->thumbnail
->thumbnails[0]
->url,
"ratio" => "16:9"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$video
->videoId
]
);
}elseif(isset($video->watchCardCompactVideoRenderer)){
$video =
$video
->watchCardCompactVideoRenderer;
array_push(
$this->out["video"],
[
"title" =>
$video
->title
->simpleText,
"description" => null,
"author" => [
"name" =>
$video
->byline
->runs[0]
->text,
"url" =>
"https://www.youtube.com/channel/" .
$video
->byline
->runs[0]
->navigationEndpoint
->browseEndpoint
->browseId,
"avatar" => null
],
"date" =>
$this->textualdate2unix(
trim(
explode(
"",
$video
->subtitle
->simpleText,
2
)[1]
)
),
"duration" =>
$this->hms2int(
$video
->lengthText
->simpleText
),
"views" =>
$this->truncatedcount2int(
trim(
explode(
"",
$video
->subtitle
->simpleText,
2
)[0]
)
),
"thumb" => [
"url" =>
$video
->thumbnail
->thumbnails[0]
->url,
"ratio" => "16:9"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$video
->navigationEndpoint
->watchEndpoint
->videoId
]
);
}elseif(isset($video->reelShelfRenderer)){
foreach(
$video
->reelShelfRenderer
->items
as $reel
){
$reel =
$reel
->reelItemRenderer;
array_push(
$this->out["reel"],
[
"title" =>
$reel
->headline
->simpleText,
"description" => null,
"author" => [
"name" => null,
"url" => null,
"avatar" => null
],
"date" => null,
"duration" =>
$this->textualtime2int(
$reel
->accessibility
->accessibilityData
->label
),
"views" =>
$this->truncatedcount2int(
$reel
->viewCountText
->simpleText
),
"thumb" => [
"url" =>
$reel
->thumbnail
->thumbnails[0]
->url,
"ratio" => "9:16"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$reel
->videoId
]
);
}
}
elseif(isset($video->channelRenderer)){
$video = $video->channelRenderer;
$description = null;
if(isset($video->descriptionSnippet)){
foreach(
$video
->descriptionSnippet
->runs
as $description_part
){
$description .= $description_part->text;
}
}
array_push(
$this->out["author"],
[
"title" =>
$video
->title
->simpleText,
"followers" =>
isset(
$video
->videoCountText
->simpleText
) ?
$this->truncatedcount2int(
$video
->videoCountText
->simpleText
) :
0,
"description" => $this->titledots($description),
"thumb" =>
[
"url" =>
$this->checkhttpspresence(
$video
->thumbnail
->thumbnails[
count(
$video
->thumbnail
->thumbnails
) - 1
]
->url
),
"ratio" => "1:1"
],
"url" =>
"https://www.youtube.com/channel/" .
$video
->channelId
]
);
}
elseif(isset($video->shelfRenderer)){
if(
!is_object(
$video
->shelfRenderer
->content
->verticalListRenderer
)
){
return;
}
foreach(
$video
->shelfRenderer
->content
->verticalListRenderer
->items
as $shelfvideo
){
$this->parsevideoobject($shelfvideo);
}
}elseif(isset($video->radioRenderer)){
$video = $video->radioRenderer;
$description =
$video
->videoCountText
->runs[0]
->text
. ".";
$tmp = [];
foreach(
$video->videos
as $childvideo
){
$tmp[] =
$childvideo
->childVideoRenderer
->title
->simpleText;
}
if(count($tmp) !== 0){
$description .=
" " . implode(", ", $tmp);
}
array_push(
$this->out["playlist"],
[
"title" =>
$video
->title
->simpleText,
"description" => $description,
"author" => [
"name" =>
$video
->longBylineText
->simpleText,
"url" => null,
"avatar" => null
],
"date" => null,
"duration" => null,
"views" => null,
"thumb" => [
"url" =>
$video
->thumbnail
->thumbnails[
count(
$video
->thumbnail
->thumbnails
) - 1
]
->url,
"ratio" => "16:9"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$video
->videos[0]
->childVideoRenderer
->videoId .
"&list=" .
$video
->playlistId .
"&start_radio=1"
]
);
}elseif(isset($video->playlistRenderer)){
$video = $video->playlistRenderer;
$description = $video->videoCount . " videos.";
$tmp = [];
foreach(
$video
->videos
as $childvideo
){
$tmp[] =
$childvideo
->childVideoRenderer
->title
->simpleText;
}
if(count($tmp) !== 0){
$description .=
" " . implode(", ", $tmp);
}
array_push(
$this->out["playlist"],
[
"title" =>
$video
->title
->simpleText,
"description" => $description,
"author" => [
"name" =>
$video
->longBylineText
->runs[0]
->text,
"url" =>
"https://www.youtube.com/channel/" .
$video
->longBylineText
->runs[0]
->navigationEndpoint
->browseEndpoint
->browseId,
"picture" => null
],
"date" => null,
"duration" => null,
"views" => null,
"thumb" =>
[
"url" =>
$video
->thumbnails[0]
->thumbnails[
count(
$video
->thumbnails[0]
->thumbnails
) - 1
]
->url,
"ratio" => "16:9"
],
"url" =>
"https://www.youtube.com/watch?v=" .
$video
->videos[0]
->childVideoRenderer
->videoId .
"&list=" .
$video
->playlistId .
"&start_radio=1"
]
);
}/*else{
if(!isset($video->searchPyvRenderer)){
echo json_encode($video);
die();}
}*/
}
private function textualdate2unix($number){
$number =
explode(
" ",
str_replace(
[
" ago",
"seconds",
"minutes",
"hours",
"days",
"weeks",
"months",
"years"
],
[
"",
"second",
"minute",
"hour",
"day",
"week",
"month",
"year"
],
$number
),
2
);
$time = 0;
switch($number[1]){
case "second":
$time = (int)$number[0];
break;
case "minute":
$time = (int)$number[0] * 60;
break;
case "hour":
$time = (int)$number[0] * 3600;
break;
case "day":
$time = (int)$number[0] * 86400;
break;
case "week":
$time = (int)$number[0] * 604800;
break;
case "month":
$time = (int)$number[0] * 2629746;
break;
case "year":
$time = (int)$number[0] * 31556952;
break;
}
return time() - $time;
}
private function checkhttpspresence($link){
if(substr($link, 0, 2) == "//"){
return "https:" . $link;
}
return $link;
}
private function textualtime2int($number){
$number = explode(" - ", $number);
if(count($number) >= 2){
$number = $number[count($number) - 2];
}else{
$number = $number[0];
}
$number =
str_replace(
[
" ",
"seconds",
"minutes",
"hours",
],
[
"",
"second",
"minute",
"hour"
],
$number
);
preg_match_all(
'/([0-9]+)(second|minute|hour)/',
$number,
$number
);
$time = 0;
for($i=0; $i<count($number[0]); $i++){
switch($number[2][$i]){
case "second":
$time = $time + (int)$number[1][$i];
break;
case "minute":
$time = $time + ((int)$number[1][$i] * 60);
break;
case "hour":
$time = $time + ((int)$number[1][$i] * 3600);
break;
}
}
return $time;
}
private function views2int($views){
return
(int)str_replace(
",", "",
explode(" ", $views, 2)[0]
);
}
private function hms2int($time){
$parts = explode(":", $time, 3);
$time = 0;
if(count($parts) === 3){
// hours
$time = $time + ((int)$parts[0] * 3600);
array_shift($parts);
}
if(count($parts) === 2){
// minutes
$time = $time + ((int)$parts[0] * 60);
array_shift($parts);
}
// seconds
$time = $time + (int)$parts[0];
return $time;
}
private function truncatedcount2int($number){
// decimal should always be 1 number long
$number = explode(" ", $number, 2);
$number = $number[0];
$unit = strtolower($number[strlen($number) - 1]);
$tmp = explode(".", $number, 2);
$number = (int)$number;
if(count($tmp) === 2){
$decimal = (int)$tmp[1];
}else{
$decimal = 0;
}
switch($unit){
case "k":
$exponant = 1000;
break;
case "m":
$exponant = 1000000;
break;
case "b";
$exponant = 1000000000;
break;
default:
$exponant = 1;
break;
}
return ($number * $exponant) + ($decimal * ($exponant / 10));
}
private function titledots($title){
$substr = substr($title, -3);
if(
$substr == "..." ||
$substr == ""
){
return trim(substr($title, 0, -3), " \n\r\t\v\x00\0\x0B\xc2\xa0");
}
return trim($title, " \n\r\t\v\x00\0\x0B\xc2\xa0");
}
}