mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-10-06 16:02:47 +02:00
Add discovery
This commit is contained in:
@@ -5,7 +5,7 @@ Discovery+ Provider Constants
|
||||
All configuration values for the Discovery+ streaming provider.
|
||||
"""
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Final
|
||||
from typing import Dict, List, Final, Optional
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -35,6 +35,7 @@ class DRMSystem(str, Enum):
|
||||
"""DRM systems"""
|
||||
WIDEVINE = "widevine"
|
||||
CLEARKEY = "clearkey"
|
||||
PLAYREADY = "playready"
|
||||
|
||||
|
||||
class AuthProvider(str, Enum):
|
||||
@@ -43,6 +44,22 @@ class AuthProvider(str, Enum):
|
||||
ANONYMOUS = "anonymous"
|
||||
|
||||
|
||||
class PlatformOS(str, Enum):
|
||||
"""
|
||||
Target OS platform used for device/header spoofing.
|
||||
|
||||
LINUX → Chrome browser, Widevine + ClearKey DRM, x-disco-client os_version="0.0.0"
|
||||
WINDOWS → Microsoft Edge browser, PlayReady DRM, x-disco-client os_version="NT 10.0"
|
||||
"""
|
||||
LINUX = "linux"
|
||||
WINDOWS = "windows"
|
||||
|
||||
|
||||
# Active platform — change this single constant to switch all OS-dependent behaviour.
|
||||
# LINUX preserves existing behaviour exactly; WINDOWS mirrors a real Edge/Windows client.
|
||||
DEFAULT_PLATFORM_OS: Final[PlatformOS] = PlatformOS.LINUX
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Basic Configuration
|
||||
# ============================================================================
|
||||
@@ -125,8 +142,21 @@ CHANNEL_ITEM_TYPES: Final[List[str]] = ["distributionChannel", "channel", "linea
|
||||
# User Agent Configuration
|
||||
# ============================================================================
|
||||
|
||||
DISCOVERY_USER_AGENT: Final[
|
||||
str] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
|
||||
# Per-platform user agent strings.
|
||||
# LINUX → Chrome on Linux (original behaviour)
|
||||
# WINDOWS → Edge on Windows (matches real captured HAR traffic)
|
||||
DISCOVERY_USER_AGENT_LINUX: Final[str] = (
|
||||
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"
|
||||
)
|
||||
DISCOVERY_USER_AGENT_WINDOWS: Final[str] = (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
||||
"(KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 Edg/139.0.0.0"
|
||||
)
|
||||
|
||||
# Convenience alias — resolves to the Linux UA by default so existing callers
|
||||
# that reference DISCOVERY_USER_AGENT directly are unaffected.
|
||||
DISCOVERY_USER_AGENT: Final[str] = DISCOVERY_USER_AGENT_LINUX
|
||||
|
||||
# ============================================================================
|
||||
# Device Configuration
|
||||
@@ -148,10 +178,14 @@ DISCOVERY_CLIENT_VERSION: Final[str] = "6.14.0"
|
||||
# x-disco-params header value
|
||||
DISCOVERY_DISCO_PARAMS: Final[str] = "realm=bolt,bid=dplus,features=ar"
|
||||
|
||||
# x-device-info header template — format with device_id and session_id
|
||||
DISCOVERY_DEVICE_INFO_TEMPLATE: Final[str] = (
|
||||
# x-device-info header templates — one per OS platform.
|
||||
# Format placeholders: {device_id}, {session_id}
|
||||
DISCOVERY_DEVICE_INFO_TEMPLATE_LINUX: Final[str] = (
|
||||
f"dplus/{DISCOVERY_CLIENT_VERSION} (desktop/desktop; Linux/x86_64; {{device_id}}/{{session_id}})"
|
||||
)
|
||||
DISCOVERY_DEVICE_INFO_TEMPLATE_WINDOWS: Final[str] = (
|
||||
f"dplus/{DISCOVERY_CLIENT_VERSION} (desktop/desktop; Windows/NT 10.0; {{device_id}}/{{session_id}})"
|
||||
)
|
||||
|
||||
# x-wbd-device-consent header value
|
||||
DISCOVERY_DEVICE_CONSENT: Final[str] = "gpc=0"
|
||||
@@ -190,9 +224,10 @@ DISCOVERY_HMAC_KEY: Final[str] = "55eea189-e9b6-479f-bc51-2224cfda56fe"
|
||||
# x-disco-client-id prefix matches hmacKeys "id" field for web
|
||||
DISCOVERY_CLIENT_ID_PREFIX: Final[str] = "web1_prd"
|
||||
|
||||
# x-disco-client format: WEB:{os_version}:dplus:{client_version}
|
||||
# OS version is "0.0.0" for web (not x86_64 as previously assumed)
|
||||
DISCOVERY_DISCO_CLIENT: Final[str] = f"WEB:0.0.0:dplus:{DISCOVERY_CLIENT_VERSION}"
|
||||
# x-disco-client header — WEB:{os_version}:dplus:{client_version}
|
||||
# os_version encodes the OS: "0.0.0" for Linux web, "NT 10.0" for Windows
|
||||
DISCOVERY_DISCO_CLIENT_LINUX: Final[str] = f"WEB:0.0.0:dplus:{DISCOVERY_CLIENT_VERSION}"
|
||||
DISCOVERY_DISCO_CLIENT_WINDOWS: Final[str] = f"WEB:NT 10.0:dplus:{DISCOVERY_CLIENT_VERSION}"
|
||||
|
||||
# Feature flags endpoint — provides hmacKeys, gisdk clientId, arkose config etc.
|
||||
# x-gisdk clientId comes from the response and is session-specific.
|
||||
@@ -205,23 +240,39 @@ DISCOVERY_FEATURE_FLAGS_PAYLOAD: Final[Dict] = {
|
||||
}
|
||||
|
||||
|
||||
def get_default_device_info() -> Dict[str, any]:
|
||||
def get_default_device_info(platform_os: Optional[PlatformOS] = None) -> Dict[str, any]:
|
||||
"""
|
||||
Return a fresh copy of default device info.
|
||||
Return a fresh copy of default device info for the given OS platform.
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
PlatformOS.LINUX → Chrome on Linux (original behaviour)
|
||||
PlatformOS.WINDOWS → Edge on Windows
|
||||
|
||||
Returns:
|
||||
Dictionary containing device information
|
||||
Dictionary containing device information suitable for the playbackInfo body.
|
||||
"""
|
||||
if platform_os is None:
|
||||
platform_os = DEFAULT_PLATFORM_OS
|
||||
|
||||
if platform_os == PlatformOS.WINDOWS:
|
||||
os_info = {"name": "Windows", "version": "NT 10.0"}
|
||||
browser_info = {"name": "Microsoft Edge", "version": "139.0.0.0"}
|
||||
else:
|
||||
# LINUX — preserves original behaviour exactly
|
||||
os_info = {"name": "Linux", "version": "0.0.0"}
|
||||
browser_info = {"name": "Chrome", "version": "144.0.0.0"}
|
||||
|
||||
return {
|
||||
"deviceId": DEFAULT_DEVICE_ID,
|
||||
"browser": {"name": "Chrome", "version": "144.0.0.0"},
|
||||
"browser": browser_info,
|
||||
"make": "desktop",
|
||||
"model": "desktop",
|
||||
"os": {"name": "Linux", "version": "0.0.0"},
|
||||
"os": os_info,
|
||||
"platform": "WEB",
|
||||
"deviceType": "web",
|
||||
"player": {
|
||||
"sdk": {"name": "Beam Player Desktop", "version": "6.14.0"},
|
||||
"sdk": {"name": "Beam Player Desktop", "version": DISCOVERY_CLIENT_VERSION},
|
||||
"mediaEngine": {
|
||||
"name": "GLUON_BROWSER",
|
||||
"version": "7.0.0",
|
||||
@@ -232,13 +283,35 @@ def get_default_device_info() -> Dict[str, any]:
|
||||
}
|
||||
|
||||
|
||||
def get_default_capabilities() -> Dict[str, any]:
|
||||
def get_default_capabilities(platform_os: Optional[PlatformOS] = None) -> Dict[str, any]:
|
||||
"""
|
||||
Return a fresh copy of default capabilities.
|
||||
Return a fresh copy of default capabilities for the given OS platform.
|
||||
|
||||
The DRM advertised differs by platform:
|
||||
LINUX → ClearKey + Widevine L3 (original behaviour)
|
||||
WINDOWS → ClearKey + PlayReady SL3000 (matches real Edge/Windows client)
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
|
||||
Returns:
|
||||
Dictionary containing device capabilities
|
||||
Dictionary containing device capabilities suitable for the playbackInfo body.
|
||||
"""
|
||||
if platform_os is None:
|
||||
platform_os = DEFAULT_PLATFORM_OS
|
||||
|
||||
if platform_os == PlatformOS.WINDOWS:
|
||||
cdm_list = [
|
||||
{"drmKeySystem": "clearkey"},
|
||||
{"drmKeySystem": "playready", "maxSecurityLevel": "sl3000"},
|
||||
]
|
||||
else:
|
||||
# LINUX — preserves original behaviour exactly
|
||||
cdm_list = [
|
||||
{"drmKeySystem": "clearkey"},
|
||||
{"drmKeySystem": "widevine", "maxSecurityLevel": "l3"},
|
||||
]
|
||||
|
||||
return {
|
||||
"manifests": {"formats": {"dash": {}}},
|
||||
"codecs": {
|
||||
@@ -270,10 +343,7 @@ def get_default_capabilities() -> Dict[str, any]:
|
||||
},
|
||||
},
|
||||
"contentProtection": {
|
||||
"contentDecryptionModules": [
|
||||
{"drmKeySystem": "clearkey"},
|
||||
{"drmKeySystem": "widevine", "maxSecurityLevel": "l3"},
|
||||
]
|
||||
"contentDecryptionModules": cdm_list
|
||||
},
|
||||
"devicePlatform": {
|
||||
"memory": {"allocatedMemory": 0, "freeAvailableMemory": 1.7976931348623157e308},
|
||||
@@ -289,6 +359,41 @@ def get_default_capabilities() -> Dict[str, any]:
|
||||
}
|
||||
|
||||
|
||||
def get_disco_client(platform_os: Optional[PlatformOS] = None) -> str:
|
||||
"""
|
||||
Return the x-disco-client header value for the given OS platform.
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
|
||||
Returns:
|
||||
x-disco-client header string, e.g. "WEB:0.0.0:dplus:6.14.0"
|
||||
"""
|
||||
if platform_os is None:
|
||||
platform_os = DEFAULT_PLATFORM_OS
|
||||
if platform_os == PlatformOS.WINDOWS:
|
||||
return DISCOVERY_DISCO_CLIENT_WINDOWS
|
||||
return DISCOVERY_DISCO_CLIENT_LINUX
|
||||
|
||||
|
||||
def get_device_info_template(platform_os: Optional[PlatformOS] = None) -> str:
|
||||
"""
|
||||
Return the x-device-info header template for the given OS platform.
|
||||
The caller must still call .format(device_id=..., session_id=...) on the result.
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
|
||||
Returns:
|
||||
x-device-info template string with {device_id} and {session_id} placeholders.
|
||||
"""
|
||||
if platform_os is None:
|
||||
platform_os = DEFAULT_PLATFORM_OS
|
||||
if platform_os == PlatformOS.WINDOWS:
|
||||
return DISCOVERY_DEVICE_INFO_TEMPLATE_WINDOWS
|
||||
return DISCOVERY_DEVICE_INFO_TEMPLATE_LINUX
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Playback Configuration
|
||||
# ============================================================================
|
||||
@@ -301,18 +406,39 @@ DEFAULT_APPLICATION_SESSION_ID: Final[str] = "74985592-a061-4597-ab5b-51492d0fc2
|
||||
# ============================================================================
|
||||
|
||||
DRM_SYSTEM_WIDEVINE: Final[str] = DRMSystem.WIDEVINE.value
|
||||
DRM_SYSTEM_PLAYREADY: Final[str] = DRMSystem.PLAYREADY.value
|
||||
|
||||
|
||||
def get_drm_request_headers() -> Dict[str, str]:
|
||||
def get_user_agent(platform_os: Optional[PlatformOS] = None) -> str:
|
||||
"""
|
||||
Return a fresh copy of DRM request headers.
|
||||
Return the User-Agent string for the given OS platform.
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
|
||||
Returns:
|
||||
Dictionary containing DRM request headers
|
||||
User-Agent header string.
|
||||
"""
|
||||
if platform_os is None:
|
||||
platform_os = DEFAULT_PLATFORM_OS
|
||||
if platform_os == PlatformOS.WINDOWS:
|
||||
return DISCOVERY_USER_AGENT_WINDOWS
|
||||
return DISCOVERY_USER_AGENT_LINUX
|
||||
|
||||
|
||||
def get_drm_request_headers(platform_os: Optional[PlatformOS] = None) -> Dict[str, str]:
|
||||
"""
|
||||
Return a fresh copy of DRM request headers for the given OS platform.
|
||||
|
||||
Args:
|
||||
platform_os: Target OS platform. Defaults to DEFAULT_PLATFORM_OS.
|
||||
|
||||
Returns:
|
||||
Dictionary containing DRM request headers.
|
||||
"""
|
||||
return {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"User-Agent": DISCOVERY_USER_AGENT,
|
||||
"User-Agent": get_user_agent(platform_os),
|
||||
"Origin": "https://play.discoveryplus.com",
|
||||
"Referer": "https://play.discoveryplus.com/",
|
||||
"traceparent": "00-aba275155d9ed5c2b54d576682cb30e6-ddfd854be17b3a6e-01",
|
||||
|
||||
@@ -27,9 +27,11 @@ from .auth import (
|
||||
from .constants import (
|
||||
DEFAULT_COUNTRY,
|
||||
DEFAULT_TENANT,
|
||||
DEFAULT_PLATFORM_OS,
|
||||
DISCOVERY_LOGO,
|
||||
DISCOVERY_USER_AGENT,
|
||||
DRMSystem as DiscoveryDRMSystem,
|
||||
DRM_SYSTEM_PLAYREADY,
|
||||
PlatformOS,
|
||||
SUPPORTED_AUTH_TYPES,
|
||||
SUPPORTED_COUNTRIES,
|
||||
CMS_INCLUDE_PARAMS,
|
||||
@@ -38,7 +40,10 @@ from .constants import (
|
||||
CHANNEL_ITEM_TYPES,
|
||||
get_default_capabilities,
|
||||
get_default_device_info,
|
||||
get_device_info_template,
|
||||
get_disco_client,
|
||||
get_drm_request_headers,
|
||||
get_user_agent,
|
||||
)
|
||||
from .exceptions import (
|
||||
PlaybackRestrictedException,
|
||||
@@ -56,7 +61,8 @@ class DiscoveryProvider(StreamingProvider):
|
||||
- Multi-country support (EMEA region)
|
||||
- Anonymous and user authentication
|
||||
- Live channels and VOD content
|
||||
- DRM-protected streams (Widevine)
|
||||
- DRM-protected streams (Widevine on Linux, PlayReady on Windows)
|
||||
- OS platform spoofing via PlatformOS (see constants.DEFAULT_PLATFORM_OS)
|
||||
- Provider cache pattern for efficient channel management
|
||||
"""
|
||||
|
||||
@@ -78,6 +84,7 @@ class DiscoveryProvider(StreamingProvider):
|
||||
settings_manager=None,
|
||||
proxy_config: Optional[ProxyConfig] = None,
|
||||
proxy_url: Optional[str] = None,
|
||||
platform_os: Optional[PlatformOS] = None,
|
||||
):
|
||||
"""
|
||||
Initialize Discovery+ provider.
|
||||
@@ -91,6 +98,10 @@ class DiscoveryProvider(StreamingProvider):
|
||||
settings_manager: Settings manager instance
|
||||
proxy_config: Optional proxy configuration
|
||||
proxy_url: Optional proxy URL string
|
||||
platform_os: OS platform to spoof (PlatformOS.LINUX or PlatformOS.WINDOWS).
|
||||
Defaults to DEFAULT_PLATFORM_OS from constants.
|
||||
LINUX → Widevine + Chrome on Linux (original behaviour)
|
||||
WINDOWS → PlayReady + Edge on Windows
|
||||
|
||||
Raises:
|
||||
ValueError: If country not supported or credentials missing
|
||||
@@ -103,6 +114,9 @@ class DiscoveryProvider(StreamingProvider):
|
||||
|
||||
super().__init__(country=country)
|
||||
|
||||
# OS platform used for all device/header/DRM spoofing
|
||||
self.platform_os: PlatformOS = platform_os if platform_os is not None else DEFAULT_PLATFORM_OS
|
||||
|
||||
self.auth_type = auth_type
|
||||
self._settings_manager = settings_manager
|
||||
|
||||
@@ -120,7 +134,7 @@ class DiscoveryProvider(StreamingProvider):
|
||||
proxy_config=proxy_config,
|
||||
proxy_url=proxy_url,
|
||||
config_dir=config_dir,
|
||||
user_agent=DISCOVERY_USER_AGENT,
|
||||
user_agent=get_user_agent(self.platform_os),
|
||||
timeout=30,
|
||||
max_retries=3,
|
||||
)
|
||||
@@ -247,7 +261,7 @@ class DiscoveryProvider(StreamingProvider):
|
||||
"""Get headers with authentication"""
|
||||
return self._build_provider_headers(
|
||||
base_headers={
|
||||
"User-Agent": DISCOVERY_USER_AGENT,
|
||||
"User-Agent": get_user_agent(self.platform_os),
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
@@ -437,9 +451,9 @@ class DiscoveryProvider(StreamingProvider):
|
||||
"ssaiProvider": {"version": "2.2.0"},
|
||||
},
|
||||
"consumptionType": "streaming",
|
||||
"deviceInfo": get_default_device_info(),
|
||||
"deviceInfo": get_default_device_info(self.platform_os),
|
||||
"editId": edit_id,
|
||||
"capabilities": get_default_capabilities(),
|
||||
"capabilities": get_default_capabilities(self.platform_os),
|
||||
"gdpr": False,
|
||||
"firstPlay": False,
|
||||
"playbackSessionId": str(uuid.uuid4()),
|
||||
@@ -567,15 +581,28 @@ class DiscoveryProvider(StreamingProvider):
|
||||
"""
|
||||
Extract streaming URLs and DRM info from playback response.
|
||||
|
||||
Detects whichever DRM scheme is present in the response — either
|
||||
'widevine' (Linux/Chrome) or 'playready' (Windows/Edge) — and
|
||||
records it as ``drm_system`` so callers can build the correct DRMConfig
|
||||
without needing to know the active PlatformOS.
|
||||
|
||||
Args:
|
||||
playback_data: Playback API response
|
||||
|
||||
Returns:
|
||||
Dictionary with manifest_url, license_url, drm_auth, etc.
|
||||
Dictionary with:
|
||||
manifest_url – DASH manifest URL
|
||||
license_url – DRM license server URL (or None)
|
||||
drm_system – 'widevine' | 'playready' | None
|
||||
drm_auth – JWT auth token extracted from license URL (or None)
|
||||
streaming_format – 'dash' (always for Discovery+)
|
||||
drm_expiration – ISO-8601 expiration string (or None)
|
||||
fallback_manifest – Fallback manifest URL (or None)
|
||||
"""
|
||||
result = {
|
||||
"manifest_url": None,
|
||||
"license_url": None,
|
||||
"drm_system": None,
|
||||
"drm_auth": None,
|
||||
"streaming_format": "dash",
|
||||
"drm_expiration": None,
|
||||
@@ -596,22 +623,32 @@ class DiscoveryProvider(StreamingProvider):
|
||||
if fallback_manifest:
|
||||
result["fallback_manifest"] = fallback_manifest.get("url")
|
||||
|
||||
# Extract DRM info
|
||||
# Extract DRM info — check both schemes in priority order.
|
||||
# The server returns exactly the scheme(s) matching the capabilities
|
||||
# we advertised in the playback request (widevine for Linux,
|
||||
# playready for Windows). We probe both so this method stays
|
||||
# stateless and works regardless of which platform produced the response.
|
||||
drm = playback_data.get("drm", {})
|
||||
if drm:
|
||||
result["drm_expiration"] = drm.get("expirationDate")
|
||||
schemes = drm.get("schemes", {})
|
||||
widevine = schemes.get("widevine", {})
|
||||
if widevine:
|
||||
result["license_url"] = widevine.get("licenseUrl")
|
||||
result["drm_expiration"] = drm.get("expirationDate")
|
||||
|
||||
# Extract auth token from license URL if present
|
||||
if result["license_url"] and "auth=" in result["license_url"]:
|
||||
import urllib.parse
|
||||
parsed = urllib.parse.urlparse(result["license_url"])
|
||||
query = urllib.parse.parse_qs(parsed.query)
|
||||
if "auth" in query:
|
||||
result["drm_auth"] = query["auth"][0]
|
||||
# Preference order: widevine → playready (mirrors Linux default)
|
||||
scheme_priority = ["widevine", "playready"]
|
||||
for scheme_name in scheme_priority:
|
||||
scheme = schemes.get(scheme_name, {})
|
||||
if scheme and scheme.get("licenseUrl"):
|
||||
result["license_url"] = scheme["licenseUrl"]
|
||||
result["drm_system"] = scheme_name
|
||||
|
||||
# Extract JWT auth token from the license URL if present
|
||||
if "auth=" in result["license_url"]:
|
||||
import urllib.parse
|
||||
parsed = urllib.parse.urlparse(result["license_url"])
|
||||
query = urllib.parse.parse_qs(parsed.query)
|
||||
if "auth" in query:
|
||||
result["drm_auth"] = query["auth"][0]
|
||||
break # Stop at first found scheme
|
||||
|
||||
# Extract CDN info
|
||||
cdn = playback_data.get("cdn", {})
|
||||
@@ -623,6 +660,61 @@ class DiscoveryProvider(StreamingProvider):
|
||||
|
||||
return result
|
||||
|
||||
def _build_drm_config(self, streaming_data: Dict[str, Any]) -> Optional[DRMConfig]:
|
||||
"""
|
||||
Build a DRMConfig from extracted streaming data.
|
||||
|
||||
Selects the correct DRMSystem based on the scheme returned by the
|
||||
server (recorded in ``streaming_data["drm_system"]``). Falls back to
|
||||
the active ``self.platform_os`` when the scheme is absent so the caller
|
||||
never has to make this decision themselves.
|
||||
|
||||
Supported schemes:
|
||||
'widevine' → DRMSystem.WIDEVINE (Linux/Chrome path)
|
||||
'playready' → DRMSystem.PLAYREADY (Windows/Edge path)
|
||||
|
||||
Args:
|
||||
streaming_data: Dictionary returned by extract_streaming_data()
|
||||
|
||||
Returns:
|
||||
DRMConfig instance or None if no license URL is available
|
||||
"""
|
||||
license_url = streaming_data.get("license_url")
|
||||
if not license_url:
|
||||
return None
|
||||
|
||||
# Resolve DRM system from what the server actually returned,
|
||||
# falling back to platform_os expectation if not present.
|
||||
drm_system_str = streaming_data.get("drm_system")
|
||||
if drm_system_str == "playready":
|
||||
drm_system = DRMSystem.PLAYREADY
|
||||
elif drm_system_str == "widevine":
|
||||
drm_system = DRMSystem.WIDEVINE
|
||||
else:
|
||||
# Fallback: derive from active platform
|
||||
drm_system = (
|
||||
DRMSystem.PLAYREADY
|
||||
if self.platform_os == PlatformOS.WINDOWS
|
||||
else DRMSystem.WIDEVINE
|
||||
)
|
||||
logger.debug(
|
||||
f"drm_system not in streaming_data, inferred from platform_os "
|
||||
f"({self.platform_os.value}): {drm_system.name}"
|
||||
)
|
||||
|
||||
license_headers = get_drm_request_headers(self.platform_os)
|
||||
|
||||
return DRMConfig(
|
||||
system=drm_system,
|
||||
priority=1,
|
||||
license=LicenseConfig(
|
||||
server_url=license_url,
|
||||
req_headers=json.dumps(license_headers),
|
||||
req_data="{CHA-RAW}",
|
||||
use_http_get_request=False,
|
||||
),
|
||||
)
|
||||
|
||||
def populate_streaming_data(
|
||||
self,
|
||||
channels: List[StreamingChannel],
|
||||
@@ -678,8 +770,11 @@ class DiscoveryProvider(StreamingProvider):
|
||||
channel.streaming_format = streaming_data["streaming_format"]
|
||||
|
||||
if streaming_data["license_url"]:
|
||||
drm_config = self._build_drm_config(streaming_data)
|
||||
if drm_config:
|
||||
channel.drm_config = drm_config
|
||||
channel.license_url = streaming_data["license_url"]
|
||||
channel.cdm_type = DiscoveryDRMSystem.WIDEVINE.value
|
||||
channel.cdm_type = streaming_data["drm_system"]
|
||||
|
||||
# Store DRM token in DiscoveryChannel cache
|
||||
if streaming_data["drm_auth"]:
|
||||
@@ -763,20 +858,10 @@ class DiscoveryProvider(StreamingProvider):
|
||||
|
||||
# Configure DRM if license URL is present
|
||||
if streaming_data["license_url"]:
|
||||
license_headers = get_drm_request_headers()
|
||||
|
||||
drm_config = DRMConfig(
|
||||
system=DRMSystem.WIDEVINE,
|
||||
priority=1,
|
||||
license=LicenseConfig(
|
||||
server_url=streaming_data["license_url"],
|
||||
req_headers=json.dumps(license_headers),
|
||||
req_data="{CHA-RAW}",
|
||||
use_http_get_request=False,
|
||||
),
|
||||
)
|
||||
channel.drm_config = drm_config
|
||||
channel.cdm_type = DiscoveryDRMSystem.WIDEVINE.value
|
||||
drm_config = self._build_drm_config(streaming_data)
|
||||
if drm_config:
|
||||
channel.drm_config = drm_config
|
||||
channel.cdm_type = streaming_data["drm_system"]
|
||||
|
||||
return channel
|
||||
|
||||
@@ -858,20 +943,8 @@ class DiscoveryProvider(StreamingProvider):
|
||||
if not streaming_data["license_url"]:
|
||||
return []
|
||||
|
||||
license_headers = get_drm_request_headers()
|
||||
|
||||
drm_config = DRMConfig(
|
||||
system=DRMSystem.WIDEVINE,
|
||||
priority=1,
|
||||
license=LicenseConfig(
|
||||
server_url=streaming_data["license_url"],
|
||||
req_headers=json.dumps(license_headers),
|
||||
req_data="{CHA-RAW}",
|
||||
use_http_get_request=False,
|
||||
),
|
||||
)
|
||||
|
||||
return [drm_config]
|
||||
drm_config = self._build_drm_config(streaming_data)
|
||||
return [drm_config] if drm_config else []
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
|
||||
@@ -6,7 +6,6 @@ iso8601>=1.1.0
|
||||
pycountry>=23.12.11
|
||||
python-dateutil>=2.8.2
|
||||
urllib3>=2.0.7
|
||||
chardet>=5.2.0
|
||||
pymp4~=1.4.0
|
||||
protobuf~=6.33.0
|
||||
pycryptodome~=3.23.0
|
||||
|
||||
Reference in New Issue
Block a user