Zum Hauptinhalt springen

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

MethodParameterReturnBeschreibung
get()string $endpoint, array $queryarrayGeneric GET mit Default-Pool
rawGetWithKeyPool()string $endpoint, array $query, string $poolResponseRaw GET mit spezifischem Pool
getChannelByHandle()string $handlearrayChannel via forHandle Parameter
getChannelByUsername()string $usernamearrayChannel via forUsername Parameter
getChannelById()string $channelIdarrayChannel via id Parameter
getChannelByIdWithParts()string $channelId, string $partsarrayChannel mit Custom Parts
getPlaylistItems()string $playlistId, ?string $pageToken, int $maxResultsarrayPlaylist-Items (Video-Pool)
getVideosByIds()array $videoIds, string $partsarrayVideos via IDs (Video-Pool)
getChannelIdByVideoId()string $videoIdstringChannel-ID aus Video extrahieren

Key-Pool-Architektur

Jeder Pool hat eine kaskadierte Fallback-Kette:

PoolKaskadeVerwendung
defaultYOUTUBE_API_KEYS -> YOUTUBE_API_KEYStandard-Channel-Abfragen
videoVIDEO_KEYS -> EXTENDED_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEYVideo-Statistiken, Playlist-Items
researchRESEARCH_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEYRelated Channels, Auto-Fill
extendedEXTENDED_KEYS -> YOUTUBE_API_KEYS -> YOUTUBE_API_KEYExtended Channel Data

Key-Rotation-Algorithmus

Der Two-Pass-Ansatz minimiert Ausfallzeiten:

  1. Pass 1: Alle nicht-erschöpften Keys durchprobieren. Bei Quota/Rate-Limit: Key im Cache als erschöpft markieren und nächsten probieren.
  2. 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

MethodParameterReturnBeschreibung
resolve()string $urlarrayURL -> 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)

  1. Channel-ID: /channel/UC... -> direkte API-Abfrage via getChannelById()
  2. Handle: /@handle -> API-Abfrage via getChannelByHandle()
  3. Username: /user/name -> API-Abfrage via getChannelByUsername()
  4. Custom URL: /c/name -> Handle-Versuch, dann Username-Fallback
  5. Video-URL: /watch?v=... -> Channel-ID aus Video extrahieren via getChannelIdByVideoId()
  6. 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

MethodParameterReturnBeschreibung
getStatus()--arrayAktuellen Quota-Status mit Verbrauch und Limit
allowsAutoFill()--boolPrüfen ob Auto-Fill-Operations erlaubt sind
hasQuota()int $cost = 1boolPrü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

MethodParameterReturnBeschreibung
getStatus()--arrayAggregierter Update-Status (total, processed, failed, pending)
refresh()--voidStatus-Cache invalidieren und neu berechnen
getQueueableProfileIds()--arrayProfile-IDs die noch gescraped werden müssen

Abhängigkeiten

  • DailySyncRun Model, SocialProfile Model, 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

MethodParameterReturnBeschreibung
suggest()int $limit = 20arrayTop-Keywords aus AI-Profilen (mit Cooldown-Filter)
markUsed()array $keywordsvoidKeywords als verwendet markieren (14-Tage-Cooldown)

Logik

  1. Alle ai_keywords aus YouTube-Profilen laden (nur tracking_enabled, nicht blocked/sanitized)
  2. Keywords aggregieren und nach Haeufigkeit sortieren
  3. Bereits auf Cooldown befindliche Keywords ausfiltern
  4. Top-N zurueckgeben mit Frequency-Count

Abhaengigkeiten

  • SocialProfile Model, YouTubeResearchKeywordCooldown Model

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

MethodParameterReturnBeschreibung
suggest()string $query, string $language = 'de'arrayAutocomplete-Vorschlaege fuer Suchbegriff

Abhaengigkeiten

  • Laravel HTTP Client

Verwendet von

  • Admin/YouTubeResearch/Index (YouTube Suggest Integration)