contv.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. from .common import InfoExtractor
  2. from ..utils import (
  3. float_or_none,
  4. int_or_none,
  5. )
  6. class CONtvIE(InfoExtractor):
  7. _VALID_URL = r'https?://(?:www\.)?contv\.com/details-movie/(?P<id>[^/]+)'
  8. _TESTS = [{
  9. 'url': 'https://www.contv.com/details-movie/CEG10022949/days-of-thrills-&-laughter',
  10. 'info_dict': {
  11. 'id': 'CEG10022949',
  12. 'ext': 'mp4',
  13. 'title': 'Days Of Thrills & Laughter',
  14. 'description': 'md5:5d6b3d0b1829bb93eb72898c734802eb',
  15. 'upload_date': '20180703',
  16. 'timestamp': 1530634789.61,
  17. },
  18. 'params': {
  19. # m3u8 download
  20. 'skip_download': True,
  21. },
  22. }, {
  23. 'url': 'https://www.contv.com/details-movie/CLIP-show_fotld_bts/fight-of-the-living-dead:-behind-the-scenes-bites',
  24. 'info_dict': {
  25. 'id': 'CLIP-show_fotld_bts',
  26. 'title': 'Fight of the Living Dead: Behind the Scenes Bites',
  27. },
  28. 'playlist_mincount': 7,
  29. }]
  30. def _real_extract(self, url):
  31. video_id = self._match_id(url)
  32. details = self._download_json(
  33. 'http://metax.contv.live.junctiontv.net/metax/2.5/details/' + video_id,
  34. video_id, query={'device': 'web'})
  35. if details.get('type') == 'episodic':
  36. seasons = self._download_json(
  37. 'http://metax.contv.live.junctiontv.net/metax/2.5/seriesfeed/json/' + video_id,
  38. video_id)
  39. entries = []
  40. for season in seasons:
  41. for episode in season.get('episodes', []):
  42. episode_id = episode.get('id')
  43. if not episode_id:
  44. continue
  45. entries.append(self.url_result(
  46. 'https://www.contv.com/details-movie/' + episode_id,
  47. CONtvIE.ie_key(), episode_id))
  48. return self.playlist_result(entries, video_id, details.get('title'))
  49. m_details = details['details']
  50. title = details['title']
  51. formats = []
  52. media_hls_url = m_details.get('media_hls_url')
  53. if media_hls_url:
  54. formats.extend(self._extract_m3u8_formats(
  55. media_hls_url, video_id, 'mp4',
  56. m3u8_id='hls', fatal=False))
  57. media_mp4_url = m_details.get('media_mp4_url')
  58. if media_mp4_url:
  59. formats.append({
  60. 'format_id': 'http',
  61. 'url': media_mp4_url,
  62. })
  63. subtitles = {}
  64. captions = m_details.get('captions') or {}
  65. for caption_url in captions.values():
  66. subtitles.setdefault('en', []).append({
  67. 'url': caption_url,
  68. })
  69. thumbnails = []
  70. for image in m_details.get('images', []):
  71. image_url = image.get('url')
  72. if not image_url:
  73. continue
  74. thumbnails.append({
  75. 'url': image_url,
  76. 'width': int_or_none(image.get('width')),
  77. 'height': int_or_none(image.get('height')),
  78. })
  79. description = None
  80. for p in ('large_', 'medium_', 'small_', ''):
  81. d = m_details.get(p + 'description')
  82. if d:
  83. description = d
  84. break
  85. return {
  86. 'id': video_id,
  87. 'title': title,
  88. 'formats': formats,
  89. 'thumbnails': thumbnails,
  90. 'description': description,
  91. 'timestamp': float_or_none(details.get('metax_added_on'), 1000),
  92. 'subtitles': subtitles,
  93. 'duration': float_or_none(m_details.get('duration'), 1000),
  94. 'view_count': int_or_none(details.get('num_watched')),
  95. 'like_count': int_or_none(details.get('num_fav')),
  96. 'categories': details.get('category'),
  97. 'tags': details.get('tags'),
  98. 'season_number': int_or_none(details.get('season')),
  99. 'episode_number': int_or_none(details.get('episode')),
  100. 'release_year': int_or_none(details.get('pub_year')),
  101. }