Playwright_Videoabspielen

Dieser Commit ist enthalten in:
Claude Project Manager
2025-10-18 21:41:33 +02:00
Ursprung 7261f70073
Commit d41c9f7eac
5 geänderte Dateien mit 149 neuen und 8 gelöschten Zeilen

Datei anzeigen

@ -26,10 +26,15 @@ class PlaywrightManager:
headless: bool = False,
proxy: Optional[Dict[str, str]] = None,
browser_type: str = "chromium",
browser_channel: Optional[str] = None,
user_agent: Optional[str] = None,
screenshots_dir: str = "screenshots",
slowmo: int = 0,
window_position: Optional[Tuple[int, int]] = None):
window_position: Optional[Tuple[int, int]] = None,
enable_autoplay_flag: bool = True,
auto_click_video: bool = True,
auto_mute_on_play: bool = True,
enable_video_enhancements: bool = False):
"""
Initialisiert den PlaywrightManager.
@ -45,10 +50,15 @@ class PlaywrightManager:
self.headless = headless
self.proxy = proxy
self.browser_type = browser_type
self.browser_channel = browser_channel
self.user_agent = user_agent
self.screenshots_dir = screenshots_dir
self.slowmo = slowmo
self.window_position = window_position
self.enable_autoplay_flag = enable_autoplay_flag
self.auto_click_video = auto_click_video
self.auto_mute_on_play = auto_mute_on_play
self.enable_video_enhancements = enable_video_enhancements
# Stelle sicher, dass das Screenshots-Verzeichnis existiert
os.makedirs(self.screenshots_dir, exist_ok=True)
@ -62,7 +72,8 @@ class PlaywrightManager:
# Zähler für Wiederhholungsversuche
self.retry_counter = {}
# Lade Stealth-Konfigurationen
# Lade Browser-/Stealth-Konfigurationen
self.browser_config = self._load_browser_config()
self.stealth_config = self._load_stealth_config()
# Browser Protection Service
@ -92,6 +103,27 @@ class PlaywrightManager:
"fingerprint_noise": True,
"device_scale_factor": 1.0,
}
def _load_browser_config(self) -> Dict[str, Any]:
"""Lädt Browser-bezogene Konfigurationen (Channel, Autoplay-Flags, Video-Helper)."""
try:
config_dir = Path(__file__).parent.parent / "config"
browser_config_path = config_dir / "browser_config.json"
if browser_config_path.exists() and browser_config_path.stat().st_size > 0:
with open(browser_config_path, 'r', encoding='utf-8') as f:
data = json.load(f)
return data if isinstance(data, dict) else {}
except Exception as e:
logger.warning(f"Konnte Browser-Konfiguration nicht laden: {e}")
# Defaults: Chrome/Edge Channel und Autoplay erlauben
return {
"channel": "chrome", # Alternativ: "msedge"
"enable_autoplay_flag": True,
"auto_click_video": True,
"auto_mute_on_play": True,
"enable_video_enhancements": False
}
def start(self) -> Page:
"""
@ -124,8 +156,14 @@ class PlaywrightManager:
'--disable-features=IsolateOrigins,site-per-process',
'--disable-site-isolation-trials',
])
# Autoplay-Blockade aufheben (für Video-Tests/Automation)
# Aktiviert nur, wenn konfiguriert
if self.enable_autoplay_flag if self.enable_autoplay_flag is not None else self.browser_config.get("enable_autoplay_flag", True):
browser_args.append('--autoplay-policy=no-user-gesture-required')
# Browser-Launch-Optionen
# Speichere Args für mögliche Erweiterungen (z.B. Gmail Fresh Browser)
self.browser_args = browser_args
launch_options = {
"headless": self.headless,
"args": browser_args,
@ -139,8 +177,33 @@ class PlaywrightManager:
f'--window-position={x},{y}'
])
# Browser starten
self.browser = browser_instance.launch(**launch_options)
# Für Chromium optional einen Channel (chrome/msedge) nutzen
# Fallback: Ohne Channel starten, wenn der Channel nicht verfügbar ist
if self.browser_type == "chromium":
# Bevorzugung: expliziter Parameter > Konfigurationswert
channel = self.browser_channel if self.browser_channel else self.browser_config.get("channel")
tried_channel = False
if channel:
try:
logger.info(f"Starte Chromium mit Channel '{channel}' (für H.264/AAC Unterstützung)")
self.browser = browser_instance.launch(channel=channel, **launch_options)
tried_channel = True
except Exception as e:
logger.warning(f"Start mit Channel '{channel}' fehlgeschlagen: {e}.")
# Zweiter Versuch mit alternativem Channel (msedge/chrome)
alt = 'msedge' if channel.startswith('chrome') else 'chrome'
try:
logger.info(f"Versuche alternativen Channel '{alt}'")
self.browser = browser_instance.launch(channel=alt, **launch_options)
tried_channel = True
except Exception as e2:
logger.warning(f"Auch alternativer Channel '{alt}' fehlgeschlagen: {e2}. Fallback auf gebundleten Chromium.")
# Fallback ohne Channel unten
if not tried_channel or self.browser is None:
self.browser = browser_instance.launch(**launch_options)
else:
# Andere Browser-Typen normal starten
self.browser = browser_instance.launch(**launch_options)
# Kontext-Optionen für Stealth-Modus
context_options = {
@ -161,6 +224,16 @@ class PlaywrightManager:
# Browserkontext erstellen
self.context = self.browser.new_context(**context_options)
# Optional: Video Stealth/Kompatibilitäts-Verbesserungen anwenden
try:
enable_video_enh = self.enable_video_enhancements if self.enable_video_enhancements is not None else self.browser_config.get("enable_video_enhancements", False)
if enable_video_enh:
from browser.video_stealth_enhancement import VideoStealthEnhancement
VideoStealthEnhancement(self.context).apply_video_stealth()
logger.info("Video-Stealth-Verbesserungen aktiviert")
except Exception as e:
logger.warning(f"Konnte Video-Stealth-Verbesserungen nicht anwenden: {e}")
# JavaScript-Fingerprinting-Schutz
self._apply_stealth_scripts()
@ -288,11 +361,65 @@ class PlaywrightManager:
try:
logger.info(f"Navigiere zu: {url}")
self.page.goto(url, wait_until=wait_until, timeout=timeout)
# Nach erfolgreicher Navigation: Versuche Videos zu starten (optional)
try:
enable_auto_kick = self.enable_autoplay_flag if self.enable_autoplay_flag is not None else self.browser_config.get("enable_autoplay_flag", True)
if enable_auto_kick:
self._kickstart_video_playback()
except Exception:
pass
return True
except Exception as e:
logger.error(f"Fehler bei der Navigation zu {url}: {e}")
self.take_screenshot(f"navigation_error_{int(time.time())}")
return False
def _kickstart_video_playback(self) -> None:
"""
Versucht, die Wiedergabe von <video>-Elementen zu starten.
- Klickt das erste Video (simuliert User-Gesture)
- Setzt muted=true und ruft play() auf allen Videos auf
"""
if self.page is None:
return
try:
# Kurzes Warten auf eventuelle Video-Elemente
self.page.wait_for_selector('video', timeout=1500)
except Exception:
# Kein Video gefunden – nichts zu tun
return
# Optional: Klick auf erstes Video-Element
try:
if self.auto_click_video if self.auto_click_video is not None else self.browser_config.get("auto_click_video", True):
self.page.click('video', timeout=1000)
except Exception:
pass
# Erzwinge (stumm) die Wiedergabe aller Videos über JS
try:
muted = self.auto_mute_on_play if self.auto_mute_on_play is not None else self.browser_config.get("auto_mute_on_play", True)
js = (
"() => {\n"
" const vids = Array.from(document.querySelectorAll('video'));\n"
" let started = 0;\n"
" for (const v of vids) {\n"
" try {\n"
" v.playsInline = true;\n"
" v.setAttribute('playsinline', '');\n"
+ (" v.muted = true;\n" if muted else " v.muted = false;\n") +
" const p = v.play();\n"
" if (p && typeof p.catch === 'function') p.catch(() => {});\n"
" started++;\n"
" } catch (e) {}\n"
" }\n"
" return started;\n"
"}"
)
started = self.page.evaluate(js)
logger.debug(f"Video-Wiedergabe gestartet für {started} Elemente")
except Exception:
pass
def wait_for_selector(self, selector: str, timeout: int = 30000) -> Optional[ElementHandle]:
"""
@ -903,4 +1030,4 @@ if __name__ == "__main__":
# Browser starten und zu einer Seite navigieren
with PlaywrightManager(headless=False) as manager:
manager.navigate_to("https://www.instagram.com")
time.sleep(5) # Kurze Pause zum Anzeigen der Seite
time.sleep(5) # Kurze Pause zum Anzeigen der Seite

Datei anzeigen

@ -1,6 +1,6 @@
{
"current_version": "1.0.0",
"last_check": "2025-07-19T01:32:14.527285",
"last_check": "2025-10-18T21:12:40.353264",
"channel": "stable",
"auto_check": true,
"auto_download": false

Datei anzeigen

@ -0,0 +1,7 @@
{
"channel": "chrome",
"enable_autoplay_flag": true,
"auto_click_video": true,
"auto_mute_on_play": true,
"enable_video_enhancements": false
}

Binäre Datei nicht angezeigt.

Datei anzeigen

@ -43,8 +43,15 @@ def setup_logger(name="main", level=logging.DEBUG):
logger.setLevel(level)
# Datehandler
log_file = os.path.join("logs", f"{name}.log")
# Dateihandler: Stelle sicher, dass das Log-Verzeichnis existiert
log_dir = os.path.join("logs")
try:
os.makedirs(log_dir, exist_ok=True)
except Exception:
# Falls das Anlegen fehlschlägt, weiter mit aktuellem Verzeichnis
pass
log_file = os.path.join(log_dir, f"{name}.log")
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
logger.addHandler(file_handler)