YouTubeDataUnparsable
This commit is contained in:
@@ -50,10 +50,14 @@ class TranscriptExtractor:
|
||||
# FlareSolverr ayarları
|
||||
self.flaresolverr_url = flaresolverr_url or os.getenv('FLARESOLVERR_URL', 'http://192.168.1.27:8191/v1')
|
||||
self.use_flaresolverr = bool(self.flaresolverr_url)
|
||||
self.flaresolverr_available = False # Test sonucu
|
||||
|
||||
if self.use_flaresolverr:
|
||||
logger.info(f"[FLARESOLVERR] FlareSolverr etkin: {self.flaresolverr_url}")
|
||||
logger.info(f"[FLARESOLVERR] FlareSolverr URL ayarlandı: {self.flaresolverr_url}")
|
||||
# Test et ama başarısız olsa bile kullanmayı dene (test sırasında erişilemez olabilir)
|
||||
self._test_flaresolverr()
|
||||
if not self.flaresolverr_available:
|
||||
logger.warning("[FLARESOLVERR] ⚠ Test başarısız, ancak gerçek isteklerde tekrar denenilecek")
|
||||
else:
|
||||
logger.info("[FLARESOLVERR] FlareSolverr devre dışı")
|
||||
|
||||
@@ -68,14 +72,17 @@ class TranscriptExtractor:
|
||||
test_response = requests.get(f"{self.flaresolverr_url.replace('/v1', '')}/v1", timeout=5)
|
||||
if test_response.status_code == 405: # Method Not Allowed normal (GET yerine POST bekliyor)
|
||||
logger.info("[FLARESOLVERR] ✅ FlareSolverr erişilebilir")
|
||||
self.flaresolverr_available = True
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"[FLARESOLVERR] ⚠️ FlareSolverr yanıtı beklenmedik: {test_response.status_code}")
|
||||
self.flaresolverr_available = False
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.warning(f"[FLARESOLVERR] ⚠️ FlareSolverr test edilemedi: {e}")
|
||||
logger.warning(f"[FLARESOLVERR] FlareSolverr devre dışı bırakılıyor")
|
||||
self.use_flaresolverr = False
|
||||
logger.warning(f"[FLARESOLVERR] Test başarısız, ancak gerçek isteklerde tekrar denenilecek")
|
||||
self.flaresolverr_available = False
|
||||
# use_flaresolverr'ı False yapma, gerçek isteklerde tekrar dene
|
||||
return False
|
||||
|
||||
def _make_flaresolverr_request(self, url: str, method: str = 'GET', **kwargs) -> Optional:
|
||||
@@ -164,9 +171,10 @@ class TranscriptExtractor:
|
||||
"""requests.Session.get'i patch et - header'ları ekle ve FlareSolverr kullan"""
|
||||
# FlareSolverr kullanılıyorsa ve YouTube URL'si ise
|
||||
if extractor_instance.use_flaresolverr and ('youtube.com' in url or 'youtu.be' in url):
|
||||
logger.info(f"[FLARESOLVERR] YouTube isteği FlareSolverr üzerinden: {url[:50]}...")
|
||||
logger.debug(f"[FLARESOLVERR] YouTube isteği FlareSolverr üzerinden deneniyor: {url[:50]}...")
|
||||
flaresolverr_response = extractor_instance._make_flaresolverr_request(url, 'GET', **kwargs)
|
||||
if flaresolverr_response:
|
||||
logger.debug(f"[FLARESOLVERR] ✅ FlareSolverr başarılı, response döndürülüyor")
|
||||
# FlareSolverr response'unu requests.Response'a benzet
|
||||
class PatchedResponse:
|
||||
def __init__(self, flaresolverr_response):
|
||||
@@ -192,7 +200,7 @@ class TranscriptExtractor:
|
||||
|
||||
return PatchedResponse(flaresolverr_response)
|
||||
else:
|
||||
logger.warning(f"[FLARESOLVERR] FlareSolverr yanıt vermedi, normal istek deneniyor")
|
||||
logger.debug(f"[FLARESOLVERR] FlareSolverr yanıt vermedi, normal istek deneniyor")
|
||||
|
||||
# Normal istek (header'ları ekle)
|
||||
headers = kwargs.get('headers', {})
|
||||
@@ -205,9 +213,10 @@ class TranscriptExtractor:
|
||||
"""requests.Session.post'i patch et - header'ları ekle ve FlareSolverr kullan"""
|
||||
# FlareSolverr kullanılıyorsa ve YouTube URL'si ise
|
||||
if extractor_instance.use_flaresolverr and ('youtube.com' in url or 'youtu.be' in url):
|
||||
logger.info(f"[FLARESOLVERR] YouTube POST isteği FlareSolverr üzerinden: {url[:50]}...")
|
||||
logger.debug(f"[FLARESOLVERR] YouTube POST isteği FlareSolverr üzerinden deneniyor: {url[:50]}...")
|
||||
flaresolverr_response = extractor_instance._make_flaresolverr_request(url, 'POST', **kwargs)
|
||||
if flaresolverr_response:
|
||||
logger.debug(f"[FLARESOLVERR] ✅ FlareSolverr başarılı, response döndürülüyor")
|
||||
class PatchedResponse:
|
||||
def __init__(self, flaresolverr_response):
|
||||
self.status_code = flaresolverr_response.status_code
|
||||
@@ -232,7 +241,7 @@ class TranscriptExtractor:
|
||||
|
||||
return PatchedResponse(flaresolverr_response)
|
||||
else:
|
||||
logger.warning(f"[FLARESOLVERR] FlareSolverr yanıt vermedi, normal istek deneniyor")
|
||||
logger.debug(f"[FLARESOLVERR] FlareSolverr yanıt vermedi, normal istek deneniyor")
|
||||
|
||||
# Normal istek (header'ları ekle)
|
||||
headers = kwargs.get('headers', {})
|
||||
@@ -326,13 +335,15 @@ class TranscriptExtractor:
|
||||
logger.debug(f"[RATE_LIMIT] İstek kaydedildi (Toplam aktif istek: {len(self.request_times)})")
|
||||
|
||||
def fetch_transcript(self, video_id: str,
|
||||
languages: List[str] = ['en']) -> Optional[List[Dict]]:
|
||||
languages: List[str] = ['en'],
|
||||
max_retries: int = 2) -> Optional[List[Dict]]:
|
||||
"""
|
||||
Transcript çıkar (sync)
|
||||
Transcript çıkar (sync) - Retry mekanizması ile
|
||||
|
||||
Args:
|
||||
video_id: YouTube video ID
|
||||
languages: Öncelik sırasına göre dil listesi
|
||||
max_retries: Maksimum retry sayısı (YouTubeDataUnparsable için)
|
||||
|
||||
Returns:
|
||||
Transcript listesi veya None
|
||||
@@ -342,8 +353,18 @@ class TranscriptExtractor:
|
||||
# Rate limiting kontrolü
|
||||
self._check_rate_limit()
|
||||
|
||||
# Retry mekanizması
|
||||
for attempt in range(max_retries + 1):
|
||||
try:
|
||||
logger.debug(f"[TRANSCRIPT] YouTube Transcript API çağrısı yapılıyor: video_id={video_id}")
|
||||
if attempt > 0:
|
||||
# Retry için bekleme (YouTube'un HTML'i yenilemesi için)
|
||||
wait_time = 5 + (attempt * 3) # 5, 8, 11 saniye
|
||||
logger.warning(f"[TRANSCRIPT] ⚠️ Retry {attempt}/{max_retries} - {wait_time} saniye bekleniyor...")
|
||||
time.sleep(wait_time)
|
||||
# Rate limit kontrolü tekrar yap
|
||||
self._check_rate_limit()
|
||||
|
||||
logger.debug(f"[TRANSCRIPT] YouTube Transcript API çağrısı yapılıyor: video_id={video_id} (Deneme: {attempt + 1}/{max_retries + 1})")
|
||||
|
||||
# YouTube Transcript API kullanımı (yeni versiyon)
|
||||
# API instance oluştur ve fetch() metodunu kullan
|
||||
@@ -355,13 +376,28 @@ class TranscriptExtractor:
|
||||
transcript = fetched_transcript.to_raw_data()
|
||||
|
||||
transcript_count = len(transcript) if transcript else 0
|
||||
logger.info(f"[TRANSCRIPT] ✅ Video {video_id} transcript'i başarıyla çıkarıldı ({transcript_count} segment)")
|
||||
logger.info(f"[TRANSCRIPT] ✅ Video {video_id} transcript'i başarıyla çıkarıldı ({transcript_count} segment, Deneme: {attempt + 1})")
|
||||
|
||||
return transcript
|
||||
|
||||
except Exception as e:
|
||||
error_msg = str(e)
|
||||
error_type = type(e).__name__
|
||||
|
||||
# YouTubeDataUnparsable hatası için retry yap
|
||||
if "YouTubeDataUnparsable" in error_type or "Unparsable" in error_type:
|
||||
if attempt < max_retries:
|
||||
logger.warning(f"[TRANSCRIPT] ⚠️ Video {video_id} parse hatası (Deneme {attempt + 1}/{max_retries + 1}): {error_type}")
|
||||
logger.warning(f"[TRANSCRIPT] Hata mesajı: {error_msg[:300]}")
|
||||
logger.warning(f"[TRANSCRIPT] Retry yapılacak...")
|
||||
continue # Retry yap
|
||||
else:
|
||||
logger.error(f"[TRANSCRIPT] ❌ Video {video_id} parse hatası - Tüm denemeler başarısız: {error_type}")
|
||||
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)")
|
||||
return None
|
||||
|
||||
# Diğer hatalar için normal işlem
|
||||
logger.error(f"[TRANSCRIPT] ❌ Video {video_id} transcript çıkarımı başarısız: {error_type} - {error_msg[:200]}")
|
||||
|
||||
# IP blocking hatası tespit edilirse işaretle
|
||||
@@ -380,5 +416,9 @@ class TranscriptExtractor:
|
||||
logger.error(f"[TRANSCRIPT] ⚠️ UYARI: {self.block_count} kez IP blocking alındı! YouTube IP'nizi geçici olarak engellemiş olabilir.")
|
||||
logger.error(f"[TRANSCRIPT] Öneriler: 1) Daha uzun bekleme (30+ dakika), 2) Farklı IP kullan, 3) Proxy/VPN kullan")
|
||||
|
||||
# Retry yapılmayacak hatalar için direkt dön
|
||||
return None
|
||||
|
||||
# Tüm retry'lar başarısız
|
||||
return None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user