]> jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/voot.py
[funimation] Add `FunimationShowIE` (#442)
[yt-dlp.git] / yt_dlp / extractor / voot.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 from .common import InfoExtractor
5 from ..compat import compat_str
6 from ..utils import (
7 ExtractorError,
8 int_or_none,
9 try_get,
10 unified_timestamp,
11 )
12
13
14 class VootIE(InfoExtractor):
15 _VALID_URL = r'''(?x)
16 (?:
17 voot:|
18 (?:https?://)(?:www\.)?voot\.com/?
19 (?:
20 movies/[^/]+/|
21 (?:shows|kids)/(?:[^/]+/){4}
22 )
23 )
24 (?P<id>\d{3,})
25 '''
26 _GEO_COUNTRIES = ['IN']
27 _TESTS = [{
28 'url': 'https://www.voot.com/shows/ishq-ka-rang-safed/1/360558/is-this-the-end-of-kamini-/441353',
29 'info_dict': {
30 'id': '0_8ledb18o',
31 'ext': 'mp4',
32 'title': 'Ishq Ka Rang Safed - Season 01 - Episode 340',
33 'description': 'md5:06291fbbbc4dcbe21235c40c262507c1',
34 'timestamp': 1472162937,
35 'upload_date': '20160825',
36 'series': 'Ishq Ka Rang Safed',
37 'season_number': 1,
38 'episode': 'Is this the end of Kamini?',
39 'episode_number': 340,
40 'view_count': int,
41 'like_count': int,
42 },
43 'params': {
44 'skip_download': True,
45 },
46 'expected_warnings': ['Failed to download m3u8 information'],
47 }, {
48 'url': 'https://www.voot.com/kids/characters/mighty-cat-masked-niyander-e-/400478/school-bag-disappears/440925',
49 'only_matching': True,
50 }, {
51 'url': 'https://www.voot.com/movies/pandavas-5/424627',
52 'only_matching': True,
53 }]
54
55 def _real_extract(self, url):
56 video_id = self._match_id(url)
57 media_info = self._download_json(
58 'https://wapi.voot.com/ws/ott/getMediaInfo.json', video_id,
59 query={
60 'platform': 'Web',
61 'pId': 2,
62 'mediaId': video_id,
63 })
64
65 status_code = try_get(media_info, lambda x: x['status']['code'], int)
66 if status_code != 0:
67 raise ExtractorError(media_info['status']['message'], expected=True)
68
69 media = media_info['assets']
70
71 entry_id = media['EntryId']
72 title = media['MediaName']
73 formats = self._extract_m3u8_formats(
74 'https://cdnapisec.kaltura.com/p/1982551/playManifest/pt/https/f/applehttp/t/web/e/' + entry_id,
75 video_id, 'mp4', m3u8_id='hls')
76 self._sort_formats(formats)
77
78 description, series, season_number, episode, episode_number = [None] * 5
79
80 for meta in try_get(media, lambda x: x['Metas'], list) or []:
81 key, value = meta.get('Key'), meta.get('Value')
82 if not key or not value:
83 continue
84 if key == 'ContentSynopsis':
85 description = value
86 elif key == 'RefSeriesTitle':
87 series = value
88 elif key == 'RefSeriesSeason':
89 season_number = int_or_none(value)
90 elif key == 'EpisodeMainTitle':
91 episode = value
92 elif key == 'EpisodeNo':
93 episode_number = int_or_none(value)
94 return {
95 'extractor_key': 'Kaltura',
96 'id': entry_id,
97 'title': title,
98 'description': description,
99 'series': series,
100 'season_number': season_number,
101 'episode': episode,
102 'episode_number': episode_number,
103 'timestamp': unified_timestamp(media.get('CreationDate')),
104 'duration': int_or_none(media.get('Duration')),
105 'view_count': int_or_none(media.get('ViewCounter')),
106 'like_count': int_or_none(media.get('like_counter')),
107 'formats': formats,
108 }
109
110
111 class VootSeriesIE(InfoExtractor):
112 _VALID_URL = r'https?://(?:www\.)?voot\.com/shows/[^/]+/(?P<id>\d{3,})'
113 _TESTS = [{
114 'url': 'https://www.voot.com/shows/chakravartin-ashoka-samrat/100002',
115 'playlist_mincount': 442,
116 'info_dict': {
117 'id': '100002',
118 },
119 }, {
120 'url': 'https://www.voot.com/shows/ishq-ka-rang-safed/100003',
121 'playlist_mincount': 341,
122 'info_dict': {
123 'id': '100003',
124 },
125 }]
126 _SHOW_API = 'https://psapi.voot.com/media/voot/v1/voot-web/content/generic/season-by-show?sort=season%3Aasc&id={}&responseType=common'
127 _SEASON_API = 'https://psapi.voot.com/media/voot/v1/voot-web/content/generic/series-wise-episode?sort=episode%3Aasc&id={}&responseType=common&page={:d}'
128
129 def _entries(self, show_id):
130 show_json = self._download_json(self._SHOW_API.format(show_id), video_id=show_id)
131 for season in show_json.get('result', []):
132 page_num = 1
133 season_id = try_get(season, lambda x: x['id'], compat_str)
134 season_json = self._download_json(self._SEASON_API.format(season_id, page_num),
135 video_id=season_id,
136 note='Downloading JSON metadata page %d' % page_num)
137 episodes_json = season_json.get('result', [])
138 while episodes_json:
139 page_num += 1
140 for episode in episodes_json:
141 video_id = episode.get('id')
142 yield self.url_result(
143 'voot:%s' % video_id, ie=VootIE.ie_key(), video_id=video_id)
144 episodes_json = self._download_json(self._SEASON_API.format(season_id, page_num),
145 video_id=season_id,
146 note='Downloading JSON metadata page %d' % page_num)['result']
147
148 def _real_extract(self, url):
149 show_id = self._match_id(url)
150 return self.playlist_result(self._entries(show_id), playlist_id=show_id)