# YouTube Transcript RSS Feed - Geliştirme Planı ## Proje Özeti YouTube video transkriptlerini otomatik olarak çıkarıp, tam metin içeren RSS feed'ine dönüştüren otomatik bir pipeline geliştirilmesi. Sistem, Python tabanlı transcript çıkarımı ve RSS feed oluşturma ile RSS-Bridge entegrasyonu seçeneklerini içerir. --- ## Faz 1: Proje Altyapısı ve Ortam Kurulumu ### 1.1. Teknoloji Stack Seçimi **Ana Yaklaşım: Python Tabanlı (Önerilen)** - **Transcript Çıkarımı**: `youtube-transcript-api` - **RSS Oluşturma**: `python-feedgen` - **Video Listesi**: RSS-Bridge (RSS feed parser) - **Dil**: Python 3.8+ ### 1.2. Geliştirme Ortamı Kurulumu **Görevler:** - [ ] Python 3.8+ kurulumu doğrulama - [ ] Virtual environment oluşturma (`python -m venv venv`) - [ ] Gerekli paketlerin kurulumu: ```bash pip install youtube-transcript-api pip install feedgen pip install python-dateutil pip install feedparser # RSS-Bridge feed'lerini parse etmek için pip install requests # HTTP istekleri için pip install aiolimiter # Async rate limiting için pip install httpx # Async HTTP client pip install spacy # NLP ve Sentence Boundary Detection için ``` **Not**: SQLite Python'da built-in (`sqlite3` modülü), ekstra kurulum gerekmez. **SpaCy Model**: `python -m spacy download en_core_web_sm` (veya `tr_core_news_sm` Türkçe için) - [ ] Proje dizin yapısı oluşturma: ``` yttranscriptrss/ ├── src/ │ ├── transcript_extractor.py │ ├── transcript_cleaner.py │ ├── rss_generator.py │ ├── video_fetcher.py │ └── database.py ├── config/ │ └── config.yaml ├── data/ │ └── videos.db ├── output/ │ └── transcript_feed.xml ├── tests/ ├── requirements.txt └── main.py ``` **Süre Tahmini**: 1-2 gün --- ## Faz 2: Transcript Çıkarımı ve Temizleme Modülü ### 2.1. Transcript Çıkarımı (`transcript_extractor.py`) **Görevler:** - [ ] `youtube-transcript-api` ile video ID'den transcript çıkarma - [ ] Çoklu dil desteği (fallback mekanizması) - Örnek: `languages=['tr', 'en']` - önce Türkçe, yoksa İngilizce - [ ] Hata yönetimi: - Transcript bulunamama durumları - API rate limiting - Geçersiz video ID'ler - [ ] Raw transcript formatını anlama: ```python # Format: [{"text": "...", "start": 0.0, "duration": 2.5}, ...] ``` **Kritik Gereksinimler:** - Headless browser kullanmama (API tabanlı yaklaşım) - Otomatik ve manuel transkriptleri destekleme - **Async Rate Limiting**: AIOLimiter ile eş zamanlı istek yönetimi - API limiti: 10 saniyede 5 istek - Async batching ile paralel işleme - **Retry-After Header**: 429 hatalarında `Retry-After` header'ını kullanma - Dinamik bekleme süresi (statik delay yerine) - Exponential backoff mekanizması - Timeout ve retry mekanizmaları **Süre Tahmini**: 3-4 gün ### 2.2. Transcript Temizleme ve Dönüştürme (`transcript_cleaner.py`) **Görevler:** - [ ] **Veri Temizleme Pipeline**: - **Artifact Removal**: - Zaman tabanlı işaretçileri kaldırma - Konuşma dışı etiketler: `[Music]`, `[Applause]`, vb. - Aşırı boşlukları temizleme - **Normalizasyon**: - Unicode karakter normalleştirme - Metin standardizasyonu - [ ] **Sentence Boundary Detection (SBD) - SpaCy Entegrasyonu**: - **SpaCy Model Kullanımı**: `en_core_web_sm` veya `tr_core_news_sm` - Noktalama işaretlerinin ötesine geçme: - Doğal duraklama noktalarını tespit - Anlamsal sınırları belirleme - Konuşmacı değişikliklerini algılama - Fragment'ları birleştirme ve cümle sınırlarını tespit etme - Paragraf yapısı oluşturma (cümle sayısı veya anlamsal değişikliklere göre) - **Özelleştirme**: Özel içerik için kural tabanlı SBD uzantıları - [ ] **HTML Wrapping**: - Temizlenmiş metni `
...
` tag'leri ile sarmalama - Paragraf yapısını koruma - Minimal HTML (sadece gerekli tag'ler) - [ ] **XML Entity Escaping** (Kritik!): - **Zorunlu karakter dönüşümleri**: - `&` → `&` (özellikle URL'lerde kritik!) - `<` → `<` - `>` → `>` - `"` → `"` - `'` → `'` - **CDATA kullanımı**: İsteğe bağlı ama entity escaping hala gerekli - URL'lerdeki ampersand'ların kaçışı özellikle önemli **Algoritma Özeti:** 1. Artifact'ları kaldır ve normalize et 2. SpaCy ile fragment'ları birleştir ve cümle sınırlarını tespit et 3. Paragraflara böl (anlamsal veya cümle sayısına göre) 4. HTML tag'leri ekle (`...
`) 5. XML entity escaping uygula (özellikle `&` karakterleri) **Süre Tahmini**: 4-5 gün --- ## Faz 3: Video Metadata Çıkarımı ve Yönetimi ### 3.1. Video Metadata Fetcher (`video_fetcher.py`) - RSS-Bridge Entegrasyonu **Görevler:** - [ ] **RSS-Bridge Feed Parser**: - **Public RSS-Bridge instance kullanımı (Önerilen)**: - Base URL: `https://rss-bridge.org/bridge01/` - Ücretsiz ve hazır kullanılabilir - Rate limiting riski var ama başlangıç için yeterli - RSS-Bridge YouTube Bridge endpoint'ini kullanma - **Doğru URL formatı**: - Public (Channel ID): `https://rss-bridge.org/bridge01/?action=display&bridge=YoutubeBridge&context=By+channel+id&c=CHANNEL_ID&format=Atom` - Public (Channel Handle): `https://rss-bridge.org/bridge01/?action=display&bridge=YoutubeBridge&context=By+username&u=USERNAME&format=Atom` - Self-hosted (opsiyonel): `http://localhost:3000/?action=display&bridge=YoutubeBridge&context=By+channel+id&c=CHANNEL_ID&format=Atom` - **Önemli parametreler**: - `bridge=YoutubeBridge` (Youtube değil!) - `context=By+channel+id` veya `context=By+username` - `c=CHANNEL_ID` (channel ID için) veya `u=USERNAME` (handle için) - `format=Atom` veya `format=Rss` (feed için, Html değil) - `duration_min` ve `duration_max` (opsiyonel filtreleme) - [ ] **Feed Parsing** (`feedparser` kullanarak): - RSS/Atom feed'ini parse etme - Video entry'lerini çıkarma - Metadata çıkarımı: - Video ID (YouTube URL'den parse) - Video başlığı (`entry.title`) - Yayın tarihi (`entry.published` - timezone-aware) - Video URL (`entry.link`) - Video açıklaması (`entry.summary` - opsiyonel) - Thumbnail URL (opsiyonel) - [ ] **RSS-Bridge Avantajları**: - Native feed'den daha fazla video (10-15 yerine 100+) - Channel Handle (@username) desteği - Filtreleme seçenekleri (duration, vb.) - [ ] **Hata Yönetimi**: - RSS-Bridge instance erişilemezse fallback (native RSS) - Rate limiting handling - Feed format validation - [ ] **Channel ID Extraction (Handle'dan)**: - Channel handle (@username) verildiğinde Channel ID'yi bulma - Web scraping ile HTML source'dan Channel ID çıkarma - Regex pattern: `"externalId":"(UC[a-zA-Z0-9_-]{22})"` veya `"channelId":"(UC[a-zA-Z0-9_-]{22})"` - Channel ID formatı: `UC` ile başlar, 22 karakter - Fallback mekanizması: İlk pattern bulunamazsa alternatif pattern dene - Hata yönetimi: Request exception handling - [ ] **Video ID Extraction**: - YouTube URL'den video ID çıkarma - Regex pattern: `youtube.com/watch?v=([a-zA-Z0-9_-]+)` - Short URL desteği: `youtu.be/([a-zA-Z0-9_-]+)` - [ ] `yt-dlp` entegrasyonu (opsiyonel, gelişmiş metadata için) **RSS-Bridge Kullanım Örneği:** ```python import feedparser from urllib.parse import urlencode # Public RSS-Bridge base URL RSS_BRIDGE_BASE = "https://rss-bridge.org/bridge01" # Channel ID ile feed URL'i oluştur params = { 'action': 'display', 'bridge': 'YoutubeBridge', 'context': 'By channel id', 'c': 'UC9h8BDcXwkhZtnqoQJ7PggA', # Channel ID 'format': 'Atom' # veya 'Rss' } rss_bridge_url = f"{RSS_BRIDGE_BASE}/?{urlencode(params)}" # Feed'i parse et feed = feedparser.parse(rss_bridge_url) # Video entry'lerini işle for entry in feed.entries: video_id = extract_video_id(entry.link) video_title = entry.title published_date = entry.published_parsed # timezone-aware video_url = entry.link ``` **Gerçek Örnek URL:** ``` https://rss-bridge.org/bridge01/?action=display&bridge=YoutubeBridge&context=By+channel+id&c=UC9h8BDcXwkhZtnqoQJ7PggA&format=Atom ``` **Channel ID Bulma Fonksiyonu (Handle'dan):** ```python import requests import re def get_channel_id_from_handle(handle_url): """ Channel handle URL'inden Channel ID'yi web scraping ile bulur. Örnek: https://www.youtube.com/@tavakfi -> UC... """ try: # HTML içeriğini çek response = requests.get(handle_url) response.raise_for_status() html_content = response.text # İlk pattern: "externalId":"UC..." match = re.search(r'"externalId":"(UC[a-zA-Z0-9_-]{22})"', html_content) if match: return match.group(1) # Alternatif pattern: "channelId":"UC..." match_alt = re.search(r'"channelId":"(UC[a-zA-Z0-9_-]{22})"', html_content) if match_alt: return match_alt.group(1) return None # Channel ID bulunamadı except requests.exceptions.RequestException as e: raise Exception(f"Error fetching channel page: {e}") # Kullanım örneği handle_url = "https://www.youtube.com/@tavakfi" channel_id = get_channel_id_from_handle(handle_url) # Artık channel_id ile RSS-Bridge feed'ini çekebiliriz ``` **Süre Tahmini**: 3 gün ### 3.2. İşlenmiş Video Takibi (`database.py` - SQLite) **Görevler:** - [ ] SQLite veritabanı modülü oluşturma (`database.py`) - [ ] Veritabanı şeması tasarımı: ```sql -- Channels tablosu (kanal takibi için) CREATE TABLE IF NOT EXISTS channels ( channel_id TEXT PRIMARY KEY, -- UC... formatında channel_name TEXT, channel_url TEXT, last_checked_utc TEXT, -- ISO 8601 UTC format created_at_utc TEXT DEFAULT (datetime('now')) ); CREATE INDEX IF NOT EXISTS idx_channels_last_checked ON channels(last_checked_utc); -- Videos tablosu (detaylı şema) CREATE TABLE IF NOT EXISTS videos ( video_id TEXT PRIMARY KEY, -- 11 karakterli YouTube video ID channel_id TEXT, -- UC... formatında (FK) video_title TEXT, video_url TEXT, published_at_utc TEXT, -- ISO 8601 UTC format (YYYY-MM-DDTHH:MM:SSZ) processed_at_utc TEXT, -- ISO 8601 UTC format transcript_status INTEGER DEFAULT 0, -- 0: Beklemede, 1: Çıkarıldı, 2: Başarısız transcript_language TEXT, transcript_raw TEXT, -- Ham, bölümlenmemiş transcript transcript_clean TEXT, -- SBD ile işlenmiş, RSS için hazır HTML last_updated_utc TEXT DEFAULT (datetime('now')) ); -- Kritik index'ler (performans için) CREATE INDEX IF NOT EXISTS idx_videos_channel_id ON videos(channel_id); CREATE INDEX IF NOT EXISTS idx_videos_published_at_utc ON videos(published_at_utc); CREATE INDEX IF NOT EXISTS idx_videos_transcript_status ON videos(transcript_status); CREATE INDEX IF NOT EXISTS idx_videos_processed_at_utc ON videos(processed_at_utc); ``` **Önemli Notlar**: - **Zaman Formatı**: UTC ISO 8601 (`YYYY-MM-DDTHH:MM:SSZ`) - SQLite'ın timezone desteği yok - **transcript_status**: INTEGER (0, 1, 2) - String değil, performans için - **Index Optimizasyonu**: `EXPLAIN QUERY PLAN` ile sorgu performansını doğrula - **DATE() fonksiyonu kullanma**: Index kullanımını engeller, direkt timestamp karşılaştırması yap - [ ] Database helper fonksiyonları: - `init_database()` - Veritabanı ve tablo oluşturma - `is_video_processed(video_id)` - Duplicate kontrolü - `get_pending_videos()` - `transcript_status = 0` olan videoları getir - `add_video(video_data)` - Yeni video kaydı (status=0 olarak) - `update_video_transcript(video_id, raw, clean, status, language)` - Transcript güncelleme - `get_processed_videos(limit=None, channel_id=None)` - İşlenmiş videoları getir - `mark_video_failed(video_id, reason)` - Kalıcı hata işaretleme (status=2) - `is_transcript_cached(video_id, cache_days=3)` - Transcript cache kontrolü (3 günlük) - `get_cached_transcript(video_id)` - Cache'den transcript getirme - **Query Performance**: `EXPLAIN QUERY PLAN` ile index kullanımını doğrula - [ ] **Transcript Cache Mekanizması**: - **3 Günlük Cache**: İşlenmiş transcript'ler 3 gün boyunca cache'de tutulur - **Cache Kontrolü**: Transcript çıkarımından önce cache kontrolü yapılır - **Avantajlar**: - YouTube IP blocking riskini azaltır - Performans artışı (tekrar isteklerde hızlı yanıt) - API rate limiting'i azaltır - Aynı videoların transcript'ini tekrar çekmez - **Cache Süresi**: `processed_at_utc` tarihine göre 3 gün kontrolü - **Otomatik Yenileme**: 3 gün sonra cache geçersiz olur, yeni transcript çekilir - [ ] Yeni video tespiti algoritması: 1. RSS-Bridge feed'den son videoları çek (max_items × 2, minimum 50 video) 2. SQLite veritabanında `video_id` ile sorgula 3. Sadece yeni videoları (veritabanında olmayan) işle 4. **Cache Kontrolü**: İşlenmiş videolar için 3 günlük cache kontrolü yap - Eğer 3 gün içinde işlenmişse, transcript çıkarma (cache'den kullan) - 3 günden eskiyse, yeni transcript çek 5. **max_items Parametresi**: Her API isteğinde işlenecek transcript sayısı - **Varsayılan**: 10 transcript - **Maksimum**: 100 transcript - **Kullanım**: `?max_items=50` query parametresi ile belirtilir - **Batch İşleme**: 20'şer batch'ler halinde işlenir (YouTube IP blocking önleme için) - **Veritabanı Kaydı**: Her batch işlendikten sonra hemen veritabanına kaydedilir - **RSS-Bridge Limit**: max_items × 2 kadar video çekilir (bazı videolar transcript'siz olabilir) - [ ] Transaction yönetimi (ACID compliance) - [ ] Connection pooling ve error handling **Avantajlar:** - Daha hızlı sorgulama (index'li) - Transaction desteği - İlişkisel veri yapısı - Daha iyi veri bütünlüğü - İstatistik sorguları kolaylaşır **Süre Tahmini**: 2 gün --- ## Faz 4: RSS Feed Oluşturma ### 4.1. RSS Generator (`rss_generator.py`) **Görevler:** - [ ] `python-feedgen` ile FeedGenerator oluşturma - [ ] **Content Namespace Extension** ekleme: ```xml