},
]
+ _API_BASE = 'https://api.twitter.com/1.1'
+
def _parse_media_info(self, media_info, video_id):
formats = []
for media_variant in media_info.get('variants', []):
main_script, 'bearer token')
# https://developer.twitter.com/en/docs/tweets/post-and-engage/api-reference/get-statuses-show-id
api_data = self._download_json(
- 'https://api.twitter.com/1.1/statuses/show/%s.json' % video_id,
+ '%s/statuses/show/%s.json' % (self._API_BASE, video_id),
video_id, 'Downloading API data',
headers={
'Authorization': 'Bearer ' + bearer_token,
urls.append('https://twitter.com/i/videos/' + video_id)
for u in urls:
- webpage = self._download_webpage(u, video_id)
+ webpage = self._download_webpage(
+ u, video_id, headers={'Referer': 'https://twitter.com/'})
iframe_url = self._html_search_regex(
r'<iframe[^>]+src="((?:https?:)?//(?:www\.youtube\.com/embed/[^"]+|(?:www\.)?vine\.co/v/\w+/card))"',
break
if not formats:
+ headers = {
+ 'Authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAAPYXBAAAAAAACLXUNDekMxqa8h%2F40K4moUkGsoc%3DTYfbDKbT3jJPCEVnMYqilB28NHfOPqkca3qaAxGfsyKCs0wRbw',
+ 'Referer': url,
+ }
+ ct0 = self._get_cookies(url).get('ct0')
+ if ct0:
+ headers['csrf_token'] = ct0.value
+ guest_token = self._download_json(
+ '%s/guest/activate.json' % self._API_BASE, video_id,
+ 'Downloading guest token', data=b'',
+ headers=headers)['guest_token']
+ headers['x-guest-token'] = guest_token
+ self._set_cookie('api.twitter.com', 'gt', guest_token)
config = self._download_json(
- 'https://api.twitter.com/1.1/videos/tweet/config/%s.json' % video_id,
- video_id, headers={
- 'Authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAAIK1zgAAAAAA2tUWuhGZ2JceoId5GwYWU5GspY4%3DUq7gzFoCZs1QfwGoVdvSac3IniczZEYXIcDyumCauIXpcAPorE',
- })
+ '%s/videos/tweet/config/%s.json' % (self._API_BASE, video_id),
+ video_id, headers=headers)
track = config['track']
vmap_url = track.get('vmapUrl')
if vmap_url:
'params': {
'skip_download': True, # requires ffmpeg
},
+ }, {
+ 'url': 'https://twitter.com/foobar/status/1087791357756956680',
+ 'info_dict': {
+ 'id': '1087791357756956680',
+ 'ext': 'mp4',
+ 'title': 'Twitter - A new is coming. Some of you got an opt-in to try it now. Check out the emoji button, quick keyboard shortcuts, upgraded trends, advanced search, and more. Let us know your thoughts!',
+ 'thumbnail': r're:^https?://.*\.jpg',
+ 'description': 'md5:66d493500c013e3e2d434195746a7f78',
+ 'uploader': 'Twitter',
+ 'uploader_id': 'Twitter',
+ 'duration': 61.567,
+ },
}]
def _real_extract(self, url):
mobj = re.match(self._VALID_URL, url)
- user_id = mobj.group('user_id')
twid = mobj.group('id')
webpage, urlh = self._download_webpage_handle(
if 'twitter.com/account/suspended' in urlh.geturl():
raise ExtractorError('Account suspended by Twitter.', expected=True)
- if user_id is None:
- mobj = re.match(self._VALID_URL, urlh.geturl())
+ user_id = None
+
+ redirect_mobj = re.match(self._VALID_URL, urlh.geturl())
+ if redirect_mobj:
+ user_id = redirect_mobj.group('user_id')
+
+ if not user_id:
user_id = mobj.group('user_id')
username = remove_end(self._og_search_title(webpage), ' on Twitter')