| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405 |
- <?php
- 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, deflate, br, zstd",
- "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, deflate, br, zstd",
- "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){
-
- $out = [
- "status" => "ok",
- "npt" => null,
- "video" => [],
- "author" => [],
- "livestream" => [],
- "playlist" => [],
- "reel" => []
- ];
-
- if($get["npt"]){
-
- $first_page = false;
-
- [$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 search page");
- }
-
- $json = json_decode($json, true);
- }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 search page");
- }
-
- //$json = file_get_contents("scraper/yt.html");
-
- // get next page data, unique to first page
- if(
- !preg_match(
- '/ytcfg\.set\(({".*})\); *window\.ytcfg/',
- $json,
- $ytconfig
- )
- ){
-
- throw new Exception("Could not get ytcfg");
- }
-
- $ytconfig = json_decode($ytconfig[1], true);
- $first_page = true;
-
- // this is where all of the data is
- if(
- !preg_match(
- '/ytInitialData *= *({.*});<\/script>/',
- $json,
- $json
- )
- ){
-
- throw new Exception("Could not get ytInitialData");
- }
-
- $json = json_decode($json[1], true);
- /*$first_page = true;
- $json = json_decode(file_get_contents("scraper/yt.html"), true);*/
- }
-
- $items = [
- "channelRenderer" => [],
- "videoRenderer" => [],
- "shortsLockupViewModel" => [],
- "lockupViewModel" => [], // playlists
- "continuationItemRenderer" => [], // pagination
- "backgroundPromoRenderer" => [] // errors
- ];
-
- $search = [
- "channelRenderer",
- "videoRenderer",
- "shortsLockupViewModel",
- "lockupViewModel",
- "continuationItemRenderer",
- "backgroundPromoRenderer"
- ];
-
- $this->recursive_search($search, $items, $json);
-
- // check for errors
- if(count($items["backgroundPromoRenderer"]) !== 0){
-
- foreach($items["backgroundPromoRenderer"] as $popup){
-
- if(
- isset(
- $popup
- ["title"]
- ["runs"]
- ) &&
- isset(
- $popup
- ["bodyText"]
- ["runs"]
- )
- ){
-
- $error =
- $this->assemble_runs($popup["title"]) . ". " .
- $this->assemble_runs($popup["bodyText"]);
-
- if(str_contains(strtolower($error), "no results found")){
-
- // no results
- return $out;
- }
-
- // other error
- throw new Exception(
- "YouTube returned an error: " .
- $this->assemble_runs($popup["title"]) . ". " .
- $this->assemble_runs($popup["bodyText"])
- );
- }
- }
- }
-
- // add normal videos
- foreach($items["videoRenderer"] as $video){
-
- $show_live_badge = false;
-
- if(
- $video["navigationEndpoint"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["webPageType"]
- == "WEB_PAGE_TYPE_SHORTS"
- ){
-
- $type = "reel";
- }elseif(isset($video["upcomingEventData"])){
-
- // is an upcoming event, categorize as livestream
- $type = "livestream";
-
- }else{
- $type = "video";
-
- // detect if its a livestream
- if(isset($video["badges"])){
-
- foreach($video["badges"] as $badge){
-
- if(
- $badge
- ["metadataBadgeRenderer"]
- ["label"] == "LIVE"
- ){
-
- $type = "livestream";
- $show_live_badge = true;
- break;
- }
- }
- }
- }
-
- $thumbnail =
- $video["thumbnail"]
- ["thumbnails"]
- [0]
- ["url"];
-
- $filename = basename(parse_url($thumbnail, PHP_URL_PATH));
-
- if(
- $filename == "hq720.jpg" ||
- $filename == "mqdefault.jpg"
- ){
-
- // fetch trackerless version
- // its bigger and consumes more bandwidth, but it wont serve
- // blurred out thumbnails
- $thumbnail = "https://i.ytimg.com/vi/{$video["videoId"]}/{$filename}";
- }
-
- $out[$type][] = [
- "title" =>
- $this->assemble_runs(
- $video
- ["title"]
- ),
- "description" =>
- isset(
- $video["detailedMetadataSnippets"]
- [0]
- ["snippetText"]
- ) ?
- $this->titledots(
- $this->assemble_runs(
- $video["detailedMetadataSnippets"]
- [0]
- ["snippetText"]
- )
- ) : null,
- "author" => [
- "name" =>
- $this->assemble_runs(
- $video["longBylineText"]
- ),
- "url" =>
- "https://www.youtube.com" .
- $video["ownerText"]
- ["runs"]
- [0]
- ["navigationEndpoint"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["url"],
- "avatar" =>
- $video["channelThumbnailSupportedRenderers"]
- ["channelThumbnailWithLinkRenderer"]
- ["thumbnail"]
- ["thumbnails"]
- [0]
- ["url"]
- ],
- "date" =>
- isset(
- $video["publishedTimeText"]
- ["simpleText"]
- ) ?
- $this->parse_date(
- trim(
- str_replace(
- "Streamed", "",
- $video["publishedTimeText"]
- ["simpleText"]
- )
- )
- ) : null,
- "duration" =>
- $show_live_badge === true ?
- "_LIVE" :
- (
- isset(
- $video["lengthText"]
- ["simpleText"]
- ) ?
- $this->hms2int(
- $video["lengthText"]
- ["simpleText"]
- ) : null
- ),
- "views" =>
- isset(
- $video["viewCountText"]
- ["simpleText"]
- ) ?
- $this->views2int(
- $video["viewCountText"]
- ["simpleText"]
- ) : null,
- "thumb" => [
- "ratio" => "16:9",
- "url" => $thumbnail
- ],
- "url" => "https://www.youtube.com/watch?v=" . $video["videoId"]
- ];
- }
-
- // add channels
- foreach($items["channelRenderer"] as $channel){
- $out["author"][] = [
- "title" =>
- $channel
- ["title"]
- ["simpleText"],
- "followers" =>
- isset(
- $channel
- ["videoCountText"]
- ["simpleText"]
- ) ?
- $this->truncatedcount2int(
- $channel
- ["videoCountText"]
- ["simpleText"]
- ) :
- null,
- "description" =>
- isset($channel["descriptionSnippet"]) ?
- $this->titledots(
- $this->assemble_runs(
- $channel
- ["descriptionSnippet"]
- )
- ) : null,
- "thumb" =>
- [
- "url" =>
- $this->checkhttpspresence(
- $channel
- ["thumbnail"]
- ["thumbnails"]
- [
- count(
- $channel
- ["thumbnail"]
- ["thumbnails"]
- ) - 1
- ]
- ["url"]
- ),
- "ratio" => "1:1"
- ],
- "url" =>
- "https://www.youtube.com/channel/" .
- $channel
- ["channelId"]
- ];
- }
-
- // add reels
- foreach($items["shortsLockupViewModel"] as $reel){
-
- $out["reel"][] = [
- "title" =>
- $reel
- ["overlayMetadata"]
- ["primaryText"]
- ["content"],
- "description" =>
- isset(
- $reel
- ["overlayMetadata"]
- ["primaryText"]
- ["content"]
- ) ?
- $this->titledots(
- $reel
- ["overlayMetadata"]
- ["primaryText"]
- ["content"]
- ) : null,
- "author" => [
- "name" => null,
- "url" => null,
- "avatar" => null
- ],
- "date" => null,
- "duration" => null,
- "views" =>
- $this->truncatedcount2int(
- $reel
- ["overlayMetadata"]
- ["secondaryText"]
- ["content"]
- ),
- "thumb" => [
- "url" =>
- $reel
- ["thumbnailViewModel"]
- ["thumbnailViewModel"]
- ["image"]
- ["sources"]
- [0]
- ["url"],
- "ratio" => "9:16"
- ],
- "url" =>
- "https://www.youtube.com/watch?v=" .
- $reel
- ["onTap"]
- ["innertubeCommand"]
- ["reelWatchEndpoint"]
- ["videoId"]
- ];
- }
-
- // add playlists
- foreach($items["lockupViewModel"] as $playlist){
-
- // get author of playlist
- $author_name = null;
- $author_url = null;
-
- if(
- !isset(
- $playlist
- ["metadata"]
- ["lockupMetadataViewModel"]
- ["title"]
- ["content"]
- ) ||
- !isset(
- $playlist
- ["itemPlayback"]
- ["inlinePlayerData"]
- ["onSelect"]
- ["innertubeCommand"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["url"]
- )
- ){
-
- // got an ad viewmodel or some invalid item with no link
- // i dont know why the fuck that happens dont ask me
- continue;
- }
-
- foreach(
- $playlist
- ["metadata"]
- ["lockupMetadataViewModel"]
- ["metadata"]
- ["contentMetadataViewModel"]
- ["metadataRows"]
- [0]
- ["metadataParts"]
- as $possible_author
- ){
-
- if(
- isset(
- $possible_author
- ["text"]
- ["commandRuns"]
- [0]
- ["onTap"]
- ["innertubeCommand"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["webPageType"]
- ) &&
- $possible_author
- ["text"]
- ["commandRuns"]
- [0]
- ["onTap"]
- ["innertubeCommand"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["webPageType"] == "WEB_PAGE_TYPE_CHANNEL"
- ){
-
- $author_name = $possible_author["text"]["content"];
-
- $author_url =
- "https://www.youtube.com" .
- $possible_author
- ["text"]
- ["commandRuns"]
- [0]
- ["onTap"]
- ["innertubeCommand"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["url"];
-
- break;
- }
- }
-
- $out["playlist"][] = [
- "title" =>
- $playlist
- ["metadata"]
- ["lockupMetadataViewModel"]
- ["title"]
- ["content"],
- "description" => null,
- "author" => [
- "name" => $author_name,
- "url" => $author_url,
- "avatar" => null
- ],
- "date" => null,
- "duration" => null,
- "views" => null,
- "thumb" => [
- "url" =>
- $playlist
- ["contentImage"]
- ["collectionThumbnailViewModel"]
- ["primaryThumbnail"]
- ["thumbnailViewModel"]
- ["image"]
- ["sources"]
- [0]
- ["url"],
- "ratio" => "16:9"
- ],
- "url" =>
- "https://www.youtube.com" .
- $playlist
- ["itemPlayback"]
- ["inlinePlayerData"]
- ["onSelect"]
- ["innertubeCommand"]
- ["commandMetadata"]
- ["webCommandMetadata"]
- ["url"]
- ];
- }
-
- // get next page
- $found_npt = false;
-
- if($first_page === true){
- // we're using the old pagination trick, google now sends encrypted data
- if(count($items["continuationItemRenderer"]) !== 0){
-
- $ytconfig["INNERTUBE_CONTEXT"]["client"]["screenWidthPoints"] = 1920;
- $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"]["client"]["internalExperimentFlags"] = [];
- $ytconfig["INNERTUBE_CONTEXT"]["client"]["concistencyTokenJars"] = [];
-
- $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" => "1920"
- ],
- [
- "key" => "brdim",
- "value" => "0,0,0,0,1920,0,1920,1061,1920,999"
- ],
- [
- "key" => "vis",
- "value" => "1"
- ],
- [
- "key" => "wgl",
- "value" => "true"
- ],
- [
- "key" => "ca_type",
- "value" => "image"
- ]
- ]
- ];
-
- $found_npt = true;
- $npt = [
- "key" =>
- $ytconfig
- ["INNERTUBE_API_KEY"],
- "post" => [
- "context" =>
- $ytconfig
- ["INNERTUBE_CONTEXT"],
- "continuation" =>
- $items
- ["continuationItemRenderer"]
- [0]
- ["continuationEndpoint"]
- ["continuationCommand"]
- ["token"]
- ]
- ];
- }
- }else{
-
- // handle next page for json endpoint
- if(count($items["continuationItemRenderer"]) !== 0){
-
- $found_npt = true;
- $npt["post"]["continuation"] =
- $items
- ["continuationItemRenderer"]
- [0]
- ["continuationEndpoint"]
- ["continuationCommand"]
- ["token"];
- }
- }
-
- if($found_npt){
-
- $out["npt"] =
- $this->backend->store(
- json_encode(
- $npt
- ),
- "videos",
- $proxy
- );
- }
-
- return $out;
- }
-
- private function recursive_search(&$search, &$items, &$pointer){
-
- foreach($pointer as $key => $value){
-
- if(
- in_array(
- $key,
- $search
- )
- ){
-
- // found interesting item
- $items[$key][] = $value;
-
- }elseif(is_array($value)){
-
- $this->recursive_search($search, $items, $value);
- }
- }
- }
-
- 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 str_replace(["\r", "\n"], " ", trim(substr($title, 0, -3), " \n\r\t\v\x00\0\x0B\xc2\xa0"));
- }
-
- return str_replace(["\r", "\n"], " ", trim($title, " \n\r\t\v\x00\0\x0B\xc2\xa0"));
- }
-
- private function parse_date($date){
-
- if(
- preg_match(
- '/^([0-9]+)(s|m|h|d|w|mo|y) ago$/',
- $date,
- $control_chars
- )
- ){
-
- switch($control_chars[2]){
-
- case "s": $selection = "seconds"; break;
- case "m": $selection = "minutes"; break;
- case "h": $selection = "hours"; break;
- case "d": $selection = "days"; break;
- case "w": $selection = "weeks"; break;
- case "mo": $selection = "months"; break;
- case "y": $selection = "years"; break;
- default: return null;
- }
-
- $date = "{$control_chars[1]} {$selection} ago";
- }
-
- $out = strtotime($date);
-
- if($out === false){ $out = null; }
-
- return $out;
- }
-
- private function assemble_runs($runs){
-
- if(!isset($runs["runs"])){ return ""; }
-
- $text = "";
-
- foreach($runs["runs"] as $run){
-
- if(isset($run["text"])){
-
- $text .= $run["text"];
- }
- }
-
- return $text;
- }
- }
|