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