diff options
| -rw-r--r-- | youtube_dl/extractor/pluralsight.py | 122 | 
1 files changed, 102 insertions, 20 deletions
| diff --git a/youtube_dl/extractor/pluralsight.py b/youtube_dl/extractor/pluralsight.py index a207ca9cb..1257841e4 100644 --- a/youtube_dl/extractor/pluralsight.py +++ b/youtube_dl/extractor/pluralsight.py @@ -27,6 +27,60 @@ from ..utils import (  class PluralsightBaseIE(InfoExtractor):      _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):          try:              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):          response = self._download_json( -            '%s/player/functions/rpc' % self._API_BASE, display_id, -            'Downloading course JSON', -            data=json.dumps({ -                'fn': 'bootstrapPlayer', -                '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) +            self._GRAPHQL_EP, display_id, data=json.dumps({ +                'query': self._GRAPHQL_COURSE_TMPL % course_id, +                'variables': {} +            }).encode('utf-8'), headers=self._GRAPHQL_HEADERS) + +        course = try_get( +            response, lambda x: x['data']['rpc']['bootstrapPlayer']['course'], +            dict)          if course:              return course @@ -90,6 +138,28 @@ class PluralsightIE(PluralsightBaseIE):          '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):          self._login() @@ -277,7 +347,7 @@ class PluralsightIE(PluralsightBaseIE):                  f = QUALITIES[quality].copy()                  clip_post = {                      'author': author, -                    'includeCaptions': False, +                    'includeCaptions': 'false',                      'clipIndex': int(clip_idx),                      'courseName': course_name,                      'locale': 'en', @@ -286,11 +356,23 @@ class PluralsightIE(PluralsightBaseIE):                      'quality': '%dx%d' % (f['width'], f['height']),                  }                  format_id = '%s-%s' % (ext, quality) -                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'}) + +                try: +                    viewclip = self._download_json( +                        self._GRAPHQL_EP, display_id, +                        '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                  # to return 429 HTTP errors after some time (see | 
