[pluralsight] Switch to graphql (closes #16889, closes #16899)

This commit is contained in:
Sergey M․ 2018-07-04 04:48:40 +07:00
parent 5621c3222e
commit 836ef4840f
No known key found for this signature in database
GPG Key ID: 2C393E0F18A9236D

View File

@ -27,6 +27,60 @@ from ..utils import (
class PluralsightBaseIE(InfoExtractor): class PluralsightBaseIE(InfoExtractor):
_API_BASE = 'https://app.pluralsight.com' _API_BASE = 'https://app.pluralsight.com'
_GRAPHQL_EP = '%s/player/api/graphql' % _API_BASE
_GRAPHQL_HEADERS = {
'Content-Type': 'application/json;charset=UTF-8',
}
_GRAPHQL_COURSE_TMPL = '''
query BootstrapPlayer {
rpc {
bootstrapPlayer {
profile {
firstName
lastName
email
username
userHandle
authed
isAuthed
plan
}
course(courseId: "%s") {
name
title
courseHasCaptions
translationLanguages {
code
name
}
supportsWideScreenVideoFormats
timestamp
modules {
name
title
duration
formattedDuration
author
authorized
clips {
authorized
clipId
duration
formattedDuration
id
index
moduleIndex
moduleTitle
name
title
watched
}
}
}
}
}
}'''
def _download_course(self, course_id, url, display_id): def _download_course(self, course_id, url, display_id):
try: try:
return self._download_course_rpc(course_id, url, display_id) return self._download_course_rpc(course_id, url, display_id)
@ -39,20 +93,14 @@ class PluralsightBaseIE(InfoExtractor):
def _download_course_rpc(self, course_id, url, display_id): def _download_course_rpc(self, course_id, url, display_id):
response = self._download_json( response = self._download_json(
'%s/player/functions/rpc' % self._API_BASE, display_id, self._GRAPHQL_EP, display_id, data=json.dumps({
'Downloading course JSON', 'query': self._GRAPHQL_COURSE_TMPL % course_id,
data=json.dumps({ 'variables': {}
'fn': 'bootstrapPlayer', }).encode('utf-8'), headers=self._GRAPHQL_HEADERS)
'payload': {
'courseId': course_id,
},
}).encode('utf-8'),
headers={
'Content-Type': 'application/json;charset=utf-8',
'Referer': url,
})
course = try_get(response, lambda x: x['payload']['course'], dict) course = try_get(
response, lambda x: x['data']['rpc']['bootstrapPlayer']['course'],
dict)
if course: if course:
return course return course
@ -90,6 +138,28 @@ class PluralsightIE(PluralsightBaseIE):
'only_matching': True, 'only_matching': True,
}] }]
GRAPHQL_VIEWCLIP_TMPL = '''
query viewClip {
viewClip(input: {
author: "%(author)s",
clipIndex: %(clipIndex)d,
courseName: "%(courseName)s",
includeCaptions: %(includeCaptions)s,
locale: "%(locale)s",
mediaType: "%(mediaType)s",
moduleName: "%(moduleName)s",
quality: "%(quality)s"
}) {
urls {
url
cdn
rank
source
},
status
}
}'''
def _real_initialize(self): def _real_initialize(self):
self._login() self._login()
@ -277,7 +347,7 @@ class PluralsightIE(PluralsightBaseIE):
f = QUALITIES[quality].copy() f = QUALITIES[quality].copy()
clip_post = { clip_post = {
'author': author, 'author': author,
'includeCaptions': False, 'includeCaptions': 'false',
'clipIndex': int(clip_idx), 'clipIndex': int(clip_idx),
'courseName': course_name, 'courseName': course_name,
'locale': 'en', 'locale': 'en',
@ -286,11 +356,23 @@ class PluralsightIE(PluralsightBaseIE):
'quality': '%dx%d' % (f['width'], f['height']), 'quality': '%dx%d' % (f['width'], f['height']),
} }
format_id = '%s-%s' % (ext, quality) format_id = '%s-%s' % (ext, quality)
viewclip = self._download_json(
'%s/video/clips/viewclip' % self._API_BASE, display_id, try:
'Downloading %s viewclip JSON' % format_id, fatal=False, viewclip = self._download_json(
data=json.dumps(clip_post).encode('utf-8'), self._GRAPHQL_EP, display_id,
headers={'Content-Type': 'application/json;charset=utf-8'}) 'Downloading %s viewclip graphql' % format_id,
data=json.dumps({
'query': self.GRAPHQL_VIEWCLIP_TMPL % clip_post,
'variables': {}
}).encode('utf-8'),
headers=self._GRAPHQL_HEADERS)['data']['viewClip']
except ExtractorError:
# Still works but most likely will go soon
viewclip = self._download_json(
'%s/video/clips/viewclip' % self._API_BASE, display_id,
'Downloading %s viewclip JSON' % format_id, fatal=False,
data=json.dumps(clip_post).encode('utf-8'),
headers={'Content-Type': 'application/json;charset=utf-8'})
# Pluralsight tracks multiple sequential calls to ViewClip API and start # Pluralsight tracks multiple sequential calls to ViewClip API and start
# to return 429 HTTP errors after some time (see # to return 429 HTTP errors after some time (see