diff --git a/yt_dlp/extractor/dreisat.py b/yt_dlp/extractor/dreisat.py index e8e18675a6..ff05bd371d 100644 --- a/yt_dlp/extractor/dreisat.py +++ b/yt_dlp/extractor/dreisat.py @@ -97,7 +97,8 @@ class DreiSatIE(ZDFBaseIE): (('streams', 'default'), None), ('http://zdf.de/rels/streams/ptmd', 'http://zdf.de/rels/streams/ptmd-template'), {str}, any, {require('ptmd path')})) - info = self._extract_ptmd(player_url, ptmd_path, video_id, api_token) + ptmd_url = self._expand_ptmd_template(player_url, ptmd_path) + info = self._extract_ptmd(ptmd_url, video_id, api_token) return merge_dicts(info, { **traverse_obj(content, { diff --git a/yt_dlp/extractor/phoenix.py b/yt_dlp/extractor/phoenix.py index 25e84594e9..f36e12e899 100644 --- a/yt_dlp/extractor/phoenix.py +++ b/yt_dlp/extractor/phoenix.py @@ -71,8 +71,7 @@ class PhoenixIE(ZDFBaseIE): content_id = details['tracking']['nielsen']['content']['assetid'] info = self._extract_ptmd( - 'https://tmd.phoenix.de', - f'tmd/2/{{playerId}}/vod/ptmd/phoenix/{content_id}', + f'https://tmd.phoenix.de/tmd/2/android_native_6/vod/ptmd/phoenix/{content_id}', content_id) duration = int_or_none(try_get( diff --git a/yt_dlp/extractor/zdf.py b/yt_dlp/extractor/zdf.py index 307e1f0bec..660b468364 100644 --- a/yt_dlp/extractor/zdf.py +++ b/yt_dlp/extractor/zdf.py @@ -1,3 +1,4 @@ +import functools import json import re import time @@ -87,7 +88,10 @@ class ZDFBaseIE(InfoExtractor): 'quality': qualities(self._QUALITIES)(meta.get('quality')), }) for f in fmts) - def _extract_ptmd(self, api_base_url, templates, video_id, api_token=None): + def _expand_ptmd_template(self, api_base_url, template): + return urljoin(api_base_url, template.replace('{playerId}', 'android_native_6')) + + def _extract_ptmd(self, ptmd_urls, video_id, api_token=None): # TODO: If there are multiple PTMD templates, # usually one of them is a sign-language variant of the video. # The format order works out fine as is and prefers the "regular" video, @@ -96,16 +100,14 @@ class ZDFBaseIE(InfoExtractor): # TODO: HTTPS formats are extracted without resolution information # However, we know vertical resolution and the caller often knows apsect ratio. # So we could calculate the correct resulution from those two data points. - templates = variadic(templates) + ptmd_urls = variadic(ptmd_urls) src_captions = [] content_id = None duration = None formats = [] track_uris = set() - for template in templates: - ptmd_url = urljoin(api_base_url, template.replace( - '{playerId}', 'android_native_6')) + for ptmd_url in ptmd_urls: ptmd = self._call_api(ptmd_url, video_id, 'PTMD data', api_token) # As per above TODO on sign language videos variants, # prefer content_id from the last entry to get the "regular" ID. @@ -537,11 +539,10 @@ query VideoByCanonical($canonical: String!) { if not video_data: return self._extract_fallback(video_id) - ptmd_templates = traverse_obj( - video_data, ('currentMedia', 'nodes', ..., 'ptmdTemplate')) - ptmd_data = self._extract_ptmd( - 'https://api.zdf.de', ptmd_templates, video_id, - self._get_api_token(video_id)) + ptmd_urls = traverse_obj(video_data, ( + 'currentMedia', 'nodes', ..., 'ptmdTemplate', + {functools.partial(self._expand_ptmd_template, 'https://api.zdf.de')})) + ptmd_data = self._extract_ptmd(ptmd_urls, video_id, self._get_api_token(video_id)) # We can't use the ID from PTMD extraction as the video ID # because it is not available during playlist extraction. # We fix it here manually instead of inside the method