diff --git a/custom_libs/subliminal_patch/providers/animekalesi.py b/custom_libs/subliminal_patch/providers/animekalesi.py index 937806105..e18a375af 100644 --- a/custom_libs/subliminal_patch/providers/animekalesi.py +++ b/custom_libs/subliminal_patch/providers/animekalesi.py @@ -7,6 +7,7 @@ import os import zipfile from random import randint from typing import Optional, Dict, List, Set +from datetime import datetime, timedelta from babelfish import Language from guessit import guessit @@ -19,11 +20,15 @@ from subliminal.subtitle import fix_line_ending from subliminal.video import Episode from subliminal_patch.utils import sanitize, fix_inconsistent_naming from subzero.language import Language +from subliminal.cache import region from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST logger = logging.getLogger(__name__) +# Cache expiration times +SEARCH_EXPIRATION_TIME = timedelta(weeks=1).total_seconds() + def fix_turkish_chars(text: str) -> str: """Fix Turkish characters for proper matching.""" if not text: @@ -53,7 +58,8 @@ class AnimeKalesiSubtitle(Subtitle): provider_name = 'animekalesi' hearing_impaired_verifiable = False - def __init__(self, language: Language, page_link: str, series: str, season: int, episode: int, version: str, download_link: str, uploader: str = None): + def __init__(self, language: Language, page_link: str, series: str, season: int, episode: int, + version: str, download_link: str, uploader: str = None, release_group: str = None): super().__init__(language) self.page_link = page_link self.series = series @@ -64,7 +70,7 @@ class AnimeKalesiSubtitle(Subtitle): self.release_info = version self.matches = set() self.uploader = uploader - self.release_group = None + self.release_group = release_group self.hearing_impaired = False @property @@ -102,19 +108,14 @@ class AnimeKalesiSubtitle(Subtitle): if video.release_group.lower() in self.release_group.lower(): matches.add('release_group') - #matches |= guess_matches(video, guessit(self.version)) - matches.add('year') - matches.add('video_codec') - matches.add('audio_codec') - matches.add('resolution') - matches.add('streaming_service') + matches |= guess_matches(video, guessit(self.version)) self.matches = matches return matches class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): """AnimeKalesi Provider.""" - languages = {Language('tur')} | {Language('tur', 'TR')} | {Language.fromietf('tr')} + languages = {Language('tur')} video_types = (Episode,) server_url = 'https://www.animekalesi.com' subtitle_class = AnimeKalesiSubtitle @@ -136,6 +137,7 @@ class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): def terminate(self): self.session.close() + @region.cache_on_arguments(expiration_time=SEARCH_EXPIRATION_TIME) def _search_anime_list(self, series: str) -> Optional[Dict[str, str]]: """Search for series in anime list.""" if not series: @@ -196,6 +198,36 @@ class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): logger.error('Error parsing season/episode from title "%s": %s', title, e) return None, None + @region.cache_on_arguments(expiration_time=SEARCH_EXPIRATION_TIME) + def _get_episode_list(self, series_url: str) -> Optional[List[Dict[str, str]]]: + """Get episode list for a series.""" + if not series_url: + return None + + try: + subtitle_page_url = f'{self.server_url}/{series_url.replace("bolumler-", "altyazib-")}' + response = self.session.get(subtitle_page_url, timeout=10) + response.raise_for_status() + soup = BeautifulSoup(response.content, 'html.parser') + + episodes = [] + for td in soup.select('td#ayazi_indir'): + link = td.find('a', href=True) + if not link: + continue + + if 'indir_bolum-' in link['href'] and 'Bölüm Türkçe Altyazısı' in link.get('title', ''): + episodes.append({ + 'title': link['title'], + 'url': f"{self.server_url}/{link['href']}" + }) + + return episodes + + except Exception as e: + logger.error('Error getting episode list: %s', e) + return None + def query(self, series: str, season: int, episode: int) -> List[AnimeKalesiSubtitle]: """Search subtitles from AnimeKalesi.""" if not series or not season or not episode: @@ -209,82 +241,75 @@ class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): logger.debug('Series not found: %s', series) return subtitles + # Get episode list + episodes = self._get_episode_list(series_data['url']) + if not episodes: + return subtitles + try: - # Navigate to subtitle page - subtitle_page_url = f'{self.server_url}/{series_data["url"].replace("bolumler-", "altyazib-")}' - response = self.session.get(subtitle_page_url, timeout=10) - response.raise_for_status() - soup = BeautifulSoup(response.content, 'html.parser') + for episode_data in episodes: + title = episode_data['title'] + link_url = episode_data['url'] - # Scan all episode links - for td in soup.select('td#ayazi_indir'): - link = td.find('a', href=True) - if not link: + # Extract season and episode numbers + current_season, current_episode = self._parse_season_episode(title) + if current_season is None or current_episode is None: continue - if 'indir_bolum-' in link['href'] and 'Bölüm Türkçe Altyazısı' in link.get('title', ''): - title = link['title'] - link_url = f"{self.server_url}/{link['href']}" - - # Extract season and episode numbers - current_season, current_episode = self._parse_season_episode(title) - if current_season is None or current_episode is None: + if current_season == season and current_episode == episode: + try: + # Navigate to subtitle download page + response = self.session.get(link_url, timeout=10) + response.raise_for_status() + soup = BeautifulSoup(response.content, 'html.parser') + + # Find download link + subtitle_div = soup.find('div', id='altyazi_indir') + if subtitle_div and subtitle_div.find('a', href=True): + download_link = f"{self.server_url}/{subtitle_div.find('a')['href']}" + + # Find uploader information + uploader = None + translator_info = soup.find('strong', text='Altyazı/Çeviri:') + if translator_info and translator_info.parent: + strong_tags = translator_info.parent.find_all('strong') + for i, tag in enumerate(strong_tags): + if tag.text == 'Altyazı/Çeviri:': + if i + 1 < len(strong_tags): + uploader = tag.next_sibling + if uploader: + uploader = uploader.strip() + else: + uploader = tag.next_sibling + if uploader: + uploader = uploader.strip() + break + + version = f"{series_data['title']} - S{current_season:02d}E{current_episode:02d}" + if uploader: + version += f" by {uploader}" + + try: + subtitle = self.subtitle_class( + Language('tur'), + link_url, + series_data['title'], + current_season, + current_episode, + version, + download_link, + uploader=uploader, + release_group=None + ) + subtitles.append(subtitle) + except Exception as e: + logger.error('Error creating subtitle object: %s', e) + continue + + except Exception as e: + logger.error('Error processing subtitle page %s: %s', link_url, e) continue - if current_season == season and current_episode == episode: - try: - # Navigate to subtitle download page - response = self.session.get(link_url, timeout=10) - response.raise_for_status() - soup = BeautifulSoup(response.content, 'html.parser') - - # Find download link - subtitle_div = soup.find('div', id='altyazi_indir') - if subtitle_div and subtitle_div.find('a', href=True): - download_link = f"{self.server_url}/{subtitle_div.find('a')['href']}" - - # Find uploader information - uploader = None - translator_info = soup.find('strong', text='Altyazı/Çeviri:') - if translator_info and translator_info.parent: - strong_tags = translator_info.parent.find_all('strong') - for i, tag in enumerate(strong_tags): - if tag.text == 'Altyazı/Çeviri:': - if i + 1 < len(strong_tags): - uploader = tag.next_sibling - if uploader: - uploader = uploader.strip() - else: - uploader = tag.next_sibling - if uploader: - uploader = uploader.strip() - break - - version = f"{series_data['title']} - S{current_season:02d}E{current_episode:02d}" - if uploader: - version += f" by {uploader}" - - try: - subtitle = self.subtitle_class( - Language('tur'), - link_url, - series_data['title'], - current_season, - current_episode, - version, - download_link, - uploader=uploader - ) - subtitle.release_group = None - subtitles.append(subtitle) - except Exception as e: - logger.error('Error creating subtitle object: %s', e) - continue - - except Exception as e: - logger.error('Error processing subtitle page %s: %s', link_url, e) - continue - except Exception as e: logger.error('Error querying subtitles: %s', e) @@ -294,11 +319,6 @@ class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): if not video.series or not video.episode: return [] - # Language check - both alpha3 and IETF codes - supported_languages = {l for l in languages if l.alpha3 == 'tur' or l.alpha2 == 'tr'} - if not supported_languages: - return [] - return self.query(video.series, video.season, video.episode) def download_subtitle(self, subtitle: AnimeKalesiSubtitle) -> None: @@ -330,3 +350,4 @@ class AnimeKalesiProvider(Provider, ProviderSubtitleArchiveMixin): except Exception as e: logger.error('Error downloading subtitle: %s', e) +