|
|
import subprocess |
|
|
from functools import wraps |
|
|
from bs4 import BeautifulSoup |
|
|
from tqdm import tqdm |
|
|
import json |
|
|
import requests |
|
|
|
|
|
def start_tor_and_wait(tor_path="tor"): |
|
|
process = subprocess.Popen( |
|
|
[tor_path], |
|
|
stdout=subprocess.PIPE, |
|
|
stderr=subprocess.STDOUT, |
|
|
text=True, |
|
|
bufsize=1 |
|
|
) |
|
|
for line in process.stdout: |
|
|
print(line) |
|
|
if "Bootstrapped 100% (done)" in line: |
|
|
print("✅ Tor fully started") |
|
|
return process |
|
|
return None |
|
|
|
|
|
class SocksProxy: |
|
|
def __init__(self, proxy_url): |
|
|
self.proxies = {"http": proxy_url, "https": proxy_url} |
|
|
self._original_request = None |
|
|
|
|
|
def __enter__(self): |
|
|
self._original_request = requests.sessions.Session.request |
|
|
|
|
|
def patched_request(session, method, url, **kwargs): |
|
|
kwargs.setdefault("proxies", self.proxies) |
|
|
return self._original_request(session, method, url, **kwargs) |
|
|
|
|
|
requests.sessions.Session.request = patched_request |
|
|
|
|
|
def __exit__(self, exc_type, exc_val, exc_tb): |
|
|
requests.sessions.Session.request = self._original_request |
|
|
|
|
|
def use_proxy(proxy_url="socks5h://127.0.0.1:9050"): |
|
|
def decorator(func): |
|
|
@wraps(func) |
|
|
def wrapper(*args, **kwargs): |
|
|
with SocksProxy(proxy_url): |
|
|
return func(*args, **kwargs) |
|
|
return wrapper |
|
|
return decorator |
|
|
|
|
|
class YTDownloader: |
|
|
@use_proxy() |
|
|
def __init__(self): |
|
|
self.api = self.get_api() |
|
|
|
|
|
def get_between(self,src,left_str,right_str): |
|
|
return src.split(left_str)[1].split(right_str)[0] |
|
|
|
|
|
@use_proxy() |
|
|
def __call__(self, id, download_file="output.opus"): |
|
|
data = [v for i,v in self.get_yt_audio_data(id).items() if "OPUS-audio" in i][-1] |
|
|
return self.download_file(self.get_yt_link(self.get_task_id(data['resource_content'])),download_file) |
|
|
|
|
|
def download_file(self, url, output_file): |
|
|
response = requests.get(url, stream=True) |
|
|
total_size = int(response.headers.get('content-length', 0)) |
|
|
chunk_size = 1024 |
|
|
|
|
|
with open(output_file, 'wb') as file, tqdm( |
|
|
desc=output_file, |
|
|
total=total_size, |
|
|
unit='B', |
|
|
unit_scale=True, |
|
|
unit_divisor=1024, |
|
|
) as bar: |
|
|
for chunk in response.iter_content(chunk_size=chunk_size): |
|
|
if chunk: |
|
|
file.write(chunk) |
|
|
bar.update(len(chunk)) |
|
|
return output_file |
|
|
|
|
|
def get_yt_audio_data(self,id): |
|
|
return {"-".join([i['quality'],i['format'],i['type']]):i for i in requests.post('https://api.vidssave.com/api/contentsite_api/media/parse', headers={ |
|
|
'accept': '*/*', |
|
|
'accept-language': 'en-GB,en;q=0.9,gu;q=0.8,en-US;q=0.7,hi;q=0.6', |
|
|
'content-type': 'application/x-www-form-urlencoded', |
|
|
'dnt': '1', |
|
|
'origin': 'https://vidssave.com', |
|
|
'priority': 'u=1, i', |
|
|
'referer': 'https://vidssave.com/', |
|
|
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', |
|
|
'sec-ch-ua-mobile': '?0', |
|
|
'sec-ch-ua-platform': '"Windows"', |
|
|
'sec-fetch-dest': 'empty', |
|
|
'sec-fetch-mode': 'cors', |
|
|
'sec-fetch-site': 'same-site', |
|
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', |
|
|
}, data={ |
|
|
'auth': self.api, |
|
|
'domain': 'api-ak.vidssave.com', |
|
|
'origin': 'source', |
|
|
'link': f'https://youtu.be/{id}', |
|
|
}).json()['data']['resources']} |
|
|
|
|
|
def get_api(self): |
|
|
for i in BeautifulSoup(requests.get('https://vidssave.com/yt', headers={ |
|
|
'accept': '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.7', |
|
|
'accept-language': 'en-GB,en;q=0.9,gu;q=0.8,en-US;q=0.7,hi;q=0.6', |
|
|
'cache-control': 'max-age=0', |
|
|
'dnt': '1', |
|
|
'if-modified-since': 'Thu, 05 Feb 2026 09:20:05 GMT', |
|
|
'priority': 'u=0, i', |
|
|
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', |
|
|
'sec-ch-ua-mobile': '?0', |
|
|
'sec-ch-ua-platform': '"Windows"', |
|
|
'sec-fetch-dest': 'document', |
|
|
'sec-fetch-mode': 'navigate', |
|
|
'sec-fetch-site': 'same-origin', |
|
|
'sec-fetch-user': '?1', |
|
|
'upgrade-insecure-requests': '1', |
|
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', |
|
|
}).text,"html.parser").find_all("script"): |
|
|
try: |
|
|
if i.has_attr("async"): |
|
|
i = i['src'].split("/")[4] |
|
|
if ".js" in i: |
|
|
return self.get_between(requests.get("https://vidssave.com/_next/static/chunks/"+i, headers={'sec-ch-ua-platform': '"Windows"', 'Referer': 'https://vidssave.com/yt', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', 'DNT': '1', 'sec-ch-ua-mobile': '?0'}).text,'auth:"','",') |
|
|
except: |
|
|
pass |
|
|
|
|
|
def get_task_id(self,resource_id): |
|
|
return requests.post('https://api.vidssave.com/api/contentsite_api/media/download', headers={ |
|
|
'accept': '*/*', |
|
|
'accept-language': 'en-GB,en;q=0.9,gu;q=0.8,en-US;q=0.7,hi;q=0.6', |
|
|
'content-type': 'application/x-www-form-urlencoded', |
|
|
'dnt': '1', |
|
|
'origin': 'https://vidssave.com', |
|
|
'priority': 'u=1, i', |
|
|
'referer': 'https://vidssave.com/', |
|
|
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', |
|
|
'sec-ch-ua-mobile': '?0', |
|
|
'sec-ch-ua-platform': '"Windows"', |
|
|
'sec-fetch-dest': 'empty', |
|
|
'sec-fetch-mode': 'cors', |
|
|
'sec-fetch-site': 'same-site', |
|
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', |
|
|
}, data={ |
|
|
'auth': self.api, |
|
|
'domain': 'api-ak.vidssave.com', |
|
|
'request': resource_id, |
|
|
'no_encrypt': '1', |
|
|
}).json()['data']['task_id'] |
|
|
|
|
|
def get_yt_link(self,task_id): |
|
|
return json.loads(requests.get( |
|
|
f'https://api.vidssave.com/sse/contentsite_api/media/download_query?auth={self.api}&domain=api-ak.vidssave.com&task_id={task_id}&download_domain=vidssave.com&origin=content_site', |
|
|
headers={ |
|
|
'accept': 'text/event-stream', |
|
|
'accept-language': 'en-GB,en;q=0.9,gu;q=0.8,en-US;q=0.7,hi;q=0.6', |
|
|
'cache-control': 'no-cache', |
|
|
'dnt': '1', |
|
|
'origin': 'https://vidssave.com', |
|
|
'priority': 'u=1, i', |
|
|
'referer': 'https://vidssave.com/', |
|
|
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"', |
|
|
'sec-ch-ua-mobile': '?0', |
|
|
'sec-ch-ua-platform': '"Windows"', |
|
|
'sec-fetch-dest': 'empty', |
|
|
'sec-fetch-mode': 'cors', |
|
|
'sec-fetch-site': 'same-site', |
|
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36', |
|
|
}, |
|
|
).text.strip().split("\n")[-1].lstrip("data: "))['download_link'] |
|
|
|
|
|
start_tor_and_wait() |
|
|
client = YTDownloader() |
|
|
import gradio as gr |
|
|
def f(x,prog=gr.Progress(True)): |
|
|
return client(x) |
|
|
gr.Interface(client,gr.Textbox(),gr.Audio()).launch() |