Merge pull request #83 from CodeName393/service.py

Improve service.py
This commit is contained in:
Sp5rky
2026-02-26 08:07:05 -07:00
committed by GitHub
3 changed files with 37 additions and 17 deletions

View File

@@ -1913,8 +1913,7 @@ class dl:
), ),
licence=partial( licence=partial(
service.get_playready_license service.get_playready_license
if (is_playready_cdm(self.cdm)) if is_playready_cdm(self.cdm)
and hasattr(service, "get_playready_license")
else service.get_widevine_license, else service.get_widevine_license,
title=title, title=title,
track=track, track=track,

View File

@@ -394,6 +394,27 @@ class Service(metaclass=ABCMeta):
Decode the data, return as is to reduce unnecessary computations. Decode the data, return as is to reduce unnecessary computations.
""" """
def get_playready_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> Optional[Union[bytes, str]]:
"""
Get a PlayReady License message by sending a License Request (challenge).
This License message contains the encrypted Content Decryption Keys and will be
read by the CDM and decrypted.
This is a very important request to get correct. A bad, unexpected, or missing
value in the request can cause your key to be detected and promptly banned,
revoked, disabled, or downgraded.
:param challenge: The license challenge from the PlayReady CDM.
:param title: The current `Title` from get_titles that is being executed. This is provided in
case it has data needed to be used, e.g. for a HTTP request.
:param track: The current `Track` needing decryption. Provided for same reason as `title`.
:return: The License response as Bytes or a Base64 string. Don't Base64 Encode or
Decode the data, return as is to reduce unnecessary computations.
"""
# Delegates license handling to the Widevine license method by default if a service-specific PlayReady implementation is not provided.
return self.get_widevine_license(challenge=challenge, title=title, track=track)
# Required Abstract functions # Required Abstract functions
# The following functions *must* be implemented by the Service. # The following functions *must* be implemented by the Service.
# The functions will be executed in shown order. # The functions will be executed in shown order.

View File

@@ -303,21 +303,6 @@ class EXAMPLE(Service):
def get_widevine_service_certificate(self, **_: any) -> str: def get_widevine_service_certificate(self, **_: any) -> str:
return self.config.get("certificate") return self.config.get("certificate")
def get_playready_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> Optional[bytes]:
license_url = self.config["endpoints"].get("playready_license")
if not license_url:
raise ValueError("PlayReady license endpoint not configured")
response = self.session.post(
url=license_url,
data=challenge,
headers={
"user-agent": self.config["client"][self.device]["license_user_agent"],
},
)
response.raise_for_status()
return response.content
def get_widevine_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> Optional[Union[bytes, str]]: def get_widevine_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> Optional[Union[bytes, str]]:
license_url = self.license_data.get("url") or self.config["endpoints"].get("widevine_license") license_url = self.license_data.get("url") or self.config["endpoints"].get("widevine_license")
if not license_url: if not license_url:
@@ -340,3 +325,18 @@ class EXAMPLE(Service):
return response.json().get("license") return response.json().get("license")
except ValueError: except ValueError:
return response.content return response.content
def get_playready_license(self, *, challenge: bytes, title: Title_T, track: AnyTrack) -> Optional[Union[bytes, str]]:
license_url = self.config["endpoints"].get("playready_license")
if not license_url:
raise ValueError("PlayReady license endpoint not configured")
response = self.session.post(
url=license_url,
data=challenge,
headers={
"user-agent": self.config["client"][self.device]["license_user_agent"],
},
)
response.raise_for_status()
return response.content