mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-11-26 02:55:17 +00:00
parent
9431777b4c
commit
b4760c778d
2 changed files with 69 additions and 0 deletions
|
@ -217,6 +217,7 @@
|
||||||
BBCCoUkIPlayerGroupIE,
|
BBCCoUkIPlayerGroupIE,
|
||||||
BBCCoUkPlaylistIE,
|
BBCCoUkPlaylistIE,
|
||||||
)
|
)
|
||||||
|
from .beacon import BeaconTvIE
|
||||||
from .beatbump import (
|
from .beatbump import (
|
||||||
BeatBumpPlaylistIE,
|
BeatBumpPlaylistIE,
|
||||||
BeatBumpVideoIE,
|
BeatBumpVideoIE,
|
||||||
|
|
68
yt_dlp/extractor/beacon.py
Normal file
68
yt_dlp/extractor/beacon.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import json
|
||||||
|
|
||||||
|
from .common import InfoExtractor
|
||||||
|
from ..utils import (
|
||||||
|
ExtractorError,
|
||||||
|
parse_iso8601,
|
||||||
|
traverse_obj,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BeaconTvIE(InfoExtractor):
|
||||||
|
_VALID_URL = r'https?://(?:www\.)?beacon\.tv/content/(?P<id>[\w-]+)'
|
||||||
|
|
||||||
|
_TESTS = [{
|
||||||
|
'url': 'https://beacon.tv/content/welcome-to-beacon',
|
||||||
|
'md5': 'b3f5932d437f288e662f10f3bfc5bd04',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 'welcome-to-beacon',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'upload_date': '20240509',
|
||||||
|
'description': 'md5:ea2bd32e71acf3f9fca6937412cc3563',
|
||||||
|
'thumbnail': 'https://cdn.jwplayer.com/v2/media/I4CkkEvN/poster.jpg?width=720',
|
||||||
|
'title': 'Your home for Critical Role!',
|
||||||
|
'timestamp': 1715227200,
|
||||||
|
'duration': 105.494,
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
'url': 'https://beacon.tv/content/re-slayers-take-trailer',
|
||||||
|
'md5': 'd879b091485dbed2245094c8152afd89',
|
||||||
|
'info_dict': {
|
||||||
|
'id': 're-slayers-take-trailer',
|
||||||
|
'ext': 'mp4',
|
||||||
|
'title': 'The Re-Slayer’s Take | Official Trailer',
|
||||||
|
'timestamp': 1715189040,
|
||||||
|
'upload_date': '20240508',
|
||||||
|
'duration': 53.249,
|
||||||
|
'thumbnail': 'https://cdn.jwplayer.com/v2/media/PW5ApIw3/poster.jpg?width=720',
|
||||||
|
},
|
||||||
|
}]
|
||||||
|
|
||||||
|
def _real_extract(self, url):
|
||||||
|
video_id = self._match_id(url)
|
||||||
|
webpage = self._download_webpage(url, video_id)
|
||||||
|
|
||||||
|
content_data = traverse_obj(self._search_nextjs_data(webpage, video_id), (
|
||||||
|
'props', 'pageProps', '__APOLLO_STATE__',
|
||||||
|
lambda k, v: k.startswith('Content:') and v['slug'] == video_id, any))
|
||||||
|
if not content_data:
|
||||||
|
raise ExtractorError('Failed to extract content data')
|
||||||
|
|
||||||
|
jwplayer_data = traverse_obj(content_data, (
|
||||||
|
(('contentVideo', 'video', 'videoData'),
|
||||||
|
('contentPodcast', 'podcast', 'audioData')), {json.loads}, {dict}, any))
|
||||||
|
if not jwplayer_data:
|
||||||
|
if content_data.get('contentType') not in ('videoPodcast', 'video', 'podcast'):
|
||||||
|
raise ExtractorError('Content is not a video/podcast', expected=True)
|
||||||
|
if traverse_obj(content_data, ('contentTier', '__ref')) != 'MemberTier:65b258d178f89be87b4dc0a4':
|
||||||
|
self.raise_login_required('This video/podcast is for members only')
|
||||||
|
raise ExtractorError('Failed to extract content')
|
||||||
|
|
||||||
|
return {
|
||||||
|
**self._parse_jwplayer_data(jwplayer_data, video_id),
|
||||||
|
**traverse_obj(content_data, {
|
||||||
|
'title': ('title', {str}),
|
||||||
|
'description': ('description', {str}),
|
||||||
|
'timestamp': ('publishedAt', {parse_iso8601}),
|
||||||
|
}),
|
||||||
|
}
|
Loading…
Reference in a new issue