feat: Improve Anime-Sama search with fuzzy matching
Replace direct URL conversion with official Anime-Sama search API that handles typos, partial matches, and returns multiple results with cover images. Changes: - Use /template-php/defaut/fetch.php API endpoint for search - Parse HTML search results to extract title, URL, and cover image - Return multiple results instead of single direct match - Support for fuzzy matching (e.g., "hell paradise" finds "Hell's Paradise") Examples: - "hell paradise" → finds "Hell's Paradise" (handles missing 's') - "one pie" → finds "One Piece" (handles incomplete words) - "dragon" → returns 5 Dragon Ball series with cover images Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -350,42 +350,68 @@ class AnimeSamaDownloader(BaseDownloader):
|
|||||||
"""
|
"""
|
||||||
Search for anime on anime-sama
|
Search for anime on anime-sama
|
||||||
Returns list of anime with title, url, and cover image
|
Returns list of anime with title, url, and cover image
|
||||||
|
Uses the official Anime-Sama search API which handles typos and fuzzy matching
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Update domains before searching to ensure we have the current domain
|
# Update domains before searching to ensure we have the current domain
|
||||||
await self.update_domains()
|
await self.update_domains()
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
from html import unescape
|
||||||
start = time.time()
|
start = time.time()
|
||||||
print(f"[ANIME-SAMA] Searching for '{query}' ({lang})...")
|
print(f"[ANIME-SAMA] Searching for '{query}' ({lang})...")
|
||||||
|
|
||||||
# Use the current domain from anime-sama.pw
|
# Use the current domain from anime-sama.pw
|
||||||
current_domain = await self.get_current_domain()
|
current_domain = await self.get_current_domain()
|
||||||
|
|
||||||
# Convert query to URL format (lowercase, replace spaces with hyphens)
|
# Use the official search API endpoint
|
||||||
query_formatted = query.lower().replace(' ', '-').replace("'", '').replace(':', '')
|
search_api_url = f"https://{current_domain}/template-php/defaut/fetch.php"
|
||||||
search_url = f"https://{current_domain}/catalogue/{query_formatted}/saison1/{lang}/"
|
|
||||||
|
|
||||||
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
|
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:
|
if response.status_code == 200 and response.text.strip():
|
||||||
# Check if it's a valid anime page by looking for episode selector
|
# Parse HTML results
|
||||||
if 'selectEpisodes' in response.text or 'episodes.js' in response.text:
|
soup = BeautifulSoup(response.text, 'lxml')
|
||||||
print(f"[ANIME-SAMA] Found anime at {str(response.url)}")
|
results = []
|
||||||
return [{
|
|
||||||
'title': query,
|
|
||||||
'url': str(response.url),
|
|
||||||
'type': 'direct'
|
|
||||||
}]
|
|
||||||
|
|
||||||
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 []
|
return []
|
||||||
|
|
||||||
except Exception as e:
|
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 []
|
return []
|
||||||
|
|
||||||
async def get_episodes(self, anime_url: str, lang: str = "vostfr") -> list[dict]:
|
async def get_episodes(self, anime_url: str, lang: str = "vostfr") -> list[dict]:
|
||||||
|
|||||||
Reference in New Issue
Block a user