mirror of
https://github.com/ytdl-org/youtube-dl.git
synced 2024-11-25 03:32:05 +00:00
parent
5621c3222e
commit
836ef4840f
1 changed files with 101 additions and 19 deletions
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue