refactor(iP): Check all available versions instead of just the default

Some titles don't store the HD/FHD/UHD manifests in the default location, so it will now loop through all versions and pick the best one.
This commit is contained in:
stabbedbybrick 2024-04-10 09:07:13 +02:00
parent 03f5a881ee
commit 255a832039

View File

@ -36,7 +36,6 @@ class iP(Service):
\b
Tips:
- Use full title URL as input for best results.
- See which titles are available in UHD: https://www.bbc.co.uk/programmes/p0dh39s7
\b
- An SSL certificate (PEM) is required for accessing the UHD endpoint.
Specify its path using the service configuration data in the root config:
@ -46,6 +45,8 @@ class iP(Service):
cert: path/to/cert
\b
- Use -v H.265 to request UHD tracks
- See which titles are available in UHD:
https://www.bbc.co.uk/iplayer/help/questions/programme-availability/uhd-content
"""
ALIASES = ("bbciplayer", "bbc", "iplayer")
@ -124,37 +125,26 @@ class iP(Service):
return Series(episodes)
def get_tracks(self, title: Union[Movie, Episode]) -> Tracks:
playlist = self.session.get(url=self.config["endpoints"]["playlist"].format(pid=title.id)).json()
if not playlist["defaultAvailableVersion"]:
self.log.error(" - Title is unavailable")
sys.exit(1)
r = self.session.get(url=self.config["endpoints"]["playlist"].format(pid=title.id))
r.raise_for_status()
if self.config.get("cert"):
url = self.config["endpoints"]["manifest_"].format(
vpid=playlist["defaultAvailableVersion"]["smpConfig"]["items"][0]["vpid"],
mediaset="iptv-uhd" if self.vcodec == "H.265" else "iptv-all",
quality = [
connection.get("height")
for i in (
self.check_all_versions(version)
for version in (x.get("pid") for x in r.json()["allAvailableVersions"])
)
for connection in i
if connection.get("height")
]
max_quality = max((h for h in quality if h < "1080"), default=None)
session = self.session
session.mount("https://", SSLCiphers())
session.mount("http://", SSLCiphers())
manifest = session.get(
url, headers={"user-agent": self.config["user_agent"]}, cert=self.config["cert"]
).json()
if "result" in manifest:
self.log.error(f" - Failed to get manifest [{manifest['result']}]")
sys.exit(1)
else:
url = self.config["endpoints"]["manifest"].format(
vpid=playlist["defaultAvailableVersion"]["smpConfig"]["items"][0]["vpid"],
mediaset="iptv-all",
)
manifest = self.session.get(url).json()
media = next((i for i in (self.check_all_versions(version)
for version in (x.get("pid") for x in r.json()["allAvailableVersions"]))
if any(connection.get("height") == max_quality for connection in i)), None)
connection = {}
for video in [x for x in manifest["media"] if x["kind"] == "video"]:
for video in [x for x in media if x["kind"] == "video"]:
connections = sorted(video["connection"], key=lambda x: x["priority"])
if self.vcodec == "H.265":
connection = connections[0]
@ -211,7 +201,7 @@ class iP(Service):
video.codec = Video.Codec.from_codecs(video.data["hls"]["playlist"].stream_info.codecs)
video.bitrate = int(self.find(r"-video=(\d+)", as_list(video.url)[0]) or 0)
for caption in [x for x in manifest["media"] if x["kind"] == "captions"]:
for caption in [x for x in media if x["kind"] == "captions"]:
connection = sorted(caption["connection"], key=lambda x: x["priority"])[0]
tracks.add(
Subtitle(
@ -255,6 +245,35 @@ class iP(Service):
return r.json()["data"]["programme"]
def check_all_versions(self, vpid: str) -> list:
if self.config.get("cert"):
url = self.config["endpoints"]["manifest_"].format(
vpid=vpid,
mediaset="iptv-uhd" if self.vcodec == "H.265" else "iptv-all",
)
session = self.session
session.mount("https://", SSLCiphers())
session.mount("http://", SSLCiphers())
manifest = session.get(
url, headers={"user-agent": self.config["user_agent"]}, cert=self.config["cert"]
).json()
if "result" in manifest:
return {}
else:
url = self.config["endpoints"]["manifest"].format(
vpid=vpid,
mediaset="iptv-all",
)
manifest = self.session.get(url).json()
if "result" in manifest:
return {}
return manifest["media"]
def create_episode(self, episode):
title = episode["episode"]["title"]["default"].strip()
subtitle = episode["episode"]["subtitle"]
@ -283,9 +302,7 @@ class iP(Service):
r = self.session.get(url)
r.raise_for_status()
redux = re.search(
"window.__IPLAYER_REDUX_STATE__ = (.*?);</script>", r.text
).group(1)
redux = re.search("window.__IPLAYER_REDUX_STATE__ = (.*?);</script>", r.text).group(1)
data = json.loads(redux)
subtitle = data["episode"].get("subtitle")