udn.py 3.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import re
  2. import urllib.parse
  3. from .common import InfoExtractor
  4. from ..utils import (
  5. determine_ext,
  6. int_or_none,
  7. js_to_json,
  8. )
  9. class UDNEmbedIE(InfoExtractor):
  10. IE_DESC = '聯合影音'
  11. _PROTOCOL_RELATIVE_VALID_URL = r'//video\.udn\.com/(?:embed|play)/news/(?P<id>\d+)'
  12. _VALID_URL = r'https?:' + _PROTOCOL_RELATIVE_VALID_URL
  13. _EMBED_REGEX = [rf'<iframe[^>]+src="(?:https?:)?(?P<url>{_PROTOCOL_RELATIVE_VALID_URL})"']
  14. _TESTS = [{
  15. 'url': 'http://video.udn.com/embed/news/300040',
  16. 'info_dict': {
  17. 'id': '300040',
  18. 'ext': 'mp4',
  19. 'title': '生物老師男變女 全校挺"做自己"',
  20. 'thumbnail': r're:^https?://.*\.jpg$',
  21. },
  22. 'params': {
  23. # m3u8 download
  24. 'skip_download': True,
  25. },
  26. 'expected_warnings': ['Failed to parse JSON Expecting value'],
  27. }, {
  28. 'url': 'https://video.udn.com/embed/news/300040',
  29. 'only_matching': True,
  30. }, {
  31. # From https://video.udn.com/news/303776
  32. 'url': 'https://video.udn.com/play/news/303776',
  33. 'only_matching': True,
  34. }]
  35. def _real_extract(self, url):
  36. video_id = self._match_id(url)
  37. page = self._download_webpage(url, video_id)
  38. options_str = self._html_search_regex(
  39. r'var\s+options\s*=\s*([^;]+);', page, 'options')
  40. trans_options_str = js_to_json(options_str)
  41. options = self._parse_json(trans_options_str, 'options', fatal=False) or {}
  42. if options:
  43. video_urls = options['video']
  44. title = options['title']
  45. poster = options.get('poster')
  46. else:
  47. video_urls = self._parse_json(self._html_search_regex(
  48. r'"video"\s*:\s*({.+?})\s*,', trans_options_str, 'video urls'), 'video urls')
  49. title = self._html_search_regex(
  50. r"title\s*:\s*'(.+?)'\s*,", options_str, 'title')
  51. poster = self._html_search_regex(
  52. r"poster\s*:\s*'(.+?)'\s*,", options_str, 'poster', default=None)
  53. if video_urls.get('youtube'):
  54. return self.url_result(video_urls.get('youtube'), 'Youtube')
  55. formats = []
  56. for video_type, api_url in video_urls.items():
  57. if not api_url:
  58. continue
  59. video_url = self._download_webpage(
  60. urllib.parse.urljoin(url, api_url), video_id,
  61. note=f'retrieve url for {video_type} video')
  62. ext = determine_ext(video_url)
  63. if ext == 'm3u8':
  64. formats.extend(self._extract_m3u8_formats(
  65. video_url, video_id, ext='mp4', m3u8_id='hls'))
  66. elif ext == 'f4m':
  67. formats.extend(self._extract_f4m_formats(
  68. video_url, video_id, f4m_id='hds'))
  69. else:
  70. mobj = re.search(r'_(?P<height>\d+)p_(?P<tbr>\d+)\.mp4', video_url)
  71. a_format = {
  72. 'url': video_url,
  73. # video_type may be 'mp4', which confuses YoutubeDL
  74. 'format_id': 'http-' + video_type,
  75. }
  76. if mobj:
  77. a_format.update({
  78. 'height': int_or_none(mobj.group('height')),
  79. 'tbr': int_or_none(mobj.group('tbr')),
  80. })
  81. formats.append(a_format)
  82. return {
  83. 'id': video_id,
  84. 'formats': formats,
  85. 'title': title,
  86. 'thumbnail': poster,
  87. }