mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-05-07 14:30:09 +00:00
Closes #12647 Authored by: InvalidUsernameException, bashonly Co-authored-by: bashonly <88596187+bashonly@users.noreply.github.com>
125 lines
6.0 KiB
Python
125 lines
6.0 KiB
Python
from .zdf import ZDFBaseIE
|
|
from ..utils import (
|
|
int_or_none,
|
|
merge_dicts,
|
|
parse_iso8601,
|
|
)
|
|
from ..utils.traversal import require, traverse_obj
|
|
|
|
|
|
class DreiSatIE(ZDFBaseIE):
|
|
IE_NAME = '3sat'
|
|
_VALID_URL = r'https?://(?:www\.)?3sat\.de/(?:[^/?#]+/)*(?P<id>[^/?#&]+)\.html'
|
|
_TESTS = [{
|
|
'url': 'https://www.3sat.de/dokumentation/reise/traumziele-suedostasiens-die-philippinen-und-vietnam-102.html',
|
|
'info_dict': {
|
|
'id': '231124_traumziele_philippinen_und_vietnam_dokreise',
|
|
'ext': 'mp4',
|
|
'title': 'Traumziele Südostasiens (1/2): Die Philippinen und Vietnam',
|
|
'description': 'md5:26329ce5197775b596773b939354079d',
|
|
'duration': 2625.0,
|
|
'thumbnail': 'https://www.3sat.de/assets/traumziele-suedostasiens-die-philippinen-und-vietnam-100~original?cb=1699870351148',
|
|
'episode': 'Traumziele Südostasiens (1/2): Die Philippinen und Vietnam',
|
|
'episode_id': 'POS_cc7ff51c-98cf-4d12-b99d-f7a551de1c95',
|
|
'timestamp': 1747920900,
|
|
'upload_date': '20250522',
|
|
},
|
|
}, {
|
|
'url': 'https://www.3sat.de/film/ab-18/ab-18---mein-fremdes-ich-100.html',
|
|
'md5': 'f92638413a11d759bdae95c9d8ec165c',
|
|
'info_dict': {
|
|
'id': '221128_mein_fremdes_ich2_ab18',
|
|
'ext': 'mp4',
|
|
'title': 'Ab 18! - Mein fremdes Ich',
|
|
'description': 'md5:cae0c0b27b7426d62ca0dda181738bf0',
|
|
'duration': 2625.0,
|
|
'thumbnail': 'https://www.3sat.de/assets/ab-18---mein-fremdes-ich-106~original?cb=1666081865812',
|
|
'episode': 'Ab 18! - Mein fremdes Ich',
|
|
'episode_id': 'POS_6225d1ca-a0d5-45e3-870b-e783ee6c8a3f',
|
|
'timestamp': 1695081600,
|
|
'upload_date': '20230919',
|
|
},
|
|
}, {
|
|
'url': 'https://www.3sat.de/gesellschaft/37-grad-leben/aus-dem-leben-gerissen-102.html',
|
|
'md5': 'a903eaf8d1fd635bd3317cd2ad87ec84',
|
|
'info_dict': {
|
|
'id': '250323_0903_sendung_sgl',
|
|
'ext': 'mp4',
|
|
'title': 'Plötzlich ohne dich',
|
|
'description': 'md5:380cc10659289dd91510ad8fa717c66b',
|
|
'duration': 1620.0,
|
|
'thumbnail': 'https://www.3sat.de/assets/37-grad-leben-106~original?cb=1645537156810',
|
|
'episode': 'Plötzlich ohne dich',
|
|
'episode_id': 'POS_faa7a93c-c0f2-4d51-823f-ce2ac3ee191b',
|
|
'timestamp': 1743162540,
|
|
'upload_date': '20250328',
|
|
},
|
|
}, {
|
|
# Video with chapters
|
|
'url': 'https://www.3sat.de/kultur/buchmesse/dein-buch-das-beste-von-der-leipziger-buchmesse-2025-teil-1-100.html',
|
|
'md5': '6b95790ce52e75f0d050adcdd2711ee6',
|
|
'info_dict': {
|
|
'id': '250330_dein_buch1_bum',
|
|
'ext': 'mp4',
|
|
'title': 'dein buch - Das Beste von der Leipziger Buchmesse 2025 - Teil 1',
|
|
'description': 'md5:bae51bfc22f15563ce3acbf97d2e8844',
|
|
'duration': 5399.0,
|
|
'thumbnail': 'https://www.3sat.de/assets/buchmesse-kerkeling-100~original?cb=1743329640903',
|
|
'chapters': 'count:24',
|
|
'episode': 'dein buch - Das Beste von der Leipziger Buchmesse 2025 - Teil 1',
|
|
'episode_id': 'POS_1ef236cc-b390-401e-acd0-4fb4b04315fb',
|
|
'timestamp': 1743327000,
|
|
'upload_date': '20250330',
|
|
},
|
|
}, {
|
|
# Same as https://www.zdf.de/filme/filme-sonstige/der-hauptmann-112.html
|
|
'url': 'https://www.3sat.de/film/spielfilm/der-hauptmann-100.html',
|
|
'only_matching': True,
|
|
}, {
|
|
# Same as https://www.zdf.de/wissen/nano/nano-21-mai-2019-102.html, equal media ids
|
|
'url': 'https://www.3sat.de/wissen/nano/nano-21-mai-2019-102.html',
|
|
'only_matching': True,
|
|
}]
|
|
|
|
def _real_extract(self, url):
|
|
video_id = self._match_id(url)
|
|
webpage = self._download_webpage(url, video_id)
|
|
player = self._search_json(
|
|
r'data-zdfplayer-jsb=(["\'])', webpage, 'player JSON', video_id)
|
|
player_url = player['content']
|
|
api_token = f'Bearer {player["apiToken"]}'
|
|
|
|
content = self._call_api(player_url, video_id, 'video metadata', api_token)
|
|
|
|
video_target = content['mainVideoContent']['http://zdf.de/rels/target']
|
|
ptmd_path = traverse_obj(video_target, (
|
|
(('streams', 'default'), None),
|
|
('http://zdf.de/rels/streams/ptmd', 'http://zdf.de/rels/streams/ptmd-template'),
|
|
{str}, any, {require('ptmd path')}))
|
|
ptmd_url = self._expand_ptmd_template(player_url, ptmd_path)
|
|
aspect_ratio = self._parse_aspect_ratio(video_target.get('aspectRatio'))
|
|
info = self._extract_ptmd(ptmd_url, video_id, api_token, aspect_ratio)
|
|
|
|
return merge_dicts(info, {
|
|
**traverse_obj(content, {
|
|
'title': (('title', 'teaserHeadline'), {str}, any),
|
|
'episode': (('title', 'teaserHeadline'), {str}, any),
|
|
'description': (('leadParagraph', 'teasertext'), {str}, any),
|
|
'timestamp': ('editorialDate', {parse_iso8601}),
|
|
}),
|
|
**traverse_obj(video_target, {
|
|
'duration': ('duration', {int_or_none}),
|
|
'chapters': ('streamAnchorTag', {self._extract_chapters}),
|
|
}),
|
|
'thumbnails': self._extract_thumbnails(traverse_obj(content, ('teaserImageRef', 'layouts', {dict}))),
|
|
**traverse_obj(content, ('programmeItem', 0, 'http://zdf.de/rels/target', {
|
|
'series_id': ('http://zdf.de/rels/cmdm/series', 'seriesUuid', {str}),
|
|
'series': ('http://zdf.de/rels/cmdm/series', 'seriesTitle', {str}),
|
|
'season': ('http://zdf.de/rels/cmdm/season', 'seasonTitle', {str}),
|
|
'season_number': ('http://zdf.de/rels/cmdm/season', 'seasonNumber', {int_or_none}),
|
|
'season_id': ('http://zdf.de/rels/cmdm/season', 'seasonUuid', {str}),
|
|
'episode_number': ('episodeNumber', {int_or_none}),
|
|
'episode_id': ('contentId', {str}),
|
|
})),
|
|
})
|