mirror of
				https://github.com/yt-dlp/yt-dlp.git
				synced 2025-10-31 14:45:14 +00:00 
			
		
		
		
	[ie/vimeo] Fix password-protected video extraction (#10341)
Closes #6603 Authored by: bashonly
This commit is contained in:
		| @@ -1,6 +1,7 @@ | ||||
| import base64 | ||||
| import functools | ||||
| import itertools | ||||
| import json | ||||
| import re | ||||
| import urllib.parse | ||||
| 
 | ||||
| @@ -14,6 +15,7 @@ from ..utils import ( | ||||
|     determine_ext, | ||||
|     get_element_by_class, | ||||
|     int_or_none, | ||||
|     join_nonempty, | ||||
|     js_to_json, | ||||
|     merge_dicts, | ||||
|     parse_filesize, | ||||
| @@ -84,29 +86,23 @@ class VimeoBaseInfoExtractor(InfoExtractor): | ||||
|                 expected=True) | ||||
|         return password | ||||
| 
 | ||||
|     def _verify_video_password(self, url, video_id, password, token, vuid): | ||||
|         if url.startswith('http://'): | ||||
|             # vimeo only supports https now, but the user can give an http url | ||||
|             url = url.replace('http://', 'https://') | ||||
|         self._set_vimeo_cookie('vuid', vuid) | ||||
|         return self._download_webpage( | ||||
|             url + '/password', video_id, 'Verifying the password', | ||||
|             'Wrong password', data=urlencode_postdata({ | ||||
|                 'password': password, | ||||
|                 'token': token, | ||||
|             }), headers={ | ||||
|                 'Content-Type': 'application/x-www-form-urlencoded', | ||||
|                 'Referer': url, | ||||
|             }) | ||||
| 
 | ||||
|     def _extract_xsrft_and_vuid(self, webpage): | ||||
|         xsrft = self._search_regex( | ||||
|             r'(?:(?P<q1>["\'])xsrft(?P=q1)\s*:|xsrft\s*[=:])\s*(?P<q>["\'])(?P<xsrft>.+?)(?P=q)', | ||||
|             webpage, 'login token', group='xsrft') | ||||
|         vuid = self._search_regex( | ||||
|             r'["\']vuid["\']\s*:\s*(["\'])(?P<vuid>.+?)\1', | ||||
|             webpage, 'vuid', group='vuid') | ||||
|         return xsrft, vuid | ||||
|     def _verify_video_password(self, video_id, password, token): | ||||
|         url = f'https://vimeo.com/{video_id}' | ||||
|         try: | ||||
|             return self._download_webpage( | ||||
|                 f'{url}/password', video_id, | ||||
|                 'Submitting video password', data=json.dumps({ | ||||
|                     'password': password, | ||||
|                     'token': token, | ||||
|                 }, separators=(',', ':')).encode(), headers={ | ||||
|                     'Accept': '*/*', | ||||
|                     'Content-Type': 'application/json', | ||||
|                     'Referer': url, | ||||
|                 }, impersonate=True) | ||||
|         except ExtractorError as error: | ||||
|             if isinstance(error.cause, HTTPError) and error.cause.status == 418: | ||||
|                 raise ExtractorError('Wrong password', expected=True) | ||||
|             raise | ||||
| 
 | ||||
|     def _extract_vimeo_config(self, webpage, video_id, *args, **kwargs): | ||||
|         vimeo_config = self._search_regex( | ||||
| @@ -745,21 +741,34 @@ class VimeoIE(VimeoBaseInfoExtractor): | ||||
|             raise ExtractorError('Wrong video password', expected=True) | ||||
|         return checked | ||||
| 
 | ||||
|     def _extract_from_api(self, video_id, unlisted_hash=None): | ||||
|         token = self._download_json( | ||||
|             'https://vimeo.com/_rv/jwt', video_id, headers={ | ||||
|                 'X-Requested-With': 'XMLHttpRequest', | ||||
|             })['token'] | ||||
|         api_url = 'https://api.vimeo.com/videos/' + video_id | ||||
|         if unlisted_hash: | ||||
|             api_url += ':' + unlisted_hash | ||||
|         video = self._download_json( | ||||
|             api_url, video_id, headers={ | ||||
|                 'Authorization': 'jwt ' + token, | ||||
|     def _call_videos_api(self, video_id, jwt_token, unlisted_hash=None): | ||||
|         return self._download_json( | ||||
|             join_nonempty(f'https://api.vimeo.com/videos/{video_id}', unlisted_hash, delim=':'), | ||||
|             video_id, 'Downloading API JSON', headers={ | ||||
|                 'Authorization': f'jwt {jwt_token}', | ||||
|                 'Accept': 'application/json', | ||||
|             }, query={ | ||||
|                 'fields': 'config_url,created_time,description,license,metadata.connections.comments.total,metadata.connections.likes.total,release_time,stats.plays', | ||||
|             }) | ||||
| 
 | ||||
|     def _extract_from_api(self, video_id, unlisted_hash=None): | ||||
|         viewer = self._download_json( | ||||
|             'https://vimeo.com/_next/viewer', video_id, 'Downloading viewer info') | ||||
| 
 | ||||
|         for retry in (False, True): | ||||
|             try: | ||||
|                 video = self._call_videos_api(video_id, viewer['jwt'], unlisted_hash) | ||||
|             except ExtractorError as e: | ||||
|                 if (not retry and isinstance(e.cause, HTTPError) and e.cause.status == 400 | ||||
|                     and 'password' in traverse_obj( | ||||
|                         e.cause.response.read(), | ||||
|                         ({bytes.decode}, {json.loads}, 'invalid_parameters', ..., 'field'), | ||||
|                 )): | ||||
|                     self._verify_video_password( | ||||
|                         video_id, self._get_video_password(), viewer['xsrft']) | ||||
|                     continue | ||||
|                 raise | ||||
| 
 | ||||
|         info = self._parse_config(self._download_json( | ||||
|             video['config_url'], video_id), video_id) | ||||
|         get_timestamp = lambda x: parse_iso8601(video.get(x + '_time')) | ||||
| @@ -865,12 +874,6 @@ class VimeoIE(VimeoBaseInfoExtractor): | ||||
|                     redirect_url, video_id, headers) | ||||
|             return self._parse_config(config, video_id) | ||||
| 
 | ||||
|         if re.search(r'<form[^>]+?id="pw_form"', webpage): | ||||
|             video_password = self._get_video_password() | ||||
|             token, vuid = self._extract_xsrft_and_vuid(webpage) | ||||
|             webpage = self._verify_video_password( | ||||
|                 redirect_url, video_id, video_password, token, vuid) | ||||
| 
 | ||||
|         vimeo_config = self._extract_vimeo_config(webpage, video_id, default=None) | ||||
|         if vimeo_config: | ||||
|             seed_status = vimeo_config.get('seed_status') or {} | ||||
| @@ -1290,9 +1293,7 @@ class VimeoReviewIE(VimeoBaseInfoExtractor): | ||||
|             video_password = self._get_video_password() | ||||
|             viewer = self._download_json( | ||||
|                 'https://vimeo.com/_rv/viewer', video_id) | ||||
|             webpage = self._verify_video_password( | ||||
|                 'https://vimeo.com/' + video_id, video_id, | ||||
|                 video_password, viewer['xsrft'], viewer['vuid']) | ||||
|             webpage = self._verify_video_password(video_id, video_password, viewer['xsrft']) | ||||
|             clip_page_config = self._parse_json(self._search_regex( | ||||
|                 r'window\.vimeo\.clip_page_config\s*=\s*({.+?});', | ||||
|                 webpage, 'clip page config'), video_id) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 bashonly
					bashonly