[adobepass] add specific options for adobe pass authentication
- add --ap-username and --ap-password option to specify TV provider username and password in the cmd line - add --ap-retries option to limit the number of retries - add --list-ap-msi-ids to list the supported TV Providers
This commit is contained in:
		
							parent
							
								
									8414c2da31
								
							
						
					
					
						commit
						1b6712ab23
					
				| @ -131,7 +131,9 @@ class YoutubeDL(object): | |||||||
|     username:          Username for authentication purposes. |     username:          Username for authentication purposes. | ||||||
|     password:          Password for authentication purposes. |     password:          Password for authentication purposes. | ||||||
|     videopassword:     Password for accessing a video. |     videopassword:     Password for accessing a video. | ||||||
|     ap_mso_id          Adobe Pass Multiple-system operator Identifier. |     ap_mso_id:         Adobe Pass Multiple-system operator Identifier. | ||||||
|  |     ap_username:       TV Provider username for authentication purposes. | ||||||
|  |     ap_password:       TV Provider password for authentication purposes. | ||||||
|     usenetrc:          Use netrc for authentication instead. |     usenetrc:          Use netrc for authentication instead. | ||||||
|     verbose:           Print additional info to stdout. |     verbose:           Print additional info to stdout. | ||||||
|     quiet:             Do not print messages to stdout. |     quiet:             Do not print messages to stdout. | ||||||
|  | |||||||
| @ -34,12 +34,14 @@ from .utils import ( | |||||||
|     setproctitle, |     setproctitle, | ||||||
|     std_headers, |     std_headers, | ||||||
|     write_string, |     write_string, | ||||||
|  |     render_table, | ||||||
| ) | ) | ||||||
| from .update import update_self | from .update import update_self | ||||||
| from .downloader import ( | from .downloader import ( | ||||||
|     FileDownloader, |     FileDownloader, | ||||||
| ) | ) | ||||||
| from .extractor import gen_extractors, list_extractors | from .extractor import gen_extractors, list_extractors | ||||||
|  | from .extractor.adobepass import MSO_INFO | ||||||
| from .YoutubeDL import YoutubeDL | from .YoutubeDL import YoutubeDL | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -118,18 +120,26 @@ def _real_main(argv=None): | |||||||
|                 desc += ' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES)) |                 desc += ' (Example: "%s%s:%s" )' % (ie.SEARCH_KEY, random.choice(_COUNTS), random.choice(_SEARCHES)) | ||||||
|             write_string(desc + '\n', out=sys.stdout) |             write_string(desc + '\n', out=sys.stdout) | ||||||
|         sys.exit(0) |         sys.exit(0) | ||||||
|  |     if opts.list_ap_mso_ids: | ||||||
|  |         table = [[mso_id, mso_info['name']] for mso_id, mso_info in MSO_INFO.items()] | ||||||
|  |         write_string('Supported TV Providers:\n' + render_table(['mso id', 'mso name'], table) + '\n', out=sys.stdout) | ||||||
|  |         sys.exit(0) | ||||||
| 
 | 
 | ||||||
|     # Conflicting, missing and erroneous options |     # Conflicting, missing and erroneous options | ||||||
|     if opts.usenetrc and (opts.username is not None or opts.password is not None): |     if opts.usenetrc and (opts.username is not None or opts.password is not None): | ||||||
|         parser.error('using .netrc conflicts with giving username/password') |         parser.error('using .netrc conflicts with giving username/password') | ||||||
|     if opts.password is not None and opts.username is None: |     if opts.password is not None and opts.username is None: | ||||||
|         parser.error('account username missing\n') |         parser.error('account username missing\n') | ||||||
|  |     if opts.ap_password is not None and opts.ap_username is None: | ||||||
|  |         parser.error('TV Provider account username missing\n') | ||||||
|     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid): |     if opts.outtmpl is not None and (opts.usetitle or opts.autonumber or opts.useid): | ||||||
|         parser.error('using output template conflicts with using title, video ID or auto number') |         parser.error('using output template conflicts with using title, video ID or auto number') | ||||||
|     if opts.usetitle and opts.useid: |     if opts.usetitle and opts.useid: | ||||||
|         parser.error('using title conflicts with using video ID') |         parser.error('using title conflicts with using video ID') | ||||||
|     if opts.username is not None and opts.password is None: |     if opts.username is not None and opts.password is None: | ||||||
|         opts.password = compat_getpass('Type account password and press [Return]: ') |         opts.password = compat_getpass('Type account password and press [Return]: ') | ||||||
|  |     if opts.ap_username is not None and opts.ap_password is None: | ||||||
|  |         opts.ap_password = compat_getpass('Type TV provider account password and press [Return]: ') | ||||||
|     if opts.ratelimit is not None: |     if opts.ratelimit is not None: | ||||||
|         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit) |         numeric_limit = FileDownloader.parse_bytes(opts.ratelimit) | ||||||
|         if numeric_limit is None: |         if numeric_limit is None: | ||||||
| @ -169,6 +179,8 @@ def _real_main(argv=None): | |||||||
|         opts.retries = parse_retries(opts.retries) |         opts.retries = parse_retries(opts.retries) | ||||||
|     if opts.fragment_retries is not None: |     if opts.fragment_retries is not None: | ||||||
|         opts.fragment_retries = parse_retries(opts.fragment_retries) |         opts.fragment_retries = parse_retries(opts.fragment_retries) | ||||||
|  |     if opts.ap_retries is not None: | ||||||
|  |         opts.ap_retries = parse_retries(opts.ap_retries) | ||||||
|     if opts.buffersize is not None: |     if opts.buffersize is not None: | ||||||
|         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize) |         numeric_buffersize = FileDownloader.parse_bytes(opts.buffersize) | ||||||
|         if numeric_buffersize is None: |         if numeric_buffersize is None: | ||||||
| @ -294,6 +306,9 @@ def _real_main(argv=None): | |||||||
|         'twofactor': opts.twofactor, |         'twofactor': opts.twofactor, | ||||||
|         'videopassword': opts.videopassword, |         'videopassword': opts.videopassword, | ||||||
|         'ap_mso_id': opts.ap_mso_id, |         'ap_mso_id': opts.ap_mso_id, | ||||||
|  |         'ap_username': opts.ap_username, | ||||||
|  |         'ap_password': opts.ap_password, | ||||||
|  |         'ap_retries': opts.ap_retries, | ||||||
|         'quiet': (opts.quiet or any_getting or any_printing), |         'quiet': (opts.quiet or any_getting or any_printing), | ||||||
|         'no_warnings': opts.no_warnings, |         'no_warnings': opts.no_warnings, | ||||||
|         'forceurl': opts.geturl, |         'forceurl': opts.geturl, | ||||||
|  | |||||||
| @ -15,6 +15,20 @@ from ..utils import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | MSO_INFO = { | ||||||
|  |     'DTV': { | ||||||
|  |         'name': 'DirecTV', | ||||||
|  |         'username_field': 'username', | ||||||
|  |         'password_field': 'password', | ||||||
|  |     }, | ||||||
|  |     'Rogers': { | ||||||
|  |         'name': 'Rogers Cable', | ||||||
|  |         'username_field': 'UserName', | ||||||
|  |         'password_field': 'UserPassword', | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| class AdobePassIE(InfoExtractor): | class AdobePassIE(InfoExtractor): | ||||||
|     _SERVICE_PROVIDER_TEMPLATE = 'https://sp.auth.adobe.com/adobe-services/%s' |     _SERVICE_PROVIDER_TEMPLATE = 'https://sp.auth.adobe.com/adobe-services/%s' | ||||||
|     _USER_AGENT = 'Mozilla/5.0 (X11; Linux i686; rv:47.0) Gecko/20100101 Firefox/47.0' |     _USER_AGENT = 'Mozilla/5.0 (X11; Linux i686; rv:47.0) Gecko/20100101 Firefox/47.0' | ||||||
| @ -43,6 +57,18 @@ class AdobePassIE(InfoExtractor): | |||||||
|             token_expires = unified_timestamp(re.sub(r'[_ ]GMT', '', xml_text(token, date_ele))) |             token_expires = unified_timestamp(re.sub(r'[_ ]GMT', '', xml_text(token, date_ele))) | ||||||
|             return token_expires and token_expires <= int(time.time()) |             return token_expires and token_expires <= int(time.time()) | ||||||
| 
 | 
 | ||||||
|  |         def post_form(form_page_res, note, data={}): | ||||||
|  |             form_page, urlh = form_page_res | ||||||
|  |             post_url = self._html_search_regex(r'<form[^>]+action=(["\'])(?P<url>.+?)\1', form_page, 'post url', group='url') | ||||||
|  |             if not re.match(r'https?://', post_url): | ||||||
|  |                 post_url = compat_urlparse.urljoin(urlh.geturl(), post_url) | ||||||
|  |             form_data = self._hidden_inputs(form_page) | ||||||
|  |             form_data.update(data) | ||||||
|  |             return self._download_webpage_handle( | ||||||
|  |                 post_url, video_id, note, data=urlencode_postdata(form_data), headers={ | ||||||
|  |                     'Content-Type': 'application/x-www-form-urlencoded', | ||||||
|  |                 }) | ||||||
|  | 
 | ||||||
|         def raise_mvpd_required(): |         def raise_mvpd_required(): | ||||||
|             raise ExtractorError( |             raise ExtractorError( | ||||||
|                 'This video is only available for users of participating TV providers. ' |                 'This video is only available for users of participating TV providers. ' | ||||||
| @ -57,6 +83,9 @@ class AdobePassIE(InfoExtractor): | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         guid = xml_text(resource, 'guid') |         guid = xml_text(resource, 'guid') | ||||||
|  |         retries = self._downloader.params.get('ap_retries', 3) | ||||||
|  |         count = 0 | ||||||
|  |         while count < retries: | ||||||
|             requestor_info = self._downloader.cache.load('mvpd', requestor_id) or {} |             requestor_info = self._downloader.cache.load('mvpd', requestor_id) or {} | ||||||
|             authn_token = requestor_info.get('authn_token') |             authn_token = requestor_info.get('authn_token') | ||||||
|             if authn_token and is_expired(authn_token, 'simpleTokenExpires'): |             if authn_token and is_expired(authn_token, 'simpleTokenExpires'): | ||||||
| @ -66,21 +95,13 @@ class AdobePassIE(InfoExtractor): | |||||||
|                 mso_id = self._downloader.params.get('ap_mso_id') |                 mso_id = self._downloader.params.get('ap_mso_id') | ||||||
|                 if not mso_id: |                 if not mso_id: | ||||||
|                     raise_mvpd_required() |                     raise_mvpd_required() | ||||||
|             username, password = self._get_netrc_login_info(mso_id) |                 if mso_id not in MSO_INFO: | ||||||
|  |                     raise ExtractorError( | ||||||
|  |                         'Unsupported TV Provider, use --list-ap-mso-ids to get a list of supported TV Providers' % mso_id, expected=True) | ||||||
|  |                 username, password = self._get_login_info('ap_username', 'ap_password', mso_id) | ||||||
|                 if not username or not password: |                 if not username or not password: | ||||||
|                 return raise_mvpd_required() |                     raise_mvpd_required() | ||||||
| 
 |                 mso_info = MSO_INFO[mso_id] | ||||||
|             def post_form(form_page_res, note, data={}): |  | ||||||
|                 form_page, urlh = form_page_res |  | ||||||
|                 post_url = self._html_search_regex(r'<form[^>]+action=(["\'])(?P<url>.+?)\1', form_page, 'post url', group='url') |  | ||||||
|                 if not re.match(r'https?://', post_url): |  | ||||||
|                     post_url = compat_urlparse.urljoin(urlh.geturl(), post_url) |  | ||||||
|                 form_data = self._hidden_inputs(form_page) |  | ||||||
|                 form_data.update(data) |  | ||||||
|                 return self._download_webpage_handle( |  | ||||||
|                     post_url, video_id, note, data=urlencode_postdata(form_data), headers={ |  | ||||||
|                         'Content-Type': 'application/x-www-form-urlencoded', |  | ||||||
|                     }) |  | ||||||
| 
 | 
 | ||||||
|                 provider_redirect_page_res = self._download_webpage_handle( |                 provider_redirect_page_res = self._download_webpage_handle( | ||||||
|                     self._SERVICE_PROVIDER_TEMPLATE % 'authenticate/saml', video_id, |                     self._SERVICE_PROVIDER_TEMPLATE % 'authenticate/saml', video_id, | ||||||
| @ -94,18 +115,10 @@ class AdobePassIE(InfoExtractor): | |||||||
|                     }) |                     }) | ||||||
|                 provider_login_page_res = post_form( |                 provider_login_page_res = post_form( | ||||||
|                     provider_redirect_page_res, 'Downloading Provider Login Page') |                     provider_redirect_page_res, 'Downloading Provider Login Page') | ||||||
|             login_data = {} |                 mvpd_confirm_page_res = post_form(provider_login_page_res, 'Logging in', { | ||||||
|             if mso_id == 'DTV': |                     mso_info['username_field']: username, | ||||||
|                 login_data = { |                     mso_info['password_field']: password, | ||||||
|                     'username': username, |                 }) | ||||||
|                     'password': password, |  | ||||||
|                 } |  | ||||||
|             elif mso_id == 'Rogers': |  | ||||||
|                 login_data = { |  | ||||||
|                     'UserName': username, |  | ||||||
|                     'UserPassword': password, |  | ||||||
|                 } |  | ||||||
|             mvpd_confirm_page_res = post_form(provider_login_page_res, 'Logging in', login_data) |  | ||||||
|                 if mso_id == 'DTV': |                 if mso_id == 'DTV': | ||||||
|                     post_form(mvpd_confirm_page_res, 'Confirming Login') |                     post_form(mvpd_confirm_page_res, 'Confirming Login') | ||||||
| 
 | 
 | ||||||
| @ -117,7 +130,8 @@ class AdobePassIE(InfoExtractor): | |||||||
|                     }), headers=mvpd_headers) |                     }), headers=mvpd_headers) | ||||||
|                 if '<pendingLogout' in session: |                 if '<pendingLogout' in session: | ||||||
|                     self._downloader.cache.store('mvpd', requestor_id, {}) |                     self._downloader.cache.store('mvpd', requestor_id, {}) | ||||||
|                 return self._extract_mvpd_auth(url, video_id, requestor_id, resource) |                     count += 1 | ||||||
|  |                     continue | ||||||
|                 authn_token = unescapeHTML(xml_text(session, 'authnToken')) |                 authn_token = unescapeHTML(xml_text(session, 'authnToken')) | ||||||
|                 requestor_info['authn_token'] = authn_token |                 requestor_info['authn_token'] = authn_token | ||||||
|                 self._downloader.cache.store('mvpd', requestor_id, requestor_info) |                 self._downloader.cache.store('mvpd', requestor_id, requestor_info) | ||||||
| @ -137,7 +151,8 @@ class AdobePassIE(InfoExtractor): | |||||||
|                     }), headers=mvpd_headers) |                     }), headers=mvpd_headers) | ||||||
|                 if '<pendingLogout' in authorize: |                 if '<pendingLogout' in authorize: | ||||||
|                     self._downloader.cache.store('mvpd', requestor_id, {}) |                     self._downloader.cache.store('mvpd', requestor_id, {}) | ||||||
|                 return self._extract_mvpd_auth(url, video_id, requestor_id, resource) |                     count += 1 | ||||||
|  |                     continue | ||||||
|                 authz_token = unescapeHTML(xml_text(authorize, 'authzToken')) |                 authz_token = unescapeHTML(xml_text(authorize, 'authzToken')) | ||||||
|                 requestor_info[guid] = authz_token |                 requestor_info[guid] = authz_token | ||||||
|                 self._downloader.cache.store('mvpd', requestor_id, requestor_info) |                 self._downloader.cache.store('mvpd', requestor_id, requestor_info) | ||||||
| @ -157,5 +172,6 @@ class AdobePassIE(InfoExtractor): | |||||||
|                 }), headers=mvpd_headers) |                 }), headers=mvpd_headers) | ||||||
|             if '<pendingLogout' in short_authorize: |             if '<pendingLogout' in short_authorize: | ||||||
|                 self._downloader.cache.store('mvpd', requestor_id, {}) |                 self._downloader.cache.store('mvpd', requestor_id, {}) | ||||||
|             return self._extract_mvpd_auth(url, video_id, requestor_id, resource) |                 count += 1 | ||||||
|  |                 continue | ||||||
|             return short_authorize |             return short_authorize | ||||||
|  | |||||||
| @ -680,7 +680,7 @@ class InfoExtractor(object): | |||||||
| 
 | 
 | ||||||
|         return (username, password) |         return (username, password) | ||||||
| 
 | 
 | ||||||
|     def _get_login_info(self): |     def _get_login_info(self, username_option='username', password_option='password', netrc_machine=None): | ||||||
|         """ |         """ | ||||||
|         Get the login info as (username, password) |         Get the login info as (username, password) | ||||||
|         It will look in the netrc file using the _NETRC_MACHINE value |         It will look in the netrc file using the _NETRC_MACHINE value | ||||||
| @ -694,11 +694,11 @@ class InfoExtractor(object): | |||||||
|         downloader_params = self._downloader.params |         downloader_params = self._downloader.params | ||||||
| 
 | 
 | ||||||
|         # Attempt to use provided username and password or .netrc data |         # Attempt to use provided username and password or .netrc data | ||||||
|         if downloader_params.get('username') is not None: |         if downloader_params.get(username_option) is not None: | ||||||
|             username = downloader_params['username'] |             username = downloader_params[username_option] | ||||||
|             password = downloader_params['password'] |             password = downloader_params[password_option] | ||||||
|         else: |         else: | ||||||
|             username, password = self._get_netrc_login_info() |             username, password = self._get_netrc_login_info(netrc_machine) | ||||||
| 
 | 
 | ||||||
|         return (username, password) |         return (username, password) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -94,7 +94,7 @@ def parseOpts(overrideArguments=None): | |||||||
|         setattr(parser.values, option.dest, value.split(',')) |         setattr(parser.values, option.dest, value.split(',')) | ||||||
| 
 | 
 | ||||||
|     def _hide_login_info(opts): |     def _hide_login_info(opts): | ||||||
|         PRIVATE_OPTS = ['-p', '--password', '-u', '--username', '--video-password'] |         PRIVATE_OPTS = ['-p', '--password', '-u', '--username', '--video-password', '--ap-password', '--ap-username'] | ||||||
|         eqre = re.compile('^(?P<key>' + ('|'.join(re.escape(po) for po in PRIVATE_OPTS)) + ')=.+$') |         eqre = re.compile('^(?P<key>' + ('|'.join(re.escape(po) for po in PRIVATE_OPTS)) + ')=.+$') | ||||||
| 
 | 
 | ||||||
|         def _scrub_eq(o): |         def _scrub_eq(o): | ||||||
| @ -350,10 +350,28 @@ def parseOpts(overrideArguments=None): | |||||||
|         '--video-password', |         '--video-password', | ||||||
|         dest='videopassword', metavar='PASSWORD', |         dest='videopassword', metavar='PASSWORD', | ||||||
|         help='Video password (vimeo, smotri, youku)') |         help='Video password (vimeo, smotri, youku)') | ||||||
|     authentication.add_option( | 
 | ||||||
|  |     adobe_pass = optparse.OptionGroup(parser, 'Adobe Pass Options') | ||||||
|  |     adobe_pass.add_option( | ||||||
|         '--ap-mso-id', |         '--ap-mso-id', | ||||||
|         dest='ap_mso_id', metavar='APMSOID', |         dest='ap_mso_id', metavar='APMSOID', | ||||||
|         help='Adobe Pass Multiple-system operator Identifier(DTV, Rogers)') |         help='Adobe Pass Multiple-system operator Identifier') | ||||||
|  |     adobe_pass.add_option( | ||||||
|  |         '--ap-username', | ||||||
|  |         dest='ap_username', metavar='APUSERNAME', | ||||||
|  |         help='TV Provider Login with this account ID') | ||||||
|  |     adobe_pass.add_option( | ||||||
|  |         '--ap-password', | ||||||
|  |         dest='ap_password', metavar='APPASSWORD', | ||||||
|  |         help='TV Provider Account password. If this option is left out, youtube-dl will ask interactively.') | ||||||
|  |     adobe_pass.add_option( | ||||||
|  |         '--list-ap-mso-ids', | ||||||
|  |         action='store_true', dest='list_ap_mso_ids', default=False, | ||||||
|  |         help='List all supported TV Providers') | ||||||
|  |     adobe_pass.add_option( | ||||||
|  |         '--ap-retries', | ||||||
|  |         dest='ap_retries', metavar='APRETRIES', default=3, | ||||||
|  |         help='Number of retries for Adobe Pass Authorization requests') | ||||||
| 
 | 
 | ||||||
|     video_format = optparse.OptionGroup(parser, 'Video Format Options') |     video_format = optparse.OptionGroup(parser, 'Video Format Options') | ||||||
|     video_format.add_option( |     video_format.add_option( | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user