mirror of https://github.com/ytdl-org/youtube-dl
Compare commits
11 Commits
47214e46d8
...
b2ba24bb02
Author | SHA1 | Date |
---|---|---|
dirkf | b2ba24bb02 | 10 months ago |
dirkf | a190b55964 | 10 months ago |
dirkf | b2741f2654 | 10 months ago |
dirkf | 8465222041 | 10 months ago |
dirkf | 4339910df3 | 10 months ago |
dirkf | eaaf4c6736 | 10 months ago |
dirkf | 4566e6e53e | 10 months ago |
dirkf | 1e8ccdd2eb | 10 months ago |
dirkf | cb9366eda5 | 10 months ago |
dirkf | d9d07a9581 | 10 months ago |
dirkf | 825a40744b | 10 months ago |
@ -0,0 +1,69 @@ |
||||
# coding: utf-8 |
||||
from __future__ import unicode_literals |
||||
|
||||
from .common import InfoExtractor |
||||
from ..compat import compat_str |
||||
from ..utils import ( |
||||
ExtractorError, |
||||
merge_dicts, |
||||
T, |
||||
traverse_obj, |
||||
unified_timestamp, |
||||
url_or_none, |
||||
) |
||||
|
||||
|
||||
class ClipchampIE(InfoExtractor): |
||||
_VALID_URL = r'https?://(?:www\.)?clipchamp\.com/watch/(?P<id>[\w-]+)' |
||||
_TESTS = [{ |
||||
'url': 'https://clipchamp.com/watch/gRXZ4ZhdDaU', |
||||
'info_dict': { |
||||
'id': 'gRXZ4ZhdDaU', |
||||
'ext': 'mp4', |
||||
'title': 'Untitled video', |
||||
'uploader': 'Alexander Schwartz', |
||||
'timestamp': 1680805580, |
||||
'upload_date': '20230406', |
||||
'thumbnail': r're:^https?://.+\.jpg', |
||||
}, |
||||
'params': { |
||||
'skip_download': 'm3u8', |
||||
'format': 'bestvideo', |
||||
}, |
||||
}] |
||||
|
||||
_STREAM_URL_TMPL = 'https://%s.cloudflarestream.com/%s/manifest/video.%s' |
||||
_STREAM_URL_QUERY = {'parentOrigin': 'https://clipchamp.com'} |
||||
|
||||
def _real_extract(self, url): |
||||
video_id = self._match_id(url) |
||||
webpage = self._download_webpage(url, video_id) |
||||
data = self._search_nextjs_data(webpage, video_id)['props']['pageProps']['video'] |
||||
|
||||
storage_location = data.get('storage_location') |
||||
if storage_location != 'cf_stream': |
||||
raise ExtractorError('Unsupported clip storage location "%s"' % (storage_location,)) |
||||
|
||||
path = data['download_url'] |
||||
iframe = self._download_webpage( |
||||
'https://iframe.cloudflarestream.com/' + path, video_id, 'Downloading player iframe') |
||||
subdomain = self._search_regex( |
||||
r'''\bcustomer-domain-prefix\s*=\s*("|')(?P<sd>[\w-]+)\1''', iframe, |
||||
'subdomain', group='sd', fatal=False) or 'customer-2ut9yn3y6fta1yxe' |
||||
|
||||
formats = self._extract_mpd_formats( |
||||
self._STREAM_URL_TMPL % (subdomain, path, 'mpd'), video_id, |
||||
query=self._STREAM_URL_QUERY, fatal=False, mpd_id='dash') |
||||
formats.extend(self._extract_m3u8_formats( |
||||
self._STREAM_URL_TMPL % (subdomain, path, 'm3u8'), video_id, 'mp4', |
||||
query=self._STREAM_URL_QUERY, fatal=False, m3u8_id='hls')) |
||||
|
||||
return merge_dicts({ |
||||
'id': video_id, |
||||
'formats': formats, |
||||
'uploader': ' '.join(traverse_obj(data, ('creator', ('first_name', 'last_name'), T(compat_str)))) or None, |
||||
}, traverse_obj(data, { |
||||
'title': ('project', 'project_name', T(compat_str)), |
||||
'timestamp': ('created_at', T(unified_timestamp)), |
||||
'thumbnail': ('thumbnail_url', T(url_or_none)), |
||||
}), rev=True) |
@ -0,0 +1,204 @@ |
||||
# coding: utf-8 |
||||
from __future__ import unicode_literals |
||||
|
||||
import re |
||||
|
||||
from .common import InfoExtractor |
||||
from ..compat import ( |
||||
compat_str, |
||||
) |
||||
from ..utils import ( |
||||
determine_ext, |
||||
extract_attributes, |
||||
int_or_none, |
||||
merge_dicts, |
||||
traverse_obj, |
||||
url_or_none, |
||||
variadic, |
||||
) |
||||
|
||||
|
||||
class DLFBaseIE(InfoExtractor): |
||||
_VALID_URL_BASE = r'https?://(?:www\.)?deutschlandfunk\.de/' |
||||
_BUTTON_REGEX = r'(<button[^>]+alt="Anhören"[^>]+data-audio-diraid[^>]*>)' |
||||
|
||||
def _parse_button_attrs(self, button, audio_id=None): |
||||
attrs = extract_attributes(button) |
||||
audio_id = audio_id or attrs['data-audio-diraid'] |
||||
|
||||
url = traverse_obj( |
||||
attrs, 'data-audio-download-src', 'data-audio', 'data-audioreference', |
||||
'data-audio-src', expected_type=url_or_none) |
||||
ext = determine_ext(url) |
||||
formats = (self._extract_m3u8_formats(url, audio_id, fatal=False) |
||||
if ext == 'm3u8' else [{'url': url, 'ext': ext, 'vcodec': 'none'}]) |
||||
self._sort_formats(formats) |
||||
|
||||
def traverse_attrs(path): |
||||
path = list(variadic(path)) |
||||
t = path.pop() if callable(path[-1]) else None |
||||
return traverse_obj(attrs, path, expected_type=t, get_all=False) |
||||
|
||||
def txt_or_none(v, default=None): |
||||
return default if v is None else (compat_str(v).strip() or default) |
||||
|
||||
return merge_dicts(*reversed([{ |
||||
'id': audio_id, |
||||
# 'extractor_key': DLFIE.ie_key(), |
||||
# 'extractor': DLFIE.IE_NAME, |
||||
'formats': formats, |
||||
}, dict((k, traverse_attrs(v)) for k, v in { |
||||
'title': (('data-audiotitle', 'data-audio-title', 'data-audio-download-tracking-title'), txt_or_none), |
||||
'duration': (('data-audioduration', 'data-audio-duration'), int_or_none), |
||||
'thumbnail': ('data-audioimage', url_or_none), |
||||
'uploader': 'data-audio-producer', |
||||
'series': 'data-audio-series', |
||||
'channel': 'data-audio-origin-site-name', |
||||
'webpage_url': ('data-audio-download-tracking-path', url_or_none), |
||||
}.items())])) |
||||
|
||||
|
||||
class DLFIE(DLFBaseIE): |
||||
IE_NAME = 'dlf' |
||||
_VALID_URL = DLFBaseIE._VALID_URL_BASE + r'[\w-]+-dlf-(?P<id>[\da-f]{8})-100\.html' |
||||
_TESTS = [ |
||||
# Audio as an HLS stream |
||||
{ |
||||
'url': 'https://www.deutschlandfunk.de/tanz-der-saiteninstrumente-das-wild-strings-trio-aus-slowenien-dlf-03a3eb19-100.html', |
||||
'info_dict': { |
||||
'id': '03a3eb19', |
||||
'title': r're:Tanz der Saiteninstrumente [-/] Das Wild Strings Trio aus Slowenien', |
||||
'ext': 'm4a', |
||||
'duration': 3298, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/FALLBACK-IMAGE-AUDIO/512x512.png?t=1603714364673', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'On Stage', |
||||
'channel': 'deutschlandfunk' |
||||
}, |
||||
'params': { |
||||
'skip_download': 'm3u8' |
||||
}, |
||||
'skip': 'This webpage no longer exists' |
||||
}, { |
||||
'url': 'https://www.deutschlandfunk.de/russische-athleten-kehren-zurueck-auf-die-sportbuehne-ein-gefaehrlicher-tueroeffner-dlf-d9cc1856-100.html', |
||||
'info_dict': { |
||||
'id': 'd9cc1856', |
||||
'title': 'Russische Athleten kehren zurück auf die Sportbühne: Ein gefährlicher Türöffner', |
||||
'ext': 'mp3', |
||||
'duration': 291, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/FALLBACK-IMAGE-AUDIO/512x512.png?t=1603714364673', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Kommentare und Themen der Woche', |
||||
'channel': 'deutschlandfunk' |
||||
} |
||||
}, |
||||
] |
||||
|
||||
def _real_extract(self, url): |
||||
audio_id = self._match_id(url) |
||||
webpage = self._download_webpage(url, audio_id) |
||||
|
||||
return self._parse_button_attrs( |
||||
self._search_regex(self._BUTTON_REGEX, webpage, 'button'), audio_id) |
||||
|
||||
|
||||
class DLFCorpusIE(DLFBaseIE): |
||||
IE_NAME = 'dlf:corpus' |
||||
IE_DESC = 'DLF Multi-feed Archives' |
||||
_VALID_URL = DLFBaseIE._VALID_URL_BASE + r'(?P<id>(?![\w-]+-dlf-[\da-f]{8})[\w-]+-\d+)\.html' |
||||
_TESTS = [ |
||||
# Recorded news broadcast with referrals to related broadcasts |
||||
{ |
||||
'url': 'https://www.deutschlandfunk.de/fechten-russland-belarus-ukraine-protest-100.html', |
||||
'info_dict': { |
||||
'id': 'fechten-russland-belarus-ukraine-protest-100', |
||||
'title': r're:Wiederzulassung als neutrale Athleten [-/] Was die Rückkehr russischer und belarussischer Sportler beim Fechten bedeutet', |
||||
'description': 'md5:91340aab29c71aa7518ad5be13d1e8ad' |
||||
}, |
||||
'playlist_mincount': 5, |
||||
'playlist': [{ |
||||
'info_dict': { |
||||
'id': '1fc5d64a', |
||||
'title': r're:Wiederzulassung als neutrale Athleten [-/] Was die Rückkehr russischer und belarussischer Sportler beim Fechten bedeutet', |
||||
'ext': 'mp3', |
||||
'duration': 252, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/aad16241-6b76-4a09-958b-96d0ee1d6f57/512x512.jpg?t=1679480020313', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Sport', |
||||
'channel': 'deutschlandfunk' |
||||
} |
||||
}, { |
||||
'info_dict': { |
||||
'id': '2ada145f', |
||||
'title': r're:(?:Sportpolitik / )?Fechtverband votiert für Rückkehr russischer Athleten', |
||||
'ext': 'mp3', |
||||
'duration': 336, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/FILE_93982766f7317df30409b8a184ac044a/512x512.jpg?t=1678547581005', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Deutschlandfunk Nova', |
||||
'channel': 'deutschlandfunk-nova' |
||||
} |
||||
}, { |
||||
'info_dict': { |
||||
'id': '5e55e8c9', |
||||
'title': r're:Wiederzulassung von Russland und Belarus [-/] "Herumlavieren" des Fechter-Bundes sorgt für Unverständnis', |
||||
'ext': 'mp3', |
||||
'duration': 187, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/a595989d-1ed1-4a2e-8370-b64d7f11d757/512x512.jpg?t=1679173825412', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Sport am Samstag', |
||||
'channel': 'deutschlandfunk' |
||||
} |
||||
}, { |
||||
'info_dict': { |
||||
'id': '47e1a096', |
||||
'title': r're:Rückkehr Russlands im Fechten [-/] "Fassungslos, dass es einfach so passiert ist"', |
||||
'ext': 'mp3', |
||||
'duration': 602, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/da4c494a-21cc-48b4-9cc7-40e09fd442c2/512x512.jpg?t=1678562155770', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Sport am Samstag', |
||||
'channel': 'deutschlandfunk' |
||||
} |
||||
}, { |
||||
'info_dict': { |
||||
'id': '5e55e8c9', |
||||
'title': r're:Wiederzulassung von Russland und Belarus [-/] "Herumlavieren" des Fechter-Bundes sorgt für Unverständnis', |
||||
'ext': 'mp3', |
||||
'duration': 187, |
||||
'thumbnail': 'https://assets.deutschlandfunk.de/a595989d-1ed1-4a2e-8370-b64d7f11d757/512x512.jpg?t=1679173825412', |
||||
'uploader': 'Deutschlandfunk', |
||||
'series': 'Sport am Samstag', |
||||
'channel': 'deutschlandfunk' |
||||
} |
||||
}] |
||||
}, |
||||
# Podcast feed with tag buttons, playlist count fluctuates |
||||
{ |
||||
'url': 'https://www.deutschlandfunk.de/kommentare-und-themen-der-woche-100.html', |
||||
'info_dict': { |
||||
'id': 'kommentare-und-themen-der-woche-100', |
||||
'title': 'Meinung - Kommentare und Themen der Woche', |
||||
'description': 'md5:2901bbd65cd2d45e116d399a099ce5d5', |
||||
}, |
||||
'playlist_mincount': 10, |
||||
}, |
||||
# Podcast feed with no description |
||||
{ |
||||
'url': 'https://www.deutschlandfunk.de/podcast-tolle-idee-100.html', |
||||
'info_dict': { |
||||
'id': 'podcast-tolle-idee-100', |
||||
'title': 'Wissenschaftspodcast - Tolle Idee! - Was wurde daraus?', |
||||
}, |
||||
'playlist_mincount': 11, |
||||
}, |
||||
] |
||||
|
||||
def _real_extract(self, url): |
||||
playlist_id = self._match_id(url) |
||||
webpage = self._download_webpage(url, playlist_id) |
||||
|
||||
return self.playlist_result( |
||||
map(self._parse_button_attrs, re.findall(self._BUTTON_REGEX, webpage)), |
||||
playlist_id, self._html_search_meta(['og:title', 'twitter:title'], webpage, default=None), |
||||
self._html_search_meta(['description', 'og:description', 'twitter:description'], webpage, default=None)) |
@ -0,0 +1,273 @@ |
||||
# coding: utf-8 |
||||
from __future__ import unicode_literals |
||||
|
||||
from .common import InfoExtractor |
||||
from ..utils import ( |
||||
clean_html, |
||||
join_nonempty, |
||||
merge_dicts, |
||||
parse_duration, |
||||
str_or_none, |
||||
T, |
||||
traverse_obj, |
||||
unified_strdate, |
||||
unified_timestamp, |
||||
urlhandle_detect_ext, |
||||
) |
||||
|
||||
|
||||
class GlobalPlayerBaseIE(InfoExtractor): |
||||
|
||||
def _get_page_props(self, url, video_id): |
||||
webpage = self._download_webpage(url, video_id) |
||||
return self._search_nextjs_data(webpage, video_id)['props']['pageProps'] |
||||
|
||||
def _request_ext(self, url, video_id): |
||||
return urlhandle_detect_ext(self._request_webpage( # Server rejects HEAD requests |
||||
url, video_id, note='Determining source extension')) |
||||
|
||||
@staticmethod |
||||
def _clean_desc(x): |
||||
x = clean_html(x) |
||||
if x: |
||||
x = x.replace('\xa0', ' ') |
||||
return x |
||||
|
||||
def _extract_audio(self, episode, series): |
||||
|
||||
return merge_dicts({ |
||||
'vcodec': 'none', |
||||
}, traverse_obj(series, { |
||||
'series': 'title', |
||||
'series_id': 'id', |
||||
'thumbnail': 'imageUrl', |
||||
'uploader': 'itunesAuthor', # podcasts only |
||||
}), traverse_obj(episode, { |
||||
'id': 'id', |
||||
'description': ('description', T(self._clean_desc)), |
||||
'duration': ('duration', T(parse_duration)), |
||||
'thumbnail': 'imageUrl', |
||||
'url': 'streamUrl', |
||||
'timestamp': (('pubDate', 'startDate'), T(unified_timestamp)), |
||||
'title': 'title', |
||||
}, get_all=False), rev=True) |
||||
|
||||
|
||||
class GlobalPlayerLiveIE(GlobalPlayerBaseIE): |
||||
_VALID_URL = r'https?://www\.globalplayer\.com/live/(?P<id>\w+)/\w+' |
||||
_TESTS = [{ |
||||
'url': 'https://www.globalplayer.com/live/smoothchill/uk/', |
||||
'info_dict': { |
||||
'id': '2mx1E', |
||||
'ext': 'aac', |
||||
'display_id': 'smoothchill-uk', |
||||
'title': 're:^Smooth Chill.+$', |
||||
'thumbnail': 'https://herald.musicradio.com/media/f296ade8-50c9-4f60-911f-924e96873620.png', |
||||
'description': 'Music To Chill To', |
||||
# 'live_status': 'is_live', |
||||
'is_live': True, |
||||
}, |
||||
}, { |
||||
# national station |
||||
'url': 'https://www.globalplayer.com/live/heart/uk/', |
||||
'info_dict': { |
||||
'id': '2mwx4', |
||||
'ext': 'aac', |
||||
'description': 'turn up the feel good!', |
||||
'thumbnail': 'https://herald.musicradio.com/media/49b9e8cb-15bf-4bf2-8c28-a4850cc6b0f3.png', |
||||
# 'live_status': 'is_live', |
||||
'is_live': True, |
||||
'title': 're:^Heart UK.+$', |
||||
'display_id': 'heart-uk', |
||||
}, |
||||
}, { |
||||
# regional variation |
||||
'url': 'https://www.globalplayer.com/live/heart/london/', |
||||
'info_dict': { |
||||
'id': 'AMqg', |
||||
'ext': 'aac', |
||||
'thumbnail': 'https://herald.musicradio.com/media/49b9e8cb-15bf-4bf2-8c28-a4850cc6b0f3.png', |
||||
'title': 're:^Heart London.+$', |
||||
# 'live_status': 'is_live', |
||||
'is_live': True, |
||||
'display_id': 'heart-london', |
||||
'description': 'turn up the feel good!', |
||||
}, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
video_id = self._match_id(url) |
||||
station = self._get_page_props(url, video_id)['station'] |
||||
stream_url = station['streamUrl'] |
||||
|
||||
return merge_dicts({ |
||||
'id': station['id'], |
||||
'display_id': ( |
||||
join_nonempty('brandSlug', 'slug', from_dict=station) |
||||
or station.get('legacyStationPrefix')), |
||||
'url': stream_url, |
||||
'ext': self._request_ext(stream_url, video_id), |
||||
'vcodec': 'none', |
||||
'is_live': True, |
||||
}, { |
||||
'title': self._live_title(traverse_obj( |
||||
station, (('name', 'brandName'), T(str_or_none)), |
||||
get_all=False)), |
||||
}, traverse_obj(station, { |
||||
'description': 'tagline', |
||||
'thumbnail': 'brandLogo', |
||||
}), rev=True) |
||||
|
||||
|
||||
class GlobalPlayerLivePlaylistIE(GlobalPlayerBaseIE): |
||||
_VALID_URL = r'https?://www\.globalplayer\.com/playlists/(?P<id>\w+)' |
||||
_TESTS = [{ |
||||
# "live playlist" |
||||
'url': 'https://www.globalplayer.com/playlists/8bLk/', |
||||
'info_dict': { |
||||
'id': '8bLk', |
||||
'ext': 'aac', |
||||
# 'live_status': 'is_live', |
||||
'is_live': True, |
||||
'description': r're:(?s).+\bclassical\b.+\bClassic FM Hall [oO]f Fame\b', |
||||
'thumbnail': 'https://images.globalplayer.com/images/551379?width=450&signature=oMLPZIoi5_dBSHnTMREW0Xg76mA=', |
||||
'title': 're:Classic FM Hall of Fame.+$' |
||||
}, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
video_id = self._match_id(url) |
||||
station = self._get_page_props(url, video_id)['playlistData'] |
||||
stream_url = station['streamUrl'] |
||||
|
||||
return merge_dicts({ |
||||
'id': video_id, |
||||
'url': stream_url, |
||||
'ext': self._request_ext(stream_url, video_id), |
||||
'vcodec': 'none', |
||||
'is_live': True, |
||||
}, traverse_obj(station, { |
||||
'title': 'title', |
||||
'description': ('description', T(self._clean_desc)), |
||||
'thumbnail': 'image', |
||||
}), rev=True) |
||||
|
||||
|
||||
class GlobalPlayerAudioIE(GlobalPlayerBaseIE): |
||||
_VALID_URL = r'https?://www\.globalplayer\.com/(?:(?P<podcast>podcasts)/|catchup/\w+/\w+/)(?P<id>\w+)/?(?:$|[?#])' |
||||
_TESTS = [{ |
||||
# podcast |
||||
'url': 'https://www.globalplayer.com/podcasts/42KuaM/', |
||||
'playlist_mincount': 5, |
||||
'info_dict': { |
||||
'id': '42KuaM', |
||||
'title': 'Filthy Ritual', |
||||
'thumbnail': 'md5:60286e7d12d795bd1bbc9efc6cee643e', |
||||
'categories': ['Society & Culture', 'True Crime'], |
||||
'uploader': 'Global', |
||||
'description': r're:(?s).+\bscam\b.+?\bseries available now\b', |
||||
}, |
||||
}, { |
||||
# radio catchup |
||||
'url': 'https://www.globalplayer.com/catchup/lbc/uk/46vyD7z/', |
||||
'playlist_mincount': 2, |
||||
'info_dict': { |
||||
'id': '46vyD7z', |
||||
'description': 'Nick Ferrari At Breakfast is Leading Britain\'s Conversation.', |
||||
'title': 'Nick Ferrari', |
||||
'thumbnail': 'md5:4df24d8a226f5b2508efbcc6ae874ebf', |
||||
}, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
video_id, podcast = self._match_valid_url(url).group('id', 'podcast') |
||||
props = self._get_page_props(url, video_id) |
||||
series = props['podcastInfo'] if podcast else props['catchupInfo'] |
||||
|
||||
return merge_dicts({ |
||||
'_type': 'playlist', |
||||
'id': video_id, |
||||
'entries': [self._extract_audio(ep, series) for ep in traverse_obj( |
||||
series, ('episodes', lambda _, v: v['id'] and v['streamUrl']))], |
||||
'categories': traverse_obj(series, ('categories', Ellipsis, 'name')) or None, |
||||
}, traverse_obj(series, { |
||||
'description': ('description', T(self._clean_desc)), |
||||
'thumbnail': 'imageUrl', |
||||
'title': 'title', |
||||
'uploader': 'itunesAuthor', # podcasts only |
||||
}), rev=True) |
||||
|
||||
|
||||
class GlobalPlayerAudioEpisodeIE(GlobalPlayerBaseIE): |
||||
_VALID_URL = r'https?://www\.globalplayer\.com/(?:(?P<podcast>podcasts)|catchup/\w+/\w+)/episodes/(?P<id>\w+)/?(?:$|[?#])' |
||||
_TESTS = [{ |
||||
# podcast |
||||
'url': 'https://www.globalplayer.com/podcasts/episodes/7DrfNnE/', |
||||
'info_dict': { |
||||
'id': '7DrfNnE', |
||||
'ext': 'mp3', |
||||
'title': 'Filthy Ritual - Trailer', |
||||
'description': 'md5:1f1562fd0f01b4773b590984f94223e0', |
||||
'thumbnail': 'md5:60286e7d12d795bd1bbc9efc6cee643e', |
||||
'duration': 225.0, |
||||
'timestamp': 1681254900, |
||||
'series': 'Filthy Ritual', |
||||
'series_id': '42KuaM', |
||||
'upload_date': '20230411', |
||||
'uploader': 'Global', |
||||
}, |
||||
}, { |
||||
# radio catchup |
||||
'url': 'https://www.globalplayer.com/catchup/lbc/uk/episodes/2zGq26Vcv1fCWhddC4JAwETXWe/', |
||||
'only_matching': True, |
||||
# expired: refresh the details with a current show for a full test |
||||
'info_dict': { |
||||
'id': '2zGq26Vcv1fCWhddC4JAwETXWe', |
||||
'ext': 'm4a', |
||||
'timestamp': 1682056800, |
||||
'series': 'Nick Ferrari', |
||||
'thumbnail': 'md5:4df24d8a226f5b2508efbcc6ae874ebf', |
||||
'upload_date': '20230421', |
||||
'series_id': '46vyD7z', |
||||
'description': 'Nick Ferrari At Breakfast is Leading Britain\'s Conversation.', |
||||
'title': 'Nick Ferrari', |
||||
'duration': 10800.0, |
||||
}, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
video_id, podcast = self._match_valid_url(url).group('id', 'podcast') |
||||
props = self._get_page_props(url, video_id) |
||||
episode = props['podcastEpisode'] if podcast else props['catchupEpisode'] |
||||
|
||||
return self._extract_audio( |
||||
episode, traverse_obj(episode, 'podcast', 'show', expected_type=dict) or {}) |
||||
|
||||
|
||||
class GlobalPlayerVideoIE(GlobalPlayerBaseIE): |
||||
_VALID_URL = r'https?://www\.globalplayer\.com/videos/(?P<id>\w+)' |
||||
_TESTS = [{ |
||||
'url': 'https://www.globalplayer.com/videos/2JsSZ7Gm2uP/', |
||||
'info_dict': { |
||||
'id': '2JsSZ7Gm2uP', |
||||
'ext': 'mp4', |
||||
'description': 'md5:6a9f063c67c42f218e42eee7d0298bfd', |
||||
'thumbnail': 'md5:d4498af48e15aae4839ce77b97d39550', |
||||
'upload_date': '20230420', |
||||
'title': 'Treble Malakai Bayoh sings a sublime Handel aria at Classic FM Live', |
||||
}, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
video_id = self._match_id(url) |
||||
meta = self._get_page_props(url, video_id)['videoData'] |
||||
|
||||
return merge_dicts({ |
||||
'id': video_id, |
||||
}, traverse_obj(meta, { |
||||
'url': 'url', |
||||
'thumbnail': ('image', 'url'), |
||||
'title': 'title', |
||||
'upload_date': ('publish_date', T(unified_strdate)), |
||||
'description': 'description', |
||||
}), rev=True) |
@ -0,0 +1,55 @@ |
||||
# coding: utf-8 |
||||
from __future__ import unicode_literals |
||||
|
||||
from .common import InfoExtractor |
||||
from ..utils import ( |
||||
float_or_none, |
||||
merge_dicts, |
||||
str_or_none, |
||||
T, |
||||
traverse_obj, |
||||
url_or_none, |
||||
) |
||||
|
||||
|
||||
class WhypIE(InfoExtractor): |
||||
_VALID_URL = r'https?://(?:www\.)?whyp\.it/tracks/(?P<id>\d+)' |
||||
_TESTS = [{ |
||||
'url': 'https://www.whyp.it/tracks/18337/home-page-example-track-b4kq7', |
||||
'md5': 'c1187b42ebf8605284e3dc92aeb33d16', |
||||
'info_dict': { |
||||
'url': 'https://cdn.whyp.it/50eb17cc-e9ff-4e18-b89b-dc9206a95cb1.mp3', |
||||
'id': '18337', |
||||
'title': 'Home Page Example Track', |
||||
'description': r're:(?s).+\bexample track\b', |
||||
'ext': 'mp3', |
||||
'duration': 52.82, |
||||
'uploader': 'Brad', |
||||
'uploader_id': '1', |
||||
'thumbnail': 'https://cdn.whyp.it/a537bb36-3373-4c61-96c8-27fc1b2f427a.jpg', |
||||
}, |
||||
}, { |
||||
'url': 'https://www.whyp.it/tracks/18337', |
||||
'only_matching': True, |
||||
}] |
||||
|
||||
def _real_extract(self, url): |
||||
unique_id = self._match_id(url) |
||||
webpage = self._download_webpage(url, unique_id) |
||||
data = self._search_nuxt_data(webpage, unique_id)['rawTrack'] |
||||
|
||||
return merge_dicts({ |
||||
'url': data['audio_url'], |
||||
'id': unique_id, |
||||
}, traverse_obj(data, { |
||||
'title': 'title', |
||||
'description': 'description', |
||||
'duration': ('duration', T(float_or_none)), |
||||
'uploader': ('user', 'username'), |
||||
'uploader_id': ('user', 'id', T(str_or_none)), |
||||
'thumbnail': ('artwork_url', T(url_or_none)), |
||||
}), { |
||||
'ext': 'mp3', |
||||
'vcodec': 'none', |
||||
'http_headers': {'Referer': 'https://whyp.it/'}, |
||||
}, rev=True) |
Loading…
Reference in new issue