3 from .common
import InfoExtractor
11 class BrilliantpalaBaseIE(InfoExtractor
):
12 _NETRC_MACHINE
= 'brilliantpala'
13 _DOMAIN
= '{subdomain}.brilliantpala.org'
15 def _initialize_pre_login(self
):
16 self
._HOMEPAGE
= f
'https://{self._DOMAIN}'
17 self
._LOGIN
_API
= f
'{self._HOMEPAGE}/login/'
18 self
._LOGOUT
_DEVICES
_API
= f
'{self._HOMEPAGE}/logout_devices/?next=/'
19 self
._CONTENT
_API
= f
'{self._HOMEPAGE}/api/v2.4/contents/{{content_id}}/'
20 self
._HLS
_AES
_URI
= f
'{self._HOMEPAGE}/api/v2.5/video_contents/{{content_id}}/key/'
22 def _get_logged_in_username(self
, url
, video_id
):
23 webpage
, urlh
= self
._download
_webpage
_handle
(url
, video_id
)
24 if urlh
.url
.startswith(self
._LOGIN
_API
):
25 self
.raise_login_required()
26 return self
._html
_search
_regex
(
27 r
'"username"\s*:\s*"(?P<username>[^"]+)"', webpage
, 'logged-in username')
29 def _perform_login(self
, username
, password
):
30 login_page
, urlh
= self
._download
_webpage
_handle
(
31 self
._LOGIN
_API
, None, 'Downloading login page', expected_status
=401)
32 if urlh
.status
!= 401 and not urlh
.url
.startswith(self
._LOGIN
_API
):
33 self
.write_debug('Cookies are valid, no login required.')
36 if urlh
.status
== 401:
37 self
.write_debug('Got HTTP Error 401; cookies have been invalidated')
38 login_page
= self
._download
_webpage
(self
._LOGIN
_API
, None, 'Re-downloading login page')
40 login_form
= self
._hidden
_inputs
(login_page
)
45 self
._set
_cookie
(self
._DOMAIN
, 'csrftoken', login_form
['csrfmiddlewaretoken'])
47 logged_page
= self
._download
_webpage
(
48 self
._LOGIN
_API
, None, note
='Logging in', headers
={'Referer': self
._LOGIN
_API
},
49 data
=urlencode_postdata(login_form
))
51 if self
._html
_search
_regex
(
52 r
'(Your username / email and password)', logged_page
, 'auth fail', default
=None):
53 raise ExtractorError('wrong username or password', expected
=True)
55 # the maximum number of logins is one
56 if self
._html
_search
_regex
(
57 r
'(Logout Other Devices)', logged_page
, 'logout devices button', default
=None):
58 logout_device_form
= self
._hidden
_inputs
(logged_page
)
59 self
._download
_webpage
(
60 self
._LOGOUT
_DEVICES
_API
, None, headers
={'Referer': self
._LOGIN
_API
},
61 note
='Logging out other devices', data
=urlencode_postdata(logout_device_form
))
63 def _real_extract(self
, url
):
64 course_id
, content_id
= self
._match
_valid
_url
(url
).group('course_id', 'content_id')
65 video_id
= f
'{course_id}-{content_id}'
67 username
= self
._get
_logged
_in
_username
(url
, video_id
)
69 content_json
= self
._download
_json
(
70 self
._CONTENT
_API
.format(content_id
=content_id
), video_id
,
71 note
='Fetching content info', errnote
='Unable to fetch content info')
74 for stream
in traverse_obj(content_json
, ('video', 'streams', lambda _
, v
: v
['id'] and v
['url'])):
75 formats
= self
._extract
_m
3u8_formats
(stream
['url'], video_id
, fatal
=False)
79 'id': str(stream
['id']),
80 'title': content_json
.get('title'),
82 'hls_aes': {'uri': self
._HLS
_AES
_URI
.format(content_id
=content_id
)},
83 'http_headers': {'X-Key': hashlib
.sha256(username
.encode('ascii')).hexdigest()},
84 'thumbnail': content_json
.get('cover_image'),
87 return self
.playlist_result(
88 entries
, playlist_id
=video_id
, playlist_title
=content_json
.get('title'))
91 class BrilliantpalaElearnIE(BrilliantpalaBaseIE
):
92 IE_NAME
= 'Brilliantpala:Elearn'
93 IE_DESC
= 'VoD on elearn.brilliantpala.org'
94 _VALID_URL
= r
'https?://elearn\.brilliantpala\.org/courses/(?P<course_id>\d+)/contents/(?P<content_id>\d+)/?'
96 'url': 'https://elearn.brilliantpala.org/courses/42/contents/12345/',
97 'only_matching': True,
99 'url': 'https://elearn.brilliantpala.org/courses/98/contents/36683/',
103 'title': 'Physical World, Units and Measurements - 1',
104 'thumbnail': 'https://d1j3vi2u94ebt0.cloudfront.net/institute/brilliantpalalms/chapter_contents/26237/e657f81b90874be19795c7ea081f8d5c.png',
105 'live_status': 'not_live',
108 'skip_download': True,
112 _DOMAIN
= BrilliantpalaBaseIE
._DOMAIN
.format(subdomain
='elearn')
115 class BrilliantpalaClassesIE(BrilliantpalaBaseIE
):
116 IE_NAME
= 'Brilliantpala:Classes'
117 IE_DESC
= 'VoD on classes.brilliantpala.org'
118 _VALID_URL
= r
'https?://classes\.brilliantpala\.org/courses/(?P<course_id>\d+)/contents/(?P<content_id>\d+)/?'
120 'url': 'https://classes.brilliantpala.org/courses/42/contents/12345/',
121 'only_matching': True,
123 'url': 'https://classes.brilliantpala.org/courses/416/contents/25445/',
127 'title': 'Motion in a Straight Line - Class 1',
128 'thumbnail': 'https://d3e4y8hquds3ek.cloudfront.net/institute/brilliantpalaelearn/chapter_contents/ff5ba838d0ec43419f67387fe1a01fa8.png',
129 'live_status': 'not_live',
132 'skip_download': True,
136 _DOMAIN
= BrilliantpalaBaseIE
._DOMAIN
.format(subdomain
='classes')