3 from .common
import InfoExtractor
13 class ITProTVBaseIE(InfoExtractor
):
15 'course': 'course?url={}&brand=00002560-0000-3fa9-0000-1d61000035f3',
16 'episode': 'brand/00002560-0000-3fa9-0000-1d61000035f3/episode?url={}'
19 def _call_api(self
, ep
, item_id
, webpage
):
20 return self
._download
_json
(
21 f
'https://api.itpro.tv/api/urza/v3/consumer-web/{self._ENDPOINTS[ep].format(item_id)}',
22 item_id
, note
=f
'Fetching {ep} data API',
23 headers
={'Authorization': f'Bearer {self._fetch_jwt(webpage)}
'})[ep]
25 def _fetch_jwt(self, webpage):
26 return self._search_regex(r'{"passedToken":"([\w-]+\.[\w-]+\.[\w-]+)",', webpage, 'jwt
')
28 def _check_if_logged_in(self, webpage):
29 if re.match(r'{\s
*member\s
*:\s
*null
', webpage):
30 self.raise_login_required()
33 class ITProTVIE(ITProTVBaseIE):
34 _VALID_URL = r'https
://app
.itpro
.tv
/course
/(?P
<course
>[\w
-]+)/(?P
<id>[\w
-]+)'
36 'url
': 'https
://app
.itpro
.tv
/course
/guided
-tour
/introductionitprotv
',
37 'md5
': 'bca4a28c2667fd1a63052e71a94bb88c
',
39 'id': 'introductionitprotv
',
41 'title
': 'An Introduction to ITProTV
101',
42 'thumbnail
': 'https
://itprotv
-image
-bucket
.s3
.amazonaws
.com
/getting
-started
/itprotv
-101-introduction
-PGM
.11_39_56_02.Still001
.png
',
43 'description
': 'md5
:b175c2c3061ce35a4dd33865b2c1da4e
',
45 'series
': 'ITProTV
101',
46 'series_id
': 'guided
-tour
',
47 'availability
': 'needs_auth
',
48 'chapter
': 'ITProTV
101',
50 'chapter_id
': '5dbb3de426b46c0010b5d1b6
'
54 'url
': 'https
://app
.itpro
.tv
/course
/beyond
-tech
/job
-interview
-tips
',
55 'md5
': '101a299b98c47ccf4c67f9f0951defa8
',
57 'id': 'job
-interview
-tips
',
59 'title
': 'Job Interview Tips
',
60 'thumbnail
': 'https
://s3
.amazonaws
.com
:443/production
-itprotv
-thumbnails
/2f370bf5
-294d
-4bbe
-ab80
-c0b5781630ea
.png
',
61 'description
': 'md5
:30d8ba483febdf89ec85623aad3c3cb6
',
63 'series
': 'Beyond Tech
',
64 'series_id
': 'beyond
-tech
',
65 'availability
': 'needs_auth
',
66 'chapter
': 'Job Development
',
68 'chapter_id
': '5f7c78d424330c000edf04d9
'
72 def _real_extract(self, url):
73 episode_id, course_name = self._match_valid_url(url).group('id', 'course
')
74 webpage = self._download_webpage(url, episode_id)
75 self._check_if_logged_in(webpage)
76 course = self._call_api('course
', course_name, webpage)
77 episode = self._call_api('episode
', episode_id, webpage)
79 chapter_number, chapter = next((
80 (i, topic) for i, topic in enumerate(course.get('topics
') or [], 1)
81 if traverse_obj(topic, 'id') == episode.get('topic
')), {})
85 'title
': episode.get('title
'),
86 'description
': episode.get('description
'),
87 'thumbnail
': episode.get('thumbnail
'),
89 {'url': episode[f'jwVideo{h}Embed'], 'height': h
}
90 for h
in (320, 480, 720, 1080) if episode
.get(f
'jwVideo{h}Embed')
92 'duration': int_or_none(episode
.get('length')),
93 'series': course
.get('name'),
94 'series_id': course
.get('url'),
95 'chapter': str_or_none(chapter
.get('title')),
96 'chapter_number': chapter_number
,
97 'chapter_id': str_or_none(chapter
.get('id')),
99 'en': [{'ext': 'vtt', 'data': episode['enCaptionData']}
]
100 } if episode
.get('enCaptionData') else None,
104 class ITProTVCourseIE(ITProTVBaseIE
):
105 _VALID_URL
= r
'https?://app.itpro.tv/course/(?P<id>[\w-]+)/?(?:$|[#?])'
108 'url': 'https://app.itpro.tv/course/guided-tour',
111 'description': 'md5:b175c2c3061ce35a4dd33865b2c1da4e',
112 'title': 'ITProTV 101',
117 'url': 'https://app.itpro.tv/course/beyond-tech',
120 'description': 'md5:44cd99855e7f81a15ce1269bd0621fed',
121 'title': 'Beyond Tech'
127 def _real_extract(self
, url
):
128 course_id
= self
._match
_id
(url
)
129 webpage
= self
._download
_webpage
(url
, course_id
)
130 self
._check
_if
_logged
_in
(webpage
)
131 course
= self
._call
_api
('course', course_id
, webpage
)
133 entries
= [self
.url_result(
134 urljoin(url
, f
'{course_id}/{episode["url"]}'), ITProTVIE
,
135 episode
['url'], episode
.get('title'), url_transparent
=True)
136 for episode
in course
['episodes']]
138 return self
.playlist_result(
139 entries
, course_id
, course
.get('name'), course
.get('description'))