|
@ -23,7 +23,7 @@ from ..utils import ( |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PluralsightBaseIE(InfoExtractor): |
|
|
class PluralsightBaseIE(InfoExtractor): |
|
|
_API_BASE = 'http://app.pluralsight.com' |
|
|
|
|
|
|
|
|
_API_BASE = 'https://app.pluralsight.com' |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PluralsightIE(PluralsightBaseIE): |
|
|
class PluralsightIE(PluralsightBaseIE): |
|
@ -102,7 +102,7 @@ class PluralsightIE(PluralsightBaseIE): |
|
|
'm': name, |
|
|
'm': name, |
|
|
} |
|
|
} |
|
|
captions = self._download_json( |
|
|
captions = self._download_json( |
|
|
'%s/training/Player/Captions' % self._API_BASE, video_id, |
|
|
|
|
|
|
|
|
'%s/player/retrieve-captions' % self._API_BASE, video_id, |
|
|
'Downloading captions JSON', 'Unable to download captions JSON', |
|
|
'Downloading captions JSON', 'Unable to download captions JSON', |
|
|
fatal=False, data=json.dumps(captions_post).encode('utf-8'), |
|
|
fatal=False, data=json.dumps(captions_post).encode('utf-8'), |
|
|
headers={'Content-Type': 'application/json;charset=utf-8'}) |
|
|
headers={'Content-Type': 'application/json;charset=utf-8'}) |
|
@ -147,28 +147,22 @@ class PluralsightIE(PluralsightBaseIE): |
|
|
author = qs.get('author', [None])[0] |
|
|
author = qs.get('author', [None])[0] |
|
|
name = qs.get('name', [None])[0] |
|
|
name = qs.get('name', [None])[0] |
|
|
clip_id = qs.get('clip', [None])[0] |
|
|
clip_id = qs.get('clip', [None])[0] |
|
|
course = qs.get('course', [None])[0] |
|
|
|
|
|
|
|
|
course_name = qs.get('course', [None])[0] |
|
|
|
|
|
|
|
|
if any(not f for f in (author, name, clip_id, course,)): |
|
|
|
|
|
|
|
|
if any(not f for f in (author, name, clip_id, course_name,)): |
|
|
raise ExtractorError('Invalid URL', expected=True) |
|
|
raise ExtractorError('Invalid URL', expected=True) |
|
|
|
|
|
|
|
|
display_id = '%s-%s' % (name, clip_id) |
|
|
display_id = '%s-%s' % (name, clip_id) |
|
|
|
|
|
|
|
|
webpage = self._download_webpage(url, display_id) |
|
|
|
|
|
|
|
|
parsed_url = compat_urlparse.urlparse(url) |
|
|
|
|
|
|
|
|
modules = self._search_regex( |
|
|
|
|
|
r'moduleCollection\s*:\s*new\s+ModuleCollection\((\[.+?\])\s*,\s*\$rootScope\)', |
|
|
|
|
|
webpage, 'modules', default=None) |
|
|
|
|
|
|
|
|
payload_url = compat_urlparse.urlunparse(parsed_url._replace( |
|
|
|
|
|
netloc='app.pluralsight.com', path='player/api/v1/payload')) |
|
|
|
|
|
|
|
|
if modules: |
|
|
|
|
|
collection = self._parse_json(modules, display_id) |
|
|
|
|
|
else: |
|
|
|
|
|
# Webpage may be served in different layout (see |
|
|
|
|
|
# https://github.com/rg3/youtube-dl/issues/7607) |
|
|
|
|
|
collection = self._parse_json( |
|
|
|
|
|
self._search_regex( |
|
|
|
|
|
r'var\s+initialState\s*=\s*({.+?});\n', webpage, 'initial state'), |
|
|
|
|
|
display_id)['course']['modules'] |
|
|
|
|
|
|
|
|
course = self._download_json( |
|
|
|
|
|
payload_url, display_id, headers={'Referer': url})['payload']['course'] |
|
|
|
|
|
|
|
|
|
|
|
collection = course['modules'] |
|
|
|
|
|
|
|
|
module, clip = None, None |
|
|
module, clip = None, None |
|
|
|
|
|
|
|
@ -209,8 +203,7 @@ class PluralsightIE(PluralsightBaseIE): |
|
|
|
|
|
|
|
|
# Some courses also offer widescreen resolution for high quality (see |
|
|
# Some courses also offer widescreen resolution for high quality (see |
|
|
# https://github.com/rg3/youtube-dl/issues/7766) |
|
|
# https://github.com/rg3/youtube-dl/issues/7766) |
|
|
widescreen = True if re.search( |
|
|
|
|
|
r'courseSupportsWidescreenVideoFormats\s*:\s*true', webpage) else False |
|
|
|
|
|
|
|
|
widescreen = course.get('supportsWideScreenVideoFormats') is True |
|
|
best_quality = 'high-widescreen' if widescreen else 'high' |
|
|
best_quality = 'high-widescreen' if widescreen else 'high' |
|
|
if widescreen: |
|
|
if widescreen: |
|
|
for allowed_quality in ALLOWED_QUALITIES: |
|
|
for allowed_quality in ALLOWED_QUALITIES: |
|
@ -239,18 +232,18 @@ class PluralsightIE(PluralsightBaseIE): |
|
|
for quality in qualities_: |
|
|
for quality in qualities_: |
|
|
f = QUALITIES[quality].copy() |
|
|
f = QUALITIES[quality].copy() |
|
|
clip_post = { |
|
|
clip_post = { |
|
|
'a': author, |
|
|
|
|
|
'cap': 'false', |
|
|
|
|
|
'cn': clip_id, |
|
|
|
|
|
'course': course, |
|
|
|
|
|
'lc': 'en', |
|
|
|
|
|
'm': name, |
|
|
|
|
|
'mt': ext, |
|
|
|
|
|
'q': '%dx%d' % (f['width'], f['height']), |
|
|
|
|
|
|
|
|
'author': author, |
|
|
|
|
|
'includeCaptions': False, |
|
|
|
|
|
'clipIndex': int(clip_id), |
|
|
|
|
|
'courseName': course_name, |
|
|
|
|
|
'locale': 'en', |
|
|
|
|
|
'moduleName': name, |
|
|
|
|
|
'mediaType': ext, |
|
|
|
|
|
'quality': '%dx%d' % (f['width'], f['height']), |
|
|
} |
|
|
} |
|
|
format_id = '%s-%s' % (ext, quality) |
|
|
format_id = '%s-%s' % (ext, quality) |
|
|
clip_url = self._download_webpage( |
|
|
clip_url = self._download_webpage( |
|
|
'%s/training/Player/ViewClip' % self._API_BASE, display_id, |
|
|
|
|
|
|
|
|
'%s/video/clips/viewclip' % self._API_BASE, display_id, |
|
|
'Downloading %s URL' % format_id, fatal=False, |
|
|
'Downloading %s URL' % format_id, fatal=False, |
|
|
data=json.dumps(clip_post).encode('utf-8'), |
|
|
data=json.dumps(clip_post).encode('utf-8'), |
|
|
headers={'Content-Type': 'application/json;charset=utf-8'}) |
|
|
headers={'Content-Type': 'application/json;charset=utf-8'}) |
|
|