fix(musicseerr): implement session-based conversion triggering and polling in Tubidy scraper
Build and Push Docker Images / deploy (push) Blocked by required conditions Details
Build and Push Docker Images / build (api) (push) Successful in 1m14s Details
Build and Push Docker Images / build (musicseerr) (push) Successful in 6m26s Details
Build and Push Docker Images / build (web) (push) Successful in 2m11s Details
Build and Push Docker Images / build (nextgen) (push) Successful in 9m49s Details
Build and Push Docker Images / build (worker) (push) Has been cancelled Details

This commit is contained in:
fchinembiri 2026-07-10 20:40:39 +02:00
parent 732f71700c
commit 0bf96f0213
1 changed files with 55 additions and 13 deletions

View File

@ -148,6 +148,7 @@ def search_tubidy(query: str, proxy_url: str) -> list:
def get_tubidy_download_link(content_id: str, proxy_url: str) -> str: def get_tubidy_download_link(content_id: str, proxy_url: str) -> str:
""" """
Queries watch.php for the given content ID to find the direct MP3 download URL. Queries watch.php for the given content ID to find the direct MP3 download URL.
Supports initiating and polling the conversion process if the video is not yet processed.
""" """
proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None
headers = { headers = {
@ -166,23 +167,64 @@ def get_tubidy_download_link(content_id: str, proxy_url: str) -> str:
logger.info(f"Fetching watch.php for content ID '{content_id}'") logger.info(f"Fetching watch.php for content ID '{content_id}'")
try: try:
response = cf_requests.get(watch_url, headers=headers, params=params, proxies=proxies, impersonate="chrome", timeout=15) session = cf_requests.Session()
if proxies:
session.proxies = proxies
session.headers.update(headers)
response = session.get(watch_url, params=params, impersonate="chrome", timeout=15)
response.raise_for_status() response.raise_for_status()
soup = BeautifulSoup(response.text, "html.parser") def extract_link(html: str) -> str:
for li in soup.find_all("li", class_=lambda x: x and "list-group-item" in x and "big" in x): soup = BeautifulSoup(html, "html.parser")
a_tag = li.find("a") # 1. Search in list-group-item big tags
if a_tag: for li in soup.find_all("li", class_=lambda x: x and "list-group-item" in x and "big" in x):
a_tag = li.find("a")
if a_tag:
text = a_tag.text.lower()
href = a_tag.get("href")
if href and "download" in text:
return urljoin(watch_url, href)
# 2. General fallback search for direct download/mp3 links
for a_tag in soup.find_all("a", href=True):
text = a_tag.text.lower() text = a_tag.text.lower()
href = a_tag.get("href") href = a_tag["href"]
if href and "download" in text: if "download" in text and "act=process" not in href and "act=down" not in href:
return href return urljoin(watch_url, href)
if (".mp3" in href.lower() or "video.mp3.tubidy.cool" in href.lower()) and "act=process" not in href:
return urljoin(watch_url, href)
return ""
# Fallback to general scraping of the watch.php page if structure differs link = extract_link(response.text)
if link:
return link
# If no link found, check if there is a process link
soup = BeautifulSoup(response.text, "html.parser")
process_link = None
for a_tag in soup.find_all("a", href=True): for a_tag in soup.find_all("a", href=True):
text = a_tag.text.lower() if "act=process" in a_tag["href"]:
if "download" in text and "act=process" not in a_tag["href"]: process_link = urljoin(watch_url, a_tag["href"])
return a_tag["href"] break
if process_link:
logger.info(f"Triggering Tubidy processing step for content ID '{content_id}' via {process_link}")
proc_resp = session.get(process_link, impersonate="chrome", timeout=15)
proc_resp.raise_for_status()
# Wait for conversion (typically takes 5-10s on Tubidy server)
import time
wait_time = 10
logger.info(f"Waiting {wait_time} seconds for conversion to finish...")
time.sleep(wait_time)
# Re-fetch the download page
response = session.get(watch_url, params=params, impersonate="chrome", timeout=15)
response.raise_for_status()
link = extract_link(response.text)
if link:
return link
except Exception as e: except Exception as e:
logger.error(f"Failed to fetch download link for {content_id}: {e}") logger.error(f"Failed to fetch download link for {content_id}: {e}")