ciscowebex.py 4.3 KB

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