]>
Commit | Line | Data |
---|---|---|
c56ad5c9 | 1 | import json |
74539995 S |
2 | |
3 | from .common import InfoExtractor | |
3d2623a8 | 4 | from ..networking.exceptions import HTTPError |
74539995 | 5 | from ..utils import ( |
74539995 | 6 | ExtractorError, |
e897bd82 | 7 | clean_html, |
25d71fb0 RA |
8 | # remove_end, |
9 | str_or_none, | |
74539995 S |
10 | strip_or_none, |
11 | unified_timestamp, | |
74539995 S |
12 | ) |
13 | ||
14 | ||
15 | class PacktPubBaseIE(InfoExtractor): | |
25d71fb0 RA |
16 | # _PACKT_BASE = 'https://www.packtpub.com' |
17 | _STATIC_PRODUCTS_BASE = 'https://static.packt-cdn.com/products/' | |
74539995 S |
18 | |
19 | ||
20 | class PacktPubIE(PacktPubBaseIE): | |
c9b0564a | 21 | _VALID_URL = r'https?://(?:(?:www\.)?packtpub\.com/mapt|subscription\.packtpub\.com)/video/[^/]+/(?P<course_id>\d+)/(?P<chapter_id>[^/]+)/(?P<id>[^/]+)(?:/(?P<display_id>[^/?&#]+))?' |
74539995 | 22 | |
751e0515 | 23 | _TESTS = [{ |
74539995 S |
24 | 'url': 'https://www.packtpub.com/mapt/video/web-development/9781787122215/20528/20530/Project+Intro', |
25 | 'md5': '1e74bd6cfd45d7d07666f4684ef58f70', | |
26 | 'info_dict': { | |
27 | 'id': '20530', | |
28 | 'ext': 'mp4', | |
29 | 'title': 'Project Intro', | |
30 | 'thumbnail': r're:(?i)^https?://.*\.jpg', | |
31 | 'timestamp': 1490918400, | |
32 | 'upload_date': '20170331', | |
33 | }, | |
751e0515 S |
34 | }, { |
35 | 'url': 'https://subscription.packtpub.com/video/web_development/9781787122215/20528/20530/project-intro', | |
36 | 'only_matching': True, | |
c9b0564a RA |
37 | }, { |
38 | 'url': 'https://subscription.packtpub.com/video/programming/9781838988906/p1/video1_1/business-card-project', | |
39 | 'only_matching': True, | |
751e0515 | 40 | }] |
5d0968f0 RA |
41 | _NETRC_MACHINE = 'packtpub' |
42 | _TOKEN = None | |
43 | ||
52efa4b3 | 44 | def _perform_login(self, username, password): |
5d0968f0 RA |
45 | try: |
46 | self._TOKEN = self._download_json( | |
25d71fb0 | 47 | 'https://services.packtpub.com/auth-v1/users/tokens', None, |
c56ad5c9 | 48 | 'Downloading Authorization Token', data=json.dumps({ |
25d71fb0 | 49 | 'username': username, |
c56ad5c9 RA |
50 | 'password': password, |
51 | }).encode())['data']['access'] | |
5d0968f0 | 52 | except ExtractorError as e: |
3d2623a8 | 53 | if isinstance(e.cause, HTTPError) and e.cause.status in (400, 401, 404): |
54 | message = self._parse_json(e.cause.response.read().decode(), None)['message'] | |
5d0968f0 RA |
55 | raise ExtractorError(message, expected=True) |
56 | raise | |
74539995 | 57 | |
74539995 | 58 | def _real_extract(self, url): |
5ad28e7f | 59 | course_id, chapter_id, video_id, display_id = self._match_valid_url(url).groups() |
74539995 | 60 | |
5d0968f0 RA |
61 | headers = {} |
62 | if self._TOKEN: | |
c56ad5c9 | 63 | headers['Authorization'] = 'Bearer ' + self._TOKEN |
25d71fb0 RA |
64 | try: |
65 | video_url = self._download_json( | |
add96eb9 | 66 | f'https://services.packtpub.com/products-v1/products/{course_id}/{chapter_id}/{video_id}', video_id, |
25d71fb0 RA |
67 | 'Downloading JSON video', headers=headers)['data'] |
68 | except ExtractorError as e: | |
3d2623a8 | 69 | if isinstance(e.cause, HTTPError) and e.cause.status == 400: |
25d71fb0 RA |
70 | self.raise_login_required('This video is locked') |
71 | raise | |
74539995 | 72 | |
25d71fb0 RA |
73 | # TODO: find a better way to avoid duplicating course requests |
74 | # metadata = self._download_json( | |
75 | # '%s/products/%s/chapters/%s/sections/%s/metadata' | |
76 | # % (self._MAPT_REST, course_id, chapter_id, video_id), | |
77 | # video_id)['data'] | |
74539995 | 78 | |
25d71fb0 RA |
79 | # title = metadata['pageTitle'] |
80 | # course_title = metadata.get('title') | |
81 | # if course_title: | |
82 | # title = remove_end(title, ' - %s' % course_title) | |
83 | # timestamp = unified_timestamp(metadata.get('publicationDate')) | |
84 | # thumbnail = urljoin(self._PACKT_BASE, metadata.get('filepath')) | |
74539995 S |
85 | |
86 | return { | |
87 | 'id': video_id, | |
88 | 'url': video_url, | |
25d71fb0 RA |
89 | 'title': display_id or video_id, # title, |
90 | # 'thumbnail': thumbnail, | |
91 | # 'timestamp': timestamp, | |
74539995 S |
92 | } |
93 | ||
94 | ||
95 | class PacktPubCourseIE(PacktPubBaseIE): | |
751e0515 S |
96 | _VALID_URL = r'(?P<url>https?://(?:(?:www\.)?packtpub\.com/mapt|subscription\.packtpub\.com)/video/[^/]+/(?P<id>\d+))' |
97 | _TESTS = [{ | |
74539995 S |
98 | 'url': 'https://www.packtpub.com/mapt/video/web-development/9781787122215', |
99 | 'info_dict': { | |
100 | 'id': '9781787122215', | |
101 | 'title': 'Learn Nodejs by building 12 projects [Video]', | |
25d71fb0 | 102 | 'description': 'md5:489da8d953f416e51927b60a1c7db0aa', |
74539995 S |
103 | }, |
104 | 'playlist_count': 90, | |
751e0515 S |
105 | }, { |
106 | 'url': 'https://subscription.packtpub.com/video/web_development/9781787122215', | |
107 | 'only_matching': True, | |
108 | }] | |
74539995 S |
109 | |
110 | @classmethod | |
111 | def suitable(cls, url): | |
add96eb9 | 112 | return False if PacktPubIE.suitable(url) else super().suitable(url) |
74539995 S |
113 | |
114 | def _real_extract(self, url): | |
5ad28e7f | 115 | mobj = self._match_valid_url(url) |
74539995 S |
116 | url, course_id = mobj.group('url', 'id') |
117 | ||
118 | course = self._download_json( | |
add96eb9 | 119 | self._STATIC_PRODUCTS_BASE + f'{course_id}/toc', course_id) |
25d71fb0 | 120 | metadata = self._download_json( |
add96eb9 | 121 | self._STATIC_PRODUCTS_BASE + f'{course_id}/summary', |
25d71fb0 | 122 | course_id, fatal=False) or {} |
74539995 S |
123 | |
124 | entries = [] | |
25d71fb0 RA |
125 | for chapter_num, chapter in enumerate(course['chapters'], 1): |
126 | chapter_id = str_or_none(chapter.get('id')) | |
127 | sections = chapter.get('sections') | |
128 | if not chapter_id or not isinstance(sections, list): | |
74539995 S |
129 | continue |
130 | chapter_info = { | |
131 | 'chapter': chapter.get('title'), | |
132 | 'chapter_number': chapter_num, | |
25d71fb0 | 133 | 'chapter_id': chapter_id, |
74539995 | 134 | } |
25d71fb0 RA |
135 | for section in sections: |
136 | section_id = str_or_none(section.get('id')) | |
137 | if not section_id or section.get('contentType') != 'video': | |
74539995 S |
138 | continue |
139 | entry = { | |
140 | '_type': 'url_transparent', | |
25d71fb0 | 141 | 'url': '/'.join([url, chapter_id, section_id]), |
74539995 S |
142 | 'title': strip_or_none(section.get('title')), |
143 | 'description': clean_html(section.get('summary')), | |
25d71fb0 RA |
144 | 'thumbnail': metadata.get('coverImage'), |
145 | 'timestamp': unified_timestamp(metadata.get('publicationDate')), | |
74539995 S |
146 | 'ie_key': PacktPubIE.ie_key(), |
147 | } | |
148 | entry.update(chapter_info) | |
149 | entries.append(entry) | |
150 | ||
25d71fb0 RA |
151 | return self.playlist_result( |
152 | entries, course_id, metadata.get('title'), | |
153 | clean_html(metadata.get('about'))) |