[twitch] fix clip extraction(closes #23375)
This commit is contained in:
		
							parent
							
								
									cf80ff186e
								
							
						
					
					
						commit
						232ed8e6e0
					
				
					 1 changed files with 63 additions and 47 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue