import os, subprocess, asyncio, json async def nodeFetchInternal(url, data): sp = await asyncio.create_subprocess_exec( "node", "--disable-warning", "DEP0040", os.path.join(os.path.abspath(os.path.dirname(__file__)), "fetch-with-node/index.js"), url, data, stdout=asyncio.subprocess.PIPE ) out = await sp.stdout.read() out = out.decode("utf-8").rstrip() try: asJson = json.loads(out) except Exception: print("ERROR") print(out) return None return asJson def nodeFetch(url, data): return asyncio.run(nodeFetchInternal(url, data)) async def protodecInternal(input, flags): sp = subprocess.Popen( 'echo \'' + input + '\' | ' + os.path.join(os.path.abspath(os.path.dirname(__file__)), "protodec") + ' ' + flags, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) out = sp.communicate()[0] out = out.decode("utf-8").rstrip() return out def protodec(input, flags): return asyncio.run(protodecInternal(input, flags)) ### defaultHeaders = { "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US,en;q=0.9", "Content-Type": "application/json; charset=UTF-8", "Cookie": "GPS=1; YSC=q6STb5ub1CU; VISITOR_INFO1_LIVE=Hbzrltf2qrk; VISITOR_PRIVACY_METADATA=CgJVUxIEGgAgCg%3D%3D; ", "DNT": "1", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-Site": "same-origin", "User-Agent": "com.google.android.youtube/19.02.39 (Linux; U; Android 14) gzip", #"x-goog-api-format-version" => "2", #"x-youtube-client-name" => client_config.name_proto, #"x-youtube-client-version" => client_config.version, } cachedInnertubeContent = { "client": { "hl":"en", "gl":"US", "remoteHost":"98.200.139.166", "deviceMake":"", "deviceModel":"", "visitorData":"CgtIYnpybHRmMnFyayjf8s63BjIKCgJVUxIEGgAgCg%3D%3D", "userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0,gzip(gfe)", "clientName":"WEB", "clientVersion":"2.20240924.01.00", "osName":"Windows", "osVersion":"10.0", "originalUrl":"https://www.youtube.com/", "platform":"DESKTOP", "clientFormFactor":"UNKNOWN_FORM_FACTOR", "configInfo": { "appInstallData":"CN_yzrcGEI3QsQUQ3-2wBRDh7LAFEMnmsAUQooGwBRCPw7EFEImnsQUQ6sOvBRCDvLEFEI2UsQUQws2xBRCI468FEJzRsQUQ782wBRCFp7EFEK7BsQUQ2cmvBRDvx7EFEJKusQUQxtCxBRCdprAFEO_LsQUQ7KixBRCEtrAFEIzNsQUQppKxBRCSwP8SEJ3QsAUQt-r-EhDwu7EFEJSJsQUQms6xBRComrAFENCNsAUQ49GwBRDbvrEFEKrYsAUQsO6wBRC9tq4FENPhrwUQppqwBRCinbEFEPirsQUQt--vBRCWlbAFEPSrsAUQhcOxBRDmz7EFEJmYsQUQ4tSuBRCNzLAFEP7XsAUQ47qxBRC9mbAFEMfUsQUQvYqwBRDW3bAFEOW5sQUQkMyxBRC8vrEFEIiHsAUQx8qxBRCHw7EFEN3o_hIQgsawBRD5zLEFEI_QsQUQieiuBRDRuLEFEOOVsAUQksuxBRDq0LEFENfprwUQr8exBRCKobEFEMX1sAUQydewBRDGpLEFEN6tsQUQ65mxBRDtubEFEMW_sQUQx-awBRDN17AFEMi_sQUQ86KxBRDM364FEJT-sAUQ9quwBRCBw7EFEKaTsQUQyfevBRDr6P4SENuvrwUQ28GxBRDiq7EFEPjGsQUQ_dGxBRD7rbEFEMvCsQUQ2dKxBRDszf8SENrNsQUqJENBTVNGeFVVcGIyd0ROemtCb096OUF2b3NRU3ctUTc1UWgwSA%3D%3D" }, "userInterfaceTheme":"USER_INTERFACE_THEME_LIGHT", "browserName":"Firefox", "browserVersion":"102.0", "acceptHeader":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "deviceExperimentId":"ChxOelF4T0RRM05qZ3lPVE0zT0RBek16UTROZz09EN_yzrcGGN_yzrcG" } } def browse(*kwargs, browseId=None, continuation=None, params=None): data = { "headers": defaultHeaders, "referrer": "https://www.youtube.com/", "referrerPolicy": "strict-origin-when-cross-origin", "body": { "context": cachedInnertubeContent }, "method": "POST", "mode": "cors" } if browseId is not None: data["body"]["browseId"] = browseId if continuation is not None: data["body"]["continuation"] = continuation if params is not None: data["body"]["params"] = params data["body"] = json.dumps(data["body"]) return nodeFetch("https://www.youtube.com/youtubei/v1/browse?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8", json.dumps(data)) def next(data=None, continuation=None): newData = { "headers": defaultHeaders, "referrer": "https://www.youtube.com/", "referrerPolicy": "strict-origin-when-cross-origin", "body": { "context": cachedInnertubeContent }, "method": "POST", "mode": "cors" } if data is not None: for k in data: newData["body"][k] = data[k] if continuation is not None: newData["body"]["continuation"] = continuation newData["body"] = json.dumps(newData["body"]) return nodeFetch("https://www.youtube.com/youtubei/v1/next?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8", json.dumps(newData))