diff options
| -rw-r--r-- | youtube_dl/extractor/twitch.py | 110 | 
1 files changed, 63 insertions, 47 deletions
| diff --git a/youtube_dl/extractor/twitch.py b/youtube_dl/extractor/twitch.py index 1f3df3112..a8c2502af 100644 --- a/youtube_dl/extractor/twitch.py +++ b/youtube_dl/extractor/twitch.py @@ -17,12 +17,10 @@ from ..compat import (  from ..utils import (      clean_html,      ExtractorError, -    float_or_none,      int_or_none,      orderedSet,      parse_duration,      parse_iso8601, -    qualities,      try_get,      unified_timestamp,      update_url_query, @@ -676,63 +674,81 @@ class TwitchClipsIE(TwitchBaseIE):      def _real_extract(self, url):          video_id = self._match_id(url) -        status = self._download_json( -            'https://clips.twitch.tv/api/v2/clips/%s/status' % video_id, -            video_id) +        clip = self._download_json( +            'https://gql.twitch.tv/gql', video_id, data=json.dumps({ +                'query': '''{ +  clip(slug: "%s") { +    broadcaster { +      displayName +    } +    createdAt +    curator { +      displayName +      id +    } +    durationSeconds +    id +    tiny: thumbnailURL(width: 86, height: 45) +    small: thumbnailURL(width: 260, height: 147) +    medium: thumbnailURL(width: 480, height: 272) +    title +    videoQualities { +      frameRate +      quality +      sourceURL +    } +    viewCount +  } +}''' % video_id, +            }).encode(), headers={ +                'Client-ID': self._CLIENT_ID, +            })['data']['clip'] + +        if not clip: +            raise ExtractorError( +                'This clip is no longer available', expected=True)          formats = [] - -        for option in status['quality_options']: +        for option in clip.get('videoQualities', []):              if not isinstance(option, dict):                  continue -            source = url_or_none(option.get('source')) +            source = url_or_none(option.get('sourceURL'))              if not source:                  continue              formats.append({                  'url': source,                  'format_id': option.get('quality'),                  'height': int_or_none(option.get('quality')), -                'fps': int_or_none(option.get('frame_rate')), +                'fps': int_or_none(option.get('frameRate')),              }) -          self._sort_formats(formats) -        info = { +        thumbnails = [] +        for thumbnail_id in ('tiny', 'small', 'medium'): +            thumbnail_url = clip.get(thumbnail_id) +            if not thumbnail_url: +                continue +            thumb = { +                'id': thumbnail_id, +                'url': thumbnail_url, +            } +            mobj = re.search(r'-(\d+)x(\d+)\.', thumbnail_url) +            if mobj: +                thumb.update({ +                    'height': int(mobj.group(2)), +                    'width': int(mobj.group(1)), +                }) +            thumbnails.append(thumb) + +        return { +            'id': clip.get('id') or video_id, +            'title': clip.get('title') or video_id,              'formats': formats, +            'duration': int_or_none(clip.get('durationSeconds')), +            'views': int_or_none(clip.get('viewCount')), +            'timestamp': unified_timestamp(clip.get('createdAt')), +            'thumbnails': thumbnails, +            'creator': try_get(clip, lambda x: x['broadcaster']['displayName'], compat_str), +            'uploader': try_get(clip, lambda x: x['curator']['displayName'], compat_str), +            'uploader_id': try_get(clip, lambda x: x['curator']['id'], compat_str),          } - -        clip = self._call_api( -            'kraken/clips/%s' % video_id, video_id, fatal=False, headers={ -                'Accept': 'application/vnd.twitchtv.v5+json', -            }) - -        if clip: -            quality_key = qualities(('tiny', 'small', 'medium')) -            thumbnails = [] -            thumbnails_dict = clip.get('thumbnails') -            if isinstance(thumbnails_dict, dict): -                for thumbnail_id, thumbnail_url in thumbnails_dict.items(): -                    thumbnails.append({ -                        'id': thumbnail_id, -                        'url': thumbnail_url, -                        'preference': quality_key(thumbnail_id), -                    }) - -            info.update({ -                'id': clip.get('tracking_id') or video_id, -                'title': clip.get('title') or video_id, -                'duration': float_or_none(clip.get('duration')), -                'views': int_or_none(clip.get('views')), -                'timestamp': unified_timestamp(clip.get('created_at')), -                'thumbnails': thumbnails, -                'creator': try_get(clip, lambda x: x['broadcaster']['display_name'], compat_str), -                'uploader': try_get(clip, lambda x: x['curator']['display_name'], compat_str), -                'uploader_id': try_get(clip, lambda x: x['curator']['id'], compat_str), -            }) -        else: -            info.update({ -                'title': video_id, -                'id': video_id, -            }) - -        return info | 
