YouTube Services
Die YouTube-Services bilden den Kern der YouTube-Datenerhebung. Der YouTubeDataApiClient verwaltet einen Multi-Key-Pool mit automatischem Failover, der YouTubeChannelResolver löst verschiedene URL-Formate zu Channel-IDs auf, und der ResearchQuotaService steuert die Quota-Verteilung für Auto-Fill-Features.
YouTubeDataApiClient
Location: app/Services/Social/YouTube/YouTubeDataApiClient.php
HTTP-Client für die YouTube Data API v3 mit automatischer Key-Rotation und Cross-Pool-Failover. Verwaltet mehrere API-Key-Pools für verschiedene Anwendungsfälle.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
get() | string $endpoint, array $query | array | Generic GET mit Default-Pool |
rawGetWithKeyPool() | string $endpoint, array $query, string $pool | Response | Raw GET mit spezifischem Pool |
getChannelByHandle() | string $handle | array | Channel via forHandle Parameter |
getChannelByUsername() | string $username | array | Channel via forUsername Parameter |
getChannelById() | string $channelId | array | Channel via id Parameter |
getChannelByIdWithParts() | string $channelId, string $parts | array | Channel mit Custom Parts |
getPlaylistItems() | string $playlistId, ?string $pageToken, int $maxResults | array | Playlist-Items (Video-Pool) |
getVideosByIds() | array $videoIds, string $parts | array | Videos via IDs (Video-Pool) |
getChannelIdByVideoId() | string $videoId | string | Channel-ID aus Video extrahieren |
Key-Pool-Architektur
Jeder Pool hat eine kaskadierte Fallback-Kette:
| Pool | Kaskade | Verwendung |
|---|---|---|
default | YOUTUBE_API_KEYS -> YOUTUBE_API_KEY | Standard-Channel-Abfragen |
video | VIDEO_KEYS -> EXTENDED_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEY | Video-Statistiken, Playlist-Items |
research | RESEARCH_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEY | Related Channels, Auto-Fill |
extended | EXTENDED_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEY | Extended Channel Data |
Key-Rotation-Algorithmus
Der Two-Pass-Ansatz minimiert Ausfallzeiten:
- Pass 1: Alle nicht-erschöpften Keys durchprobieren. Bei Quota/Rate-Limit: Key im Cache als erschöpft markieren und nächsten probieren.
- Pass 2 (Recovery): Falls alle Keys erschöpft: 3 Sekunden warten, dann Keys erneut probieren, die in diesem Request erschöpft wurden (Rate-Limits können sich zwischenzeitlich erholt haben).
Exhaustion-Cache
- Daily-Quota-Limits (
quotaExceeded,dailyLimitExceeded): 1 Stunde TTL - Rate-Limits (
rateLimitExceeded): 5 Minuten TTL - Cache-Key-Format:
yt_key_exhausted:{pool}:{md5_prefix}
Fehlerbehandlung
- Quota/Rate-Limit: Key-Rotation, Recovery-Pass, dann
RuntimeException(Code 429) - Nicht-Quota-Fehler (404, 400): Sofortige Exception
- Server-Fehler (5xx): 3 Retries mit exponential Backoff (2s, 4s, 8s) in
rawGet()— transiente YouTube-Fehler (z.B. HTTP 500 "Internal error encountered") werden automatisch wiederholt, bevor der Fehler an die Key-Rotation weitergegeben wird - Connection-Fehler: 3 Retries mit exponential Backoff (2s, 4s, 8s)
- Final-Fallback-Notification: Warning-Log wenn letzter Key erreicht wird (1x/Stunde)
Abhängigkeiten
- Laravel HTTP Client, Cache (Redis), Config (
services.youtube.*)
Verwendet von
YouTubeChannelResolver,YouTubeProfileScraper,SyncYouTubeVideoStats,FindRelatedYouTubeChannels
YouTubeChannelResolver
Location: app/Services/Social/YouTube/YouTubeChannelResolver.php
Löst verschiedene YouTube-URL-Formate zu einer Channel-ID und dem vollständigen Channel-Resource auf. Nutzt den YouTubeDataApiClient und YouTubeUrlParser intern.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
resolve() | string $url | array | URL -> Channel-ID + Channel-Resource + Handle + Canonical URL |
Return-Struktur
[
'channel_id' => 'UC...',
'channel' => [...], // Vollständige Channel-Resource (snippet + statistics)
'handle' => 'channelhandle', // Ohne @-Prefix
'canonical_url' => 'https://www.youtube.com/@channelhandle',
]
Auflösungs-Strategien (Priorität)
- Channel-ID:
/channel/UC...-> direkte API-Abfrage viagetChannelById() - Handle:
/@handle-> API-Abfrage viagetChannelByHandle() - Username:
/user/name-> API-Abfrage viagetChannelByUsername() - Custom URL:
/c/name-> Handle-Versuch, dann Username-Fallback - Video-URL:
/watch?v=...-> Channel-ID aus Video extrahieren viagetChannelIdByVideoId() - HTML Fallback: Page Parser als letzter Ausweg (konfigurierbar via
youtube_custom_url_search_fallback)
Abhängigkeiten
YouTubeDataApiClient(Constructor Injection)YouTubeUrlParser(statisch)YouTubeChannelPageParser(Fallback)
Verwendet von
YouTubeProfileScraper, Watcher-Import
ResearchQuotaService
Location: app/Services/YouTube/ResearchQuotaService.php
Prüft ob genügend YouTube API-Quota für Research-Operationen (Related Channels, Auto-Fill) verfügbar ist. Steuert das Rate-Limiting für automatische Discovery-Features.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
getStatus() | -- | array | Aktuellen Quota-Status mit Verbrauch und Limit |
allowsAutoFill() | -- | bool | Prüfen ob Auto-Fill-Operations erlaubt sind |
hasQuota() | int $cost = 1 | bool | Prüfen ob genügend Quota für eine Operation vorhanden |
Quota-Logik
Die Research-Keys haben ein separates Budget. allowsAutoFill() gibt false zurück, wenn:
- Keine Research-Keys konfiguriert sind
- Das tägliche Quota-Budget zu mehr als einem konfigurierten Schwellwert verbraucht ist
- Alle Research-Keys im Exhaustion-Cache markiert sind
Abhängigkeiten
- Config (
services.youtube.research_keys), Cache (Redis)
Verwendet von
AutoFillRelatedYouTubeChannels-Command,AutoFillCrossPlatformRelated-Command
YouTubeUpdateStatusService
Location: app/Services/YouTubeUpdateStatusService.php
Aggregiert den aktuellen Status der YouTube-Profil-Updates. Zeigt an, welche Profile bereits aktualisiert wurden, welche noch ausstehen und welche fehlgeschlagen sind.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
getStatus() | -- | array | Aggregierter Update-Status (total, processed, failed, pending) |
refresh() | -- | void | Status-Cache invalidieren und neu berechnen |
getQueueableProfileIds() | -- | array | Profile-IDs die noch gescraped werden müssen |
Abhängigkeiten
DailySyncRunModel,SocialProfileModel, Cache
Verwendet von
SocialScrapeDailyFollowers-Command, Admin Dashboard, Health Checks
YouTubeResearchKeywordSuggester
Location: app/Services/Social/YouTube/YouTubeResearchKeywordSuggester.php
Extrahiert Keywords aus bestehenden AI-annotierten YouTube-Profilen und liefert die Top-20-Vorschlaege fuer die YouTube Research Batch-Suche. Verwaltet einen 14-Tage-Cooldown ueber YouTubeResearchKeywordCooldown, damit bereits verwendete Keywords nicht erneut vorgeschlagen werden.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
suggest() | int $limit = 20 | array | Top-Keywords aus AI-Profilen (mit Cooldown-Filter) |
markUsed() | array $keywords | void | Keywords als verwendet markieren (14-Tage-Cooldown) |
Logik
- Alle
ai_keywordsaus YouTube-Profilen laden (nurtracking_enabled, nicht blocked/sanitized) - Keywords aggregieren und nach Haeufigkeit sortieren
- Bereits auf Cooldown befindliche Keywords ausfiltern
- Top-N zurueckgeben mit Frequency-Count
Abhaengigkeiten
SocialProfileModel,YouTubeResearchKeywordCooldownModel
Verwendet von
Admin/YouTubeResearch/Index(Keyword-Suggestions Panel)
YouTubeSuggestClient
Location: app/Services/Social/YouTube/YouTubeSuggestClient.php
HTTP-Client fuer die oeffentliche YouTube Autocomplete/Suggest API. Liefert Keyword-Vervollstaendigungen ohne API-Key (oeffentlicher Endpoint). Response-Zeit ca. 200ms.
Public Methods
| Method | Parameter | Return | Beschreibung |
|---|---|---|---|
suggest() | string $query, string $language = 'de' | array | Autocomplete-Vorschlaege fuer Suchbegriff |
Abhaengigkeiten
- Laravel HTTP Client
Verwendet von
Admin/YouTubeResearch/Index(YouTube Suggest Integration)