5 from .common
import InfoExtractor
6 from ..compat
import compat_str
21 class Zee5IE(InfoExtractor
):
25 https?://(?:www\.)?zee5\.com/(?:[^#?]+/)?
27 (?:tv-shows|kids|web-series|zee5originals)(?:/[^#/?]+){3}
28 |(?:movies|kids|videos|news|music-videos)/(?!kids-shows)[^#/?]+
29 )/(?P<display_id>[^#/?]+)/
31 (?P<id>[^#/?]+)/?(?:$|[?#])
34 'url': 'https://www.zee5.com/movies/details/adavari-matalaku-ardhale-verule/0-0-movie_1143162669',
36 'id': '0-0-movie_1143162669',
38 'display_id': 'adavari-matalaku-ardhale-verule',
39 'title': 'Adavari Matalaku Ardhale Verule',
41 'description': compat_str
,
42 'alt_title': 'Adavari Matalaku Ardhale Verule',
43 'uploader': 'Zee Entertainment Enterprises Ltd',
44 'release_date': '20070427',
45 'upload_date': '20070427',
46 'timestamp': 1177632000,
47 'thumbnail': r
're:^https?://.*\.jpg$',
49 'episode': 'Episode 0',
56 'url': 'https://www.zee5.com/kids/kids-shows/bandbudh-aur-budbak/0-6-1899/yoga-se-hoga-bandbudh-aur-budbak/0-1-239839',
60 'display_id': 'yoga-se-hoga-bandbudh-aur-budbak',
61 'title': 'Yoga Se Hoga-Bandbudh aur Budbak',
63 'description': compat_str
,
64 'alt_title': 'Yoga Se Hoga-Bandbudh aur Budbak',
65 'uploader': 'Zee Entertainment Enterprises Ltd',
66 'release_date': '20150101',
67 'upload_date': '20150101',
68 'timestamp': 1420070400,
69 'thumbnail': r
're:^https?://.*\.jpg$',
70 'series': 'Bandbudh Aur Budbak',
73 'episode': 'Episode 1',
81 'url': 'https://www.zee5.com/hi/tv-shows/details/kundali-bhagya/0-6-366/kundali-bhagya-march-08-2021/0-1-manual_7g9jv1os7730?country=IN',
84 'url': 'https://www.zee5.com/global/hi/tv-shows/details/kundali-bhagya/0-6-366/kundali-bhagya-march-08-2021/0-1-manual_7g9jv1os7730',
87 'url': 'https://www.zee5.com/web-series/details/mithya/0-6-4z587408/maine-dekhi-hai-uski-mrityu/0-1-6z587412',
90 'url': 'https://www.zee5.com/kids/kids-movies/maya-bommalu/0-0-movie_1040370005',
93 'url': 'https://www.zee5.com/news/details/jana-sena-chief-pawan-kalyan-shows-slippers-to-ysrcp-leaders/0-0-newsauto_6ettj4242oo0',
96 'url': 'https://www.zee5.com/music-videos/details/adhento-gaani-vunnapaatuga-jersey-nani-shraddha-srinath/0-0-56973',
99 _DEVICE_ID
= str(uuid
.uuid4())
101 _LOGIN_HINT
= 'Use "--username <mobile_number>" to login using otp or "--username token" and "--password <user_token>" to login using user token.'
102 _NETRC_MACHINE
= 'zee5'
103 _GEO_COUNTRIES
= ['IN']
106 def _perform_login(self
, username
, password
):
107 if len(username
) == 10 and username
.isdigit() and self
._USER
_TOKEN
is None:
109 otp_request_json
= self
._download
_json
(f
'https://b2bapi.zee5.com/device/sendotp_v1.php?phoneno=91{username}',
110 None, note
='Sending OTP')
111 if otp_request_json
['code'] == 0:
112 self
.to_screen(otp_request_json
['message'])
114 raise ExtractorError(otp_request_json
['message'], expected
=True)
115 otp_code
= self
._get
_tfa
_info
('OTP')
116 otp_verify_json
= self
._download
_json
(f
'https://b2bapi.zee5.com/device/verifyotp_v1.php?phoneno=91{username}&otp={otp_code}&guest_token={self._DEVICE_ID}&platform=web',
117 None, note
='Verifying OTP', fatal
=False)
118 if not otp_verify_json
:
119 raise ExtractorError('Unable to verify OTP.', expected
=True)
120 self
._USER
_TOKEN
= otp_verify_json
.get('token')
121 if not self
._USER
_TOKEN
:
122 raise ExtractorError(otp_request_json
['message'], expected
=True)
123 elif username
.lower() == 'token' and try_call(lambda: jwt_decode_hs256(password
)):
124 self
._USER
_TOKEN
= password
126 raise ExtractorError(self
._LOGIN
_HINT
, expected
=True)
128 token
= jwt_decode_hs256(self
._USER
_TOKEN
)
129 if token
.get('exp', 0) <= int(time
.time()):
130 raise ExtractorError('User token has expired', expected
=True)
131 self
._USER
_COUNTRY
= token
.get('current_country')
133 def _real_extract(self
, url
):
134 video_id
, display_id
= self
._match
_valid
_url
(url
).group('id', 'display_id')
135 access_token_request
= self
._download
_json
(
136 'https://useraction.zee5.com/token/platform_tokens.php?platform_name=web_app',
137 video_id
, note
='Downloading access token')
139 'x-access-token': access_token_request
['token']
142 data
['Authorization'] = 'bearer %s' % self
._USER
_TOKEN
144 data
['X-Z5-Guest-Token'] = self
._DEVICE
_ID
146 json_data
= self
._download
_json
(
147 'https://spapi.zee5.com/singlePlayback/getDetails/secure', video_id
, query
={
148 'content_id': video_id
,
149 'device_id': self
._DEVICE
_ID
,
150 'platform_name': 'desktop_web',
151 'country': self
._USER
_COUNTRY
or self
.get_param('geo_bypass_country') or 'IN',
152 'check_parental_control': False,
153 }, headers
={'content-type': 'application/json'}
, data
=json
.dumps(data
).encode('utf-8'))
154 asset_data
= json_data
['assetDetails']
155 show_data
= json_data
.get('showDetails', {})
156 if 'premium' in asset_data
['business_type']:
157 raise ExtractorError('Premium content is DRM protected.', expected
=True)
158 if not asset_data
.get('hls_url'):
159 self
.raise_login_required(self
._LOGIN
_HINT
, metadata_available
=True, method
=None)
160 formats
, m3u8_subs
= self
._extract
_m
3u8_formats
_and
_subtitles
(asset_data
['hls_url'], video_id
, 'mp4', fatal
=False)
163 for sub
in asset_data
.get('subtitle_url', []):
164 sub_url
= sub
.get('url')
167 subtitles
.setdefault(sub
.get('language', 'en'), []).append({
168 'url': self
._proto
_relative
_url
(sub_url
),
170 subtitles
= self
._merge
_subtitles
(subtitles
, m3u8_subs
)
173 'display_id': display_id
,
174 'title': asset_data
['title'],
176 'subtitles': subtitles
,
177 'duration': int_or_none(asset_data
.get('duration')),
178 'description': str_or_none(asset_data
.get('description')),
179 'alt_title': str_or_none(asset_data
.get('original_title')),
180 'uploader': str_or_none(asset_data
.get('content_owner')),
181 'age_limit': parse_age_limit(asset_data
.get('age_rating')),
182 'release_date': unified_strdate(asset_data
.get('release_date')),
183 'timestamp': unified_timestamp(asset_data
.get('release_date')),
184 'thumbnail': url_or_none(asset_data
.get('image_url')),
185 'series': str_or_none(asset_data
.get('tvshow_name')),
186 'season': try_get(show_data
, lambda x
: x
['seasons']['title'], str),
187 'season_number': int_or_none(try_get(show_data
, lambda x
: x
['seasons'][0]['orderid'])),
188 'episode_number': int_or_none(try_get(asset_data
, lambda x
: x
['orderid'])),
189 'tags': try_get(asset_data
, lambda x
: x
['tags'], list)
193 class Zee5SeriesIE(InfoExtractor
):
194 IE_NAME
= 'zee5:series'
195 _VALID_URL
= r
'''(?x)
198 https?://(?:www\.)?zee5\.com/(?:[^#?]+/)?
199 (?:tv-shows|web-series|kids|zee5originals)/(?!kids-movies)(?:[^#/?]+/){2}
201 (?P<id>[^#/?]+)(?:/episodes)?/?(?:$|[?#])
204 'url': 'https://www.zee5.com/kids/kids-shows/bandbudh-aur-budbak/0-6-1899',
205 'playlist_mincount': 156,
210 'url': 'https://www.zee5.com/tv-shows/details/bhabi-ji-ghar-par-hai/0-6-199',
211 'playlist_mincount': 1500,
216 'url': 'https://www.zee5.com/tv-shows/details/agent-raghav-crime-branch/0-6-965',
217 'playlist_mincount': 24,
222 'url': 'https://www.zee5.com/ta/tv-shows/details/nagabhairavi/0-6-3201',
223 'playlist_mincount': 3,
228 'url': 'https://www.zee5.com/global/hi/tv-shows/details/khwaabon-ki-zamin-par/0-6-270',
229 'playlist_mincount': 150,
234 'url': 'https://www.zee5.com/tv-shows/details/chala-hawa-yeu-dya-ladies-zindabaad/0-6-2943/episodes',
235 'only_matching': True,
237 'url': 'https://www.zee5.com/web-series/details/mithya/0-6-4z587408',
238 'only_matching': True,
241 def _entries(self
, show_id
):
242 access_token_request
= self
._download
_json
(
243 'https://useraction.zee5.com/token/platform_tokens.php?platform_name=web_app',
244 show_id
, note
='Downloading access token')
246 'X-Access-Token': access_token_request
['token'],
247 'Referer': 'https://www.zee5.com/',
249 show_url
= f
'https://gwapi.zee5.com/content/tvshow/{show_id}?translation=en&country=IN'
252 show_json
= self
._download
_json
(show_url
, video_id
=show_id
, headers
=headers
)
253 for season
in show_json
.get('seasons') or []:
254 season_id
= try_get(season
, lambda x
: x
['id'], compat_str
)
255 next_url
= f
'https://gwapi.zee5.com/content/tvshow/?season_id={season_id}&type=episode&translation=en&country=IN&on_air=false&asset_subtype=tvshow&page=1&limit=100'
258 episodes_json
= self
._download
_json
(
259 next_url
, video_id
=show_id
, headers
=headers
,
260 note
='Downloading JSON metadata page %d' % page_num
)
261 for episode
in try_get(episodes_json
, lambda x
: x
['episode'], list) or []:
262 video_id
= episode
.get('id')
263 yield self
.url_result(
264 'zee5:%s' % video_id
,
265 ie
=Zee5IE
.ie_key(), video_id
=video_id
)
266 next_url
= url_or_none(episodes_json
.get('next_episode_api'))
268 def _real_extract(self
, url
):
269 show_id
= self
._match
_id
(url
)
270 return self
.playlist_result(self
._entries
(show_id
), playlist_id
=show_id
)