Files
Playtube/playtube/webview2_runtime.py

86 lines
3.3 KiB
Python

"""Laedt Microsoft Edge WebView2 (per pythonnet / .NET Framework) fuer den Browser-Tab.
Die DLLs (Microsoft.Web.WebView2.Core/WinForms, WebView2Loader) liegen im Projektordner
vendor/webview2 (offizielles NuGet-Paket "Microsoft.Web.WebView2"). Die eigentliche
Browser-Engine ist die auf Windows 10/11 vorinstallierte "WebView2 Runtime" (Edge) - sie
bringt AAC/H.264 mit, die in QtWebEngine fehlen.
"""
from __future__ import annotations
import os
import sys
from functools import lru_cache
from pathlib import Path
from types import SimpleNamespace
class WebView2Unavailable(RuntimeError):
"""WebView2 konnte nicht geladen werden (DLLs oder Runtime fehlen)."""
def _app_base_dir() -> Path:
return Path(getattr(sys, "_MEIPASS", Path(__file__).resolve().parent.parent))
def _vendor_dir() -> Path:
return _app_base_dir() / "vendor" / "webview2"
def _unblock_downloaded_files(folders: tuple[Path, ...]) -> None:
"""Entfernt die "Mark of the Web" (Zone.Identifier) von den DLLs, die .NET laden soll.
Wer die ZIP aus dem Internet laedt und entpackt, bekommt alle Dateien mit dieser
Markierung; .NET verweigert dann das Laden von Python.Runtime.dll ("Failed to resolve
Python.Runtime.Loader.Initialize"). Die Dateien liegen im eigenen App-Ordner - das
Entfernen der Markierung betrifft nur sie."""
if os.name != "nt":
return
for folder in folders:
for path in folder.rglob("*"):
if path.suffix.lower() in (".dll", ".exe"):
try:
os.remove(f"{path}:Zone.Identifier")
except OSError:
pass # keine Markierung vorhanden (Normalfall) oder Dateisystem ohne Datenstroeme
@lru_cache(maxsize=1)
def load() -> SimpleNamespace:
"""Laedt .NET + WebView2 einmalig und gibt die benoetigten Klassen zurueck."""
vendor = _vendor_dir()
core_dll = vendor / "Microsoft.Web.WebView2.Core.dll"
winforms_dll = vendor / "Microsoft.Web.WebView2.WinForms.dll"
if not core_dll.exists() or not winforms_dll.exists():
raise WebView2Unavailable(f"WebView2-DLLs fehlen in {vendor}")
base = _app_base_dir()
_unblock_downloaded_files((vendor, base / "pythonnet", base / "clr_loader"))
# WebView2Loader.dll (nativ) wird ueber den Suchpfad bzw. runtimes/win-x64/native gefunden.
os.environ["PATH"] = f"{vendor}{os.pathsep}{os.environ.get('PATH', '')}"
try:
from pythonnet import load as load_runtime
load_runtime("netfx")
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
clr.AddReference(str(core_dll))
clr.AddReference(str(winforms_dll))
from Microsoft.Web.WebView2.Core import (
CoreWebView2PermissionKind,
CoreWebView2PermissionState,
)
from Microsoft.Web.WebView2.WinForms import CoreWebView2CreationProperties, WebView2
except Exception as error: # pythonnet wirft je nach Fehler unterschiedliche Typen
raise WebView2Unavailable(f"WebView2 konnte nicht geladen werden: {error}") from error
return SimpleNamespace(
WebView2=WebView2,
CreationProperties=CoreWebView2CreationProperties,
PermissionKind=CoreWebView2PermissionKind,
PermissionState=CoreWebView2PermissionState,
)