From 9b8e0a4e0b5e528f7cedbf44c23b0093e7a95d12 Mon Sep 17 00:00:00 2001 From: lolcat Date: Sun, 21 Apr 2024 19:48:14 -0400 Subject: fuck --- scraper/youtube.php | 1734 --------------------------------------------------- scraper/yt.php | 1734 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1734 insertions(+), 1734 deletions(-) delete mode 100644 scraper/youtube.php create mode 100644 scraper/yt.php (limited to 'scraper') diff --git a/scraper/youtube.php b/scraper/youtube.php deleted file mode 100644 index 526b026..0000000 --- a/scraper/youtube.php +++ /dev/null @@ -1,1734 +0,0 @@ -video("minecraft", null, "today", "any", "any", "live", "relevance")); - -class youtube{ - - public function __construct(){ - - include "lib/backend.php"; - $this->backend = new backend("yt"); - } - - 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; - - private function get($proxy, $url, $get = [], $reqtype = self::req_web, $continuation = null){ - - $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 = - ["User-Agent: " . config::USER_AGENT, - "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 = - ["User-Agent: " . config::USER_AGENT, - "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); - - $this->backend->assign_proxy($curlproc, $proxy); - - $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);*/ - - [$npt, $proxy] = - $this->backend->get( - $get["npt"], - "videos" - ); - - $npt = json_decode($npt, true); - - try{ - $json = $this->get( - $proxy, - "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!"); - } - - $proxy = $this->backend->get_ip(); - $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( - $proxy, - "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){ - - $this->out["npt"] = - $this->backend->store( - json_encode( - $this->out["npt"] - ), - "videos", - $proxy - ); - } - - 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; $ivideo("minecraft", null, "today", "any", "any", "live", "relevance")); + +class yt{ + + public function __construct(){ + + include "lib/backend.php"; + $this->backend = new backend("yt"); + } + + 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; + + private function get($proxy, $url, $get = [], $reqtype = self::req_web, $continuation = null){ + + $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 = + ["User-Agent: " . config::USER_AGENT, + "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 = + ["User-Agent: " . config::USER_AGENT, + "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); + + $this->backend->assign_proxy($curlproc, $proxy); + + $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);*/ + + [$npt, $proxy] = + $this->backend->get( + $get["npt"], + "videos" + ); + + $npt = json_decode($npt, true); + + try{ + $json = $this->get( + $proxy, + "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!"); + } + + $proxy = $this->backend->get_ip(); + $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( + $proxy, + "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){ + + $this->out["npt"] = + $this->backend->store( + json_encode( + $this->out["npt"] + ), + "videos", + $proxy + ); + } + + 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