refactor(DSCP): Prioritize clearkey HLS over Widevine DASH

- The program will now look for AES HLS instead of Widevine DASH.
- Using '-v H.265' will request DASH manifest even if no H.265 tracks are available.
This can be useful if HLS is not available for some reason.
This commit is contained in:
stabbedbybrick 2024-08-02 14:12:31 +02:00
parent a3ec1f86bc
commit 5a286926ec

View File

@ -12,11 +12,11 @@ from urllib.parse import urljoin
import click
from click import Context
from devine.core.credential import Credential
from devine.core.manifests.dash import DASH
from devine.core.manifests import DASH, HLS
from devine.core.search_result import SearchResult
from devine.core.service import Service
from devine.core.titles import Episode, Movie, Movies, Series
from devine.core.tracks import Chapter, Tracks
from devine.core.tracks import Chapters, Tracks
from requests import Request
@ -29,7 +29,10 @@ class DSCP(Service):
Author: stabbedbybrick
Authorization: Cookies
Robustness:
Widevine:
L3: 2160p, AAC2.0
ClearKey:
AES-128: 1080p, AAC2.0
\b
Tips:
@ -38,12 +41,12 @@ class DSCP(Service):
EPISODE: /video/richard-hammonds-workshop/new-beginnings
SPORT: /video/sport/tnt-sports-1/uefa-champions-league
- Use the --lang LANG_RANGE option to request non-english tracks
- use -v H.265 to request H.265 tracks
- use -v H.265 to request H.265 UHD tracks (if available)
\b
Known issues:
- Devine can't properly parse certain manifests, causing an error in download workers.
- Sport streams specifically seem to be the most affected by this.
Notes:
- Using '-v H.265' will request DASH manifest even if no H.265 tracks are available.
This can be useful if HLS is not available for some reason.
"""
@ -118,43 +121,53 @@ class DSCP(Service):
return Series(episodes)
def get_tracks(self, title: Union[Movie, Episode]) -> Tracks:
platform = "firetv" if self.vcodec == "H.265" else "desktop"
res = self._request(
"POST",
"/playback/v3/videoPlaybackInfo",
payload = {
"videoId": title.id,
"deviceInfo": {
"adBlocker": "false",
"drmSupported": "true",
"drmSupported": "false",
"hwDecodingCapabilities": ["H264", "H265"],
"screen": {"width": 3840, "height": 2160},
"player": {"width": 3840, "height": 2160},
},
"wisteriaProperties": {
"advertiser": {"firstPlay": 0, "fwIsLat": 0},
"device": {"browser": {"name": "chrome", "version": "96.0.4664.55"}, "type": platform},
"platform": platform,
"product": "dplus_emea",
"sessionId": str(uuid.uuid1()),
"streamProvider": {"suspendBeaconing": 0, "hlsVersion": 7, "pingConfig": 1},
},
},
)
}
if self.vcodec == "H.265":
payload["wisteriaProperties"]["device"] = {
"browser": {"name": "chrome", "version": "96.0.4664.55"},
"type": "firetv",
}
payload["wisteriaProperties"]["platform"] = "firetv"
res = self._request("POST", "/playback/v3/videoPlaybackInfo", payload=payload)
self.license = None
streaming = res["data"]["attributes"]["streaming"][0]
streaming_type = streaming["type"].strip().lower()
manifest = streaming["url"]
self.token = None
self.license = None
if streaming["protection"]["drmEnabled"]:
self.token = streaming["protection"]["drmToken"]
self.license = streaming["protection"]["schemes"]["widevine"]["licenseUrl"]
if streaming_type == "hls":
tracks = HLS.from_url(url=manifest, session=self.session).to_tracks(language=title.language)
elif streaming_type == "dash":
tracks = DASH.from_url(url=manifest, session=self.session).to_tracks(language=title.language)
else:
raise ValueError(f"Unknown streaming type: {streaming_type}")
return tracks
def get_chapters(self, title: Union[Movie, Episode]) -> list[Chapter]:
return []
def get_chapters(self, title: Union[Movie, Episode]) -> Chapters:
return Chapters()
def get_widevine_service_certificate(self, **_: Any) -> str:
return None
@ -186,12 +199,8 @@ class DSCP(Service):
seasons = [
self._request(
"GET",
"/cms/collections/{}?{}&{}".format(content_id, season, show_id),
params={
"include": "default",
"decorators": "playbackAllowed,contentAction,badges",
},
"GET", "/cms/collections/{}?{}&{}".format(content_id, season, show_id),
params={"include": "default", "decorators": "playbackAllowed,contentAction,badges"},
)
for season in season_params
]
@ -231,15 +240,12 @@ class DSCP(Service):
if not video_id:
raise IndexError("Episode id not found")
params = {
"decorators": "isFavorite",
"include": "primaryChannel",
}
params = {"decorators": "isFavorite", "include": "primaryChannel"}
content = self._request("GET", "/content/videos/{}".format(video_id), params=params)
episode = content["data"]["attributes"]
name = episode.get("name")
if episode.get("secondaryTitle"):
name += " - " + episode.get("secondaryTitle")
name += f" {episode.get('secondaryTitle')}"
return [
Episode(