]> jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/ciscowebex.py
[ie/orf:on] Improve extraction (#9677)
[yt-dlp.git] / yt_dlp / extractor / ciscowebex.py
1 from .common import InfoExtractor
2 from ..utils import (
3 ExtractorError,
4 int_or_none,
5 try_get,
6 unified_timestamp,
7 )
8
9
10 class CiscoWebexIE(InfoExtractor):
11 IE_NAME = 'ciscowebex'
12 IE_DESC = 'Cisco Webex'
13 _VALID_URL = r'''(?x)
14 (?P<url>https?://(?P<subdomain>[^/#?]*)\.webex\.com/(?:
15 (?P<siteurl_1>[^/#?]*)/(?:ldr|lsr).php\?(?:[^#]*&)*RCID=(?P<rcid>[0-9a-f]{32})|
16 (?:recordingservice|webappng)/sites/(?P<siteurl_2>[^/#?]*)/recording/(?:playback/|play/)?(?P<id>[0-9a-f]{32})
17 ))'''
18
19 _TESTS = [{
20 'url': 'https://demosubdomain.webex.com/demositeurl/ldr.php?RCID=e58e803bc0f766bb5f6376d2e86adb5b',
21 'only_matching': True,
22 }, {
23 'url': 'http://demosubdomain.webex.com/demositeurl/lsr.php?RCID=bc04b4a7b5ea2cc3a493d5ae6aaff5d7',
24 'only_matching': True,
25 }, {
26 'url': 'https://demosubdomain.webex.com/recordingservice/sites/demositeurl/recording/88e7a42f7b19f5b423c54754aecc2ce9/playback',
27 'only_matching': True,
28 }]
29
30 def _real_extract(self, url):
31 mobj = self._match_valid_url(url)
32 rcid = mobj.group('rcid')
33 if rcid:
34 webpage = self._download_webpage(url, None, note='Getting video ID')
35 url = self._search_regex(self._VALID_URL, webpage, 'redirection url', group='url')
36 url = self._request_webpage(url, None, note='Resolving final URL').url
37 mobj = self._match_valid_url(url)
38 subdomain = mobj.group('subdomain')
39 siteurl = mobj.group('siteurl_1') or mobj.group('siteurl_2')
40 video_id = mobj.group('id')
41
42 password = self.get_param('videopassword')
43
44 headers = {'Accept': 'application/json'}
45 if password:
46 headers['accessPwd'] = password
47
48 stream, urlh = self._download_json_handle(
49 'https://%s.webex.com/webappng/api/v1/recordings/%s/stream' % (subdomain, video_id),
50 video_id, headers=headers, query={'siteurl': siteurl}, expected_status=(403, 429))
51
52 if urlh.status == 403:
53 if stream['code'] == 53004:
54 self.raise_login_required()
55 if stream['code'] == 53005:
56 if password:
57 raise ExtractorError('Wrong password', expected=True)
58 raise ExtractorError(
59 'This video is protected by a password, use the --video-password option', expected=True)
60 raise ExtractorError(f'{self.IE_NAME} said: {stream["code"]} - {stream["message"]}', expected=True)
61
62 if urlh.status == 429:
63 self.raise_login_required(
64 f'{self.IE_NAME} asks you to solve a CAPTCHA. Solve CAPTCHA in browser and',
65 method='cookies')
66
67 video_id = stream.get('recordUUID') or video_id
68
69 formats = [{
70 'format_id': 'video',
71 'url': stream['fallbackPlaySrc'],
72 'ext': 'mp4',
73 'vcodec': 'avc1.640028',
74 'acodec': 'mp4a.40.2',
75 }]
76 if stream.get('preventDownload') is False:
77 mp4url = try_get(stream, lambda x: x['downloadRecordingInfo']['downloadInfo']['mp4URL'])
78 if mp4url:
79 formats.append({
80 'format_id': 'video',
81 'url': mp4url,
82 'ext': 'mp4',
83 'vcodec': 'avc1.640028',
84 'acodec': 'mp4a.40.2',
85 })
86 audiourl = try_get(stream, lambda x: x['downloadRecordingInfo']['downloadInfo']['audioURL'])
87 if audiourl:
88 formats.append({
89 'format_id': 'audio',
90 'url': audiourl,
91 'ext': 'mp3',
92 'vcodec': 'none',
93 'acodec': 'mp3',
94 })
95
96 return {
97 'id': video_id,
98 'title': stream['recordName'],
99 'description': stream.get('description'),
100 'uploader': stream.get('ownerDisplayName'),
101 'uploader_id': stream.get('ownerUserName') or stream.get('ownerId'),
102 'timestamp': unified_timestamp(stream.get('createTime')),
103 'duration': int_or_none(stream.get('duration'), 1000),
104 'webpage_url': 'https://%s.webex.com/recordingservice/sites/%s/recording/playback/%s' % (subdomain, siteurl, video_id),
105 'formats': formats,
106 }