diff --git a/src/transcript_extractor.py b/src/transcript_extractor.py index 0976310..c000667 100644 --- a/src/transcript_extractor.py +++ b/src/transcript_extractor.py @@ -220,13 +220,46 @@ class TranscriptExtractor: else: logger.warning(f"[FLARESOLVERR] ⚠️ Transcript URL'leri bulunamadı HTML'de") else: - # POST istekleri için JSON kontrolü - try: - import json - json.loads(response_content) - logger.debug(f"[FLARESOLVERR] ✅ POST response geçerli JSON") - except: - logger.warning(f"[FLARESOLVERR] ⚠️ POST response JSON değil, HTML olabilir") + # POST istekleri için JSON kontrolü ve HTML içindeki JSON extract + import re + import json + + # HTML içinde JSON var mı kontrol et (
tag'i içinde olabilir)
+ if response_content.strip().startswith(']*>(.*?)', response_content, re.DOTALL)
+ if json_match:
+ json_content = json_match.group(1).strip()
+ try:
+ parsed_json = json.loads(json_content)
+ logger.debug(f"[FLARESOLVERR] ✅ POST response HTML içinde JSON bulundu ve parse edildi")
+
+ # Hata kontrolü
+ if 'error' in parsed_json:
+ error_code = parsed_json.get('error', {}).get('code', 'unknown')
+ error_message = parsed_json.get('error', {}).get('message', 'unknown')
+ error_status = parsed_json.get('error', {}).get('status', '')
+ logger.warning(f"[FLARESOLVERR] ⚠️ POST response'unda hata: {error_code} - {error_message}")
+
+ # FAILED_PRECONDITION hatası varsa, FlareSolverr POST istekleri için uygun değil
+ if error_code == 400 and 'FAILED_PRECONDITION' in error_status:
+ logger.warning(f"[FLARESOLVERR] ⚠️ YouTube API FlareSolverr POST isteklerini reddediyor (FAILED_PRECONDITION)")
+ logger.warning(f"[FLARESOLVERR] POST istekleri için FlareSolverr kullanılmayacak")
+
+ # HTML yerine JSON kullan (response_content'i güncelle)
+ response_content = json_content
+ logger.debug(f"[FLARESOLVERR] ✅ POST response HTML'den JSON extract edildi")
+ except json.JSONDecodeError:
+ logger.warning(f"[FLARESOLVERR] ⚠️ POST response HTML içindeki JSON parse edilemedi")
+ else:
+ logger.warning(f"[FLARESOLVERR] ⚠️ POST response HTML ama içinde JSON bulunamadı")
+ else:
+ # Direkt JSON kontrolü
+ try:
+ json.loads(response_content)
+ logger.debug(f"[FLARESOLVERR] ✅ POST response geçerli JSON")
+ except:
+ logger.warning(f"[FLARESOLVERR] ⚠️ POST response JSON değil")
# Response objesine transcript URL'lerini ve analiz sonuçlarını ekle (alternatif parse için)
response_obj = FlareSolverrResponse(status_code, response_content, headers, url, is_post=is_post_request)
@@ -369,58 +402,13 @@ class TranscriptExtractor:
return original_get(session_self, url, **kwargs)
def patched_post(session_self, url, **kwargs):
- """requests.Session.post'i patch et - header'ları ekle ve FlareSolverr kullan"""
- # YouTube API endpoint'leri için FlareSolverr kullan (youtubei/v1/player gibi)
+ """requests.Session.post'i patch et - header'ları ekle (FlareSolverr POST için kullanılmıyor)"""
+ # NOT: YouTube API POST istekleri FlareSolverr ile çalışmıyor (FAILED_PRECONDITION hatası)
+ # Bu yüzden POST istekleri için FlareSolverr kullanmayalım, sadece header'ları ekle
is_youtube_api = ('youtube.com' in url or 'youtu.be' in url) and ('/youtubei/v1/' in url or '/api/' in url)
- # FlareSolverr kullanılıyorsa ve YouTube API endpoint'i ise
- if extractor_instance.use_flaresolverr and is_youtube_api and extractor_instance.flaresolverr_available:
- logger.debug(f"[FLARESOLVERR] YouTube API POST isteği FlareSolverr üzerinden deneniyor: {url[:50]}...")
- # POST için FlareSolverr'da request.post kullan
- flaresolverr_response = extractor_instance._make_flaresolverr_request(url, 'POST', **kwargs)
- if flaresolverr_response:
- logger.debug(f"[FLARESOLVERR] ✅ FlareSolverr POST başarılı, response döndürülüyor")
- class PatchedResponse:
- def __init__(self, flaresolverr_response):
- self.status_code = flaresolverr_response.status_code
- self.text = flaresolverr_response.text
- self.content = flaresolverr_response.content
- self.headers = flaresolverr_response.headers
- self.url = flaresolverr_response.url
- self.ok = 200 <= self.status_code < 300
-
- def json(self):
- import json
- try:
- # Debug: JSON parse edilmeye çalışılan içeriği logla
- logger.debug(f"[FLARESOLVERR] JSON parse deneniyor (POST), içerik tipi: {type(self.text)}, uzunluk: {len(self.text)}")
- logger.debug(f"[FLARESOLVERR] İçerik önizleme (ilk 200 karakter): {self.text[:200]}")
-
- # Eğer HTML ise JSON parse etme
- if self.text.strip().startswith('<') or 'html' in self.headers.get('content-type', '').lower():
- logger.warning(f"[FLARESOLVERR] ⚠️ HTML içerik JSON olarak parse edilmeye çalışılıyor, boş dict döndürülüyor")
- return {}
-
- return json.loads(self.text)
- except json.JSONDecodeError as e:
- logger.error(f"[FLARESOLVERR] ❌ JSON parse hatası (POST): {e}")
- logger.error(f"[FLARESOLVERR] İçerik (ilk 500 karakter): {self.text[:500]}")
- return {}
- except Exception as e:
- logger.error(f"[FLARESOLVERR] ❌ JSON parse beklenmeyen hata (POST): {type(e).__name__} - {str(e)}")
- return {}
-
- def raise_for_status(self):
- """requests.Response.raise_for_status() uyumluluğu"""
- if not self.ok:
- from requests.exceptions import HTTPError
- raise HTTPError(f"{self.status_code} Client Error: {self.text[:100]}", response=self)
-
- return PatchedResponse(flaresolverr_response)
- else:
- logger.debug(f"[FLARESOLVERR] FlareSolverr POST yanıt vermedi, normal istek deneniyor")
- elif extractor_instance.use_flaresolverr and ('youtube.com' in url or 'youtu.be' in url):
- logger.debug(f"[FLARESOLVERR] POST isteği tespit edildi, FlareSolverr kullanılmıyor (sadece header'lar): {url[:50]}...")
+ if is_youtube_api:
+ logger.debug(f"[FLARESOLVERR] POST isteği tespit edildi, FlareSolverr kullanılmıyor (FAILED_PRECONDITION önleme): {url[:50]}...")
# Normal istek (header'ları ekle)
headers = kwargs.get('headers', {})
@@ -638,16 +626,57 @@ class TranscriptExtractor:
logger.error(f"[TRANSCRIPT] Hata detayları: {error_msg[:500]}")
logger.error(f"[TRANSCRIPT] Bu video için transcript çıkarılamıyor (YouTube HTML yapısı değişmiş olabilir)")
- # Debug: FlareSolverr response'unu analiz et (eğer kullanıldıysa)
+ # Debug: FlareSolverr response'unu analiz et ve transcript URL'lerini kullan (fallback)
if self.use_flaresolverr and hasattr(self, '_last_flaresolverr_response'):
logger.debug(f"[TRANSCRIPT] FlareSolverr response analizi yapılıyor...")
last_response = self._last_flaresolverr_response
- # Transcript URL'leri var mı kontrol et
+ # Transcript URL'leri var mı kontrol et ve kullan (fallback)
transcript_urls = getattr(last_response, 'transcript_urls', [])
if transcript_urls:
- logger.warning(f"[TRANSCRIPT] ⚠️ FlareSolverr response'unda {len(transcript_urls)} transcript URL bulundu ama parse edilemedi")
- logger.warning(f"[TRANSCRIPT] Bu URL'ler doğrudan kullanılabilir (fallback mekanizması henüz implement edilmedi)")
+ logger.warning(f"[TRANSCRIPT] ⚠️ FlareSolverr response'unda {len(transcript_urls)} transcript URL bulundu, fallback mekanizması deneniyor...")
+
+ # İlk transcript URL'ini kullan (genellikle en uygun dil)
+ transcript_url = transcript_urls[0]
+
+ # Unicode escape karakterlerini decode et (\u0026 -> &)
+ import codecs
+ transcript_url = codecs.decode(transcript_url, 'unicode_escape')
+
+ logger.info(f"[TRANSCRIPT] Transcript URL'den transcript çekiliyor: {transcript_url[:100]}...")
+
+ try:
+ import requests
+ import xml.etree.ElementTree as ET
+
+ # Transcript URL'inden XML çek (browser header'ları ile)
+ headers = TranscriptExtractor._get_browser_headers()
+ response = requests.get(transcript_url, headers=headers, timeout=30)
+ response.raise_for_status()
+
+ # XML'i parse et
+ root = ET.fromstring(response.text)
+
+ # Transcript segment'lerini çıkar
+ transcript_list = []
+ for text_elem in root.findall('.//text'):
+ start = float(text_elem.get('start', 0))
+ duration = float(text_elem.get('dur', 0))
+ text = text_elem.text or ''
+
+ transcript_list.append({
+ 'text': text,
+ 'start': start,
+ 'duration': duration
+ })
+
+ if transcript_list:
+ logger.info(f"[TRANSCRIPT] ✅ Transcript URL'den {len(transcript_list)} segment başarıyla çıkarıldı (fallback)")
+ return transcript_list
+ else:
+ logger.warning(f"[TRANSCRIPT] ⚠️ Transcript URL'den segment bulunamadı")
+ except Exception as fallback_err:
+ logger.error(f"[TRANSCRIPT] ❌ Transcript URL fallback hatası: {type(fallback_err).__name__} - {str(fallback_err)[:200]}")
# ytInitialPlayerResponse var mı kontrol et
yt_response_found = getattr(last_response, 'yt_initial_player_response_found', False)