diff --git a/app/downloaders/animesama.py b/app/downloaders/animesama.py index c5ebadb..a493a77 100644 --- a/app/downloaders/animesama.py +++ b/app/downloaders/animesama.py @@ -350,42 +350,68 @@ class AnimeSamaDownloader(BaseDownloader): """ Search for anime on anime-sama Returns list of anime with title, url, and cover image + Uses the official Anime-Sama search API which handles typos and fuzzy matching """ try: # Update domains before searching to ensure we have the current domain await self.update_domains() import time + from html import unescape start = time.time() print(f"[ANIME-SAMA] Searching for '{query}' ({lang})...") # Use the current domain from anime-sama.pw current_domain = await self.get_current_domain() - # Convert query to URL format (lowercase, replace spaces with hyphens) - query_formatted = query.lower().replace(' ', '-').replace("'", '').replace(':', '') - search_url = f"https://{current_domain}/catalogue/{query_formatted}/saison1/{lang}/" + # Use the official search API endpoint + search_api_url = f"https://{current_domain}/template-php/defaut/fetch.php" - response = await self.client.get(search_url, follow_redirects=True) + # Make POST request to search API + response = await self.client.post( + search_api_url, + data={'query': query}, + headers={'Content-Type': 'application/x-www-form-urlencoded'} + ) elapsed = time.time() - start - print(f"[ANIME-SAMA] Got response {response.status_code} in {elapsed:.2f}s") + print(f"[ANIME-SAMA] Got search response in {elapsed:.2f}s") - if response.status_code == 200: - # Check if it's a valid anime page by looking for episode selector - if 'selectEpisodes' in response.text or 'episodes.js' in response.text: - print(f"[ANIME-SAMA] Found anime at {str(response.url)}") - return [{ - 'title': query, - 'url': str(response.url), - 'type': 'direct' - }] + if response.status_code == 200 and response.text.strip(): + # Parse HTML results + soup = BeautifulSoup(response.text, 'lxml') + results = [] - print(f"[ANIME-SAMA] No anime found (status: {response.status_code})") + # Extract all search result links + for link in soup.find_all('a', class_='asn-search-result'): + href = link.get('href', '') + title_elem = link.find('h3', class_='asn-search-result-title') + img_elem = link.find('img', class_='asn-search-result-img') + + title = unescape(title_elem.get_text()) if title_elem else "Unknown" + cover_image = img_elem.get('src', '') if img_elem else None + + # Add language parameter to URL + if '/saison1/' not in href: + href = href.rstrip('/') + f'/saison1/{lang}/' + + results.append({ + 'title': title, + 'url': href, + 'cover_image': cover_image, + 'type': 'search_result' + }) + + print(f"[ANIME-SAMA] Found {len(results)} results") + return results + + print(f"[ANIME-SAMA] No results found") return [] except Exception as e: - print(f"[ANIME-SAMA] Error: {str(e)}") + print(f"[ANIME-SAMA] Search error: {str(e)}") + import traceback + traceback.print_exc() return [] async def get_episodes(self, anime_url: str, lang: str = "vostfr") -> list[dict]: