From f3779f00cd7a14452df77f09fb9f3e165906caab Mon Sep 17 00:00:00 2001 From: fchinembiri Date: Fri, 10 Jul 2026 20:57:29 +0200 Subject: [PATCH] fix(musicseerr): enhance Tubidy search with query variations and censorship handling --- apps/musicseerr/tasks.py | 101 +++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/apps/musicseerr/tasks.py b/apps/musicseerr/tasks.py index fe3c90f..ef7d9e9 100644 --- a/apps/musicseerr/tasks.py +++ b/apps/musicseerr/tasks.py @@ -96,6 +96,7 @@ def scrape_tubidy_link(url: str, proxy_url: str) -> str: def search_tubidy(query: str, proxy_url: str) -> list: """ Searches Tubidy for the query and returns a list of results with ID, title, and link. + Includes robust fallback variations if the initial search returns no results. """ proxies = {"http": proxy_url, "https": proxy_url} if proxy_url else None headers = { @@ -115,31 +116,83 @@ def search_tubidy(query: str, proxy_url: str) -> list: response = cf_requests.get(search_url, headers=headers, params=params, proxies=proxies, impersonate="chrome", timeout=15) response.raise_for_status() - soup = BeautifulSoup(response.text, "html.parser") - results = [] + def parse_results(html: str) -> list: + soup = BeautifulSoup(html, "html.parser") + results_list = [] + for media_body in soup.find_all("div", class_="media-body"): + a_tag = media_body.find("a") + if a_tag: + href = a_tag.get("href") + if href: + title = a_tag.get("aria-label") or a_tag.text.strip() + match = re.search(r'/watch/([^/]+)', href) + content_id = match.group(1) if match else None + link = href + if href.startswith("//"): + link = f"https:{href}" + elif href.startswith("/"): + link = f"{endpoint}{href}" + + if content_id: + results_list.append({ + "id": content_id, + "title": title, + "link": link + }) + return results_list + + results = parse_results(response.text) + if results: + return results + + # Fallback query variations if first search yielded no results + variations = [] - for media_body in soup.find_all("div", class_="media-body"): - a_tag = media_body.find("a") - if a_tag: - href = a_tag.get("href") - if href: - title = a_tag.get("aria-label") or a_tag.text.strip() - # Extract ID from /watch/content_id - match = re.search(r'/watch/([^/]+)', href) - content_id = match.group(1) if match else None - link = href - if href.startswith("//"): - link = f"https:{href}" - elif href.startswith("/"): - link = f"{endpoint}{href}" - - if content_id: - results.append({ - "id": content_id, - "title": title, - "link": link - }) - return results + # Variation 1: Clean basic symbols and parentheticals + clean1 = re.sub(r'[\(\[][^\)\]]*[\)\]]', '', query) + clean1 = clean1.replace("-", " ") + clean1 = re.sub(r'\s+', ' ', clean1).strip() + variations.append(clean1) + + # Variation 2: Clean and also remove feat/ft + clean2 = re.sub(r'(?i)\b(feat|ft)\.?\b.*$', '', clean1) + clean2 = re.sub(r'[^\w\s]', '', clean2) + clean2 = re.sub(r'\s+', ' ', clean2).strip() + variations.append(clean2) + + # Variation 3: Handle censored words (e.g. fucked -> f*cked, fuck -> f*ck) + if "fucked" in clean2.lower() or "fuck" in clean2.lower(): + clean3 = re.sub(r'(?i)\bfucked\b', 'f*cked', clean2) + clean3 = re.sub(r'(?i)\bfuck\b', 'f*ck', clean3) + variations.append(clean3) + + # Variation 4: Try just the artist and the first 2 words of the title + parts = query.split(" - ", 1) + if len(parts) == 2: + artist = re.sub(r'[^\w\s]', '', parts[0]).strip() + title_words = re.sub(r'[^\w\s]', '', parts[1]).strip().split() + if len(title_words) > 1: + clean4 = f"{artist} {' '.join(title_words[:1])}" + variations.append(clean4) + + # Try each variation in order + for var in variations: + var = var.strip() + if not var or var == query: + continue + logger.info(f"Retrying Tubidy search with variation: '{var}'") + params["q"] = var + try: + response = cf_requests.get(search_url, headers=headers, params=params, proxies=proxies, impersonate="chrome", timeout=15) + response.raise_for_status() + new_results = parse_results(response.text) + if new_results: + logger.info(f"Found {len(new_results)} results for variation '{var}'") + return new_results + except Exception as e: + logger.warning(f"Variation search for '{var}' failed: {e}") + + return [] except Exception as e: logger.error(f"Failed to search Tubidy: {e}") return []