mirror of
https://github.com/ytdl-org/youtube-dl
synced 2025-07-23 20:04:15 +09:00
improved logging
This commit is contained in:
parent
6d6fe8b3d0
commit
97977004d6
@ -2371,7 +2371,7 @@ class YoutubeDL(object):
|
|||||||
opts_cookiefile = self.params.get('cookiefile')
|
opts_cookiefile = self.params.get('cookiefile')
|
||||||
opts_proxy = self.params.get('proxy')
|
opts_proxy = self.params.get('proxy')
|
||||||
|
|
||||||
self.cookiejar = load_cookies(opts_cookiefile, opts_cookiesfrombrowser)
|
self.cookiejar = load_cookies(opts_cookiefile, opts_cookiesfrombrowser, self)
|
||||||
|
|
||||||
cookie_processor = YoutubeDLCookieProcessor(self.cookiejar)
|
cookie_processor = YoutubeDLCookieProcessor(self.cookiejar)
|
||||||
if opts_proxy is not None:
|
if opts_proxy is not None:
|
||||||
|
@ -29,18 +29,26 @@ SUPPORTED_BROWSERS = ['firefox', 'chrome', 'chrome_beta', 'chrome_dev', 'chromiu
|
|||||||
'edge', 'edge_beta']
|
'edge', 'edge_beta']
|
||||||
|
|
||||||
|
|
||||||
def extract_cookies_from_browser(browser_name):
|
class Logger:
|
||||||
|
def info(self, message):
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
print(message, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_cookies_from_browser(browser_name, logger=Logger()):
|
||||||
if browser_name == 'firefox':
|
if browser_name == 'firefox':
|
||||||
return _extract_firefox_cookies()
|
return _extract_firefox_cookies(logger)
|
||||||
elif browser_name in ('chrome', 'chrome_beta', 'chrome_dev', 'chromium',
|
elif browser_name in ('chrome', 'chrome_beta', 'chrome_dev', 'chromium',
|
||||||
'brave', 'opera', 'edge', 'edge_beta'):
|
'brave', 'opera', 'edge', 'edge_beta'):
|
||||||
return _extract_chrome_cookies(browser_name)
|
return _extract_chrome_cookies(browser_name, logger)
|
||||||
else:
|
else:
|
||||||
raise ValueError('unknown browser: {}'.format(browser_name))
|
raise ValueError('unknown browser: {}'.format(browser_name))
|
||||||
|
|
||||||
|
|
||||||
def _extract_firefox_cookies():
|
def _extract_firefox_cookies(logger):
|
||||||
print('extracting cookies from firefox')
|
logger.info('extracting cookies from firefox')
|
||||||
|
|
||||||
if sys.platform in ('linux', 'linux2'):
|
if sys.platform in ('linux', 'linux2'):
|
||||||
root = os.path.expanduser('~/.mozilla/firefox')
|
root = os.path.expanduser('~/.mozilla/firefox')
|
||||||
@ -68,14 +76,14 @@ def _extract_firefox_cookies():
|
|||||||
path=path, path_specified=bool(path), secure=is_secure, expires=expiry, discard=False,
|
path=path, path_specified=bool(path), secure=is_secure, expires=expiry, discard=False,
|
||||||
comment=None, comment_url=None, rest={})
|
comment=None, comment_url=None, rest={})
|
||||||
jar.set_cookie(cookie)
|
jar.set_cookie(cookie)
|
||||||
print('extracted {} cookies from firefox'.format(len(jar)))
|
logger.info('extracted {} cookies from firefox'.format(len(jar)))
|
||||||
return jar
|
return jar
|
||||||
finally:
|
finally:
|
||||||
if cursor is not None:
|
if cursor is not None:
|
||||||
cursor.connection.close()
|
cursor.connection.close()
|
||||||
|
|
||||||
|
|
||||||
def _get_browser_settings(browser_name):
|
def _get_chrome_like_browser_settings(browser_name):
|
||||||
# https://chromium.googlesource.com/chromium/src/+/HEAD/docs/user_data_dir.md
|
# https://chromium.googlesource.com/chromium/src/+/HEAD/docs/user_data_dir.md
|
||||||
if sys.platform in ('linux', 'linux2'):
|
if sys.platform in ('linux', 'linux2'):
|
||||||
config = _config_home()
|
config = _config_home()
|
||||||
@ -136,15 +144,15 @@ def _get_browser_settings(browser_name):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _extract_chrome_cookies(browser_name):
|
def _extract_chrome_cookies(browser_name, logger):
|
||||||
print('extracting cookies from {}'.format(browser_name))
|
logger.info('extracting cookies from {}'.format(browser_name))
|
||||||
config = _get_browser_settings(browser_name)
|
config = _get_chrome_like_browser_settings(browser_name)
|
||||||
|
|
||||||
cookie_database_path = _find_most_recently_used_file(config['browser_dir'], 'Cookies')
|
cookie_database_path = _find_most_recently_used_file(config['browser_dir'], 'Cookies')
|
||||||
if cookie_database_path is None:
|
if cookie_database_path is None:
|
||||||
raise FileNotFoundError('could not find {} cookies database'.format(browser_name))
|
raise FileNotFoundError('could not find {} cookies database'.format(browser_name))
|
||||||
|
|
||||||
decryptor = get_cookie_decryptor(config['browser_dir'], config['keyring_name'])
|
decryptor = get_cookie_decryptor(config['browser_dir'], config['keyring_name'], logger)
|
||||||
|
|
||||||
with Compat_TemporaryDirectory(prefix='youtube_dl') as tmpdir:
|
with Compat_TemporaryDirectory(prefix='youtube_dl') as tmpdir:
|
||||||
cursor = None
|
cursor = None
|
||||||
@ -176,7 +184,7 @@ def _extract_chrome_cookies(browser_name):
|
|||||||
failed_message = ' ({} could not be decrypted)'.format(failed_cookies)
|
failed_message = ' ({} could not be decrypted)'.format(failed_cookies)
|
||||||
else:
|
else:
|
||||||
failed_message = ''
|
failed_message = ''
|
||||||
print('extracted {} cookies from {}{}'.format(len(jar), browser_name, failed_message))
|
logger.info('extracted {} cookies from {}{}'.format(len(jar), browser_name, failed_message))
|
||||||
return jar
|
return jar
|
||||||
finally:
|
finally:
|
||||||
if cursor is not None:
|
if cursor is not None:
|
||||||
@ -213,13 +221,13 @@ class ChromeCookieDecryptor:
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def get_cookie_decryptor(browser_root, browser_keyring_name):
|
def get_cookie_decryptor(browser_root, browser_keyring_name, logger):
|
||||||
if sys.platform in ('linux', 'linux2'):
|
if sys.platform in ('linux', 'linux2'):
|
||||||
return LinuxChromeCookieDecryptor(browser_keyring_name)
|
return LinuxChromeCookieDecryptor(browser_keyring_name)
|
||||||
elif sys.platform == 'darwin':
|
elif sys.platform == 'darwin':
|
||||||
return MacChromeCookieDecryptor(browser_keyring_name)
|
return MacChromeCookieDecryptor(browser_keyring_name)
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
return WindowsChromeCookieDecryptor(browser_root)
|
return WindowsChromeCookieDecryptor(browser_root, logger)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError('Chrome cookie decryption is not supported '
|
raise NotImplementedError('Chrome cookie decryption is not supported '
|
||||||
'on this platform: {}'.format(sys.platform))
|
'on this platform: {}'.format(sys.platform))
|
||||||
@ -289,8 +297,9 @@ class MacChromeCookieDecryptor(ChromeCookieDecryptor):
|
|||||||
|
|
||||||
|
|
||||||
class WindowsChromeCookieDecryptor(ChromeCookieDecryptor):
|
class WindowsChromeCookieDecryptor(ChromeCookieDecryptor):
|
||||||
def __init__(self, browser_root):
|
def __init__(self, browser_root, logger):
|
||||||
self._v10_key = _get_windows_v10_password(browser_root)
|
self._logger = logger
|
||||||
|
self._v10_key = _get_windows_v10_password(browser_root, logger)
|
||||||
|
|
||||||
def decrypt(self, encrypted_value):
|
def decrypt(self, encrypted_value):
|
||||||
version = encrypted_value[:3]
|
version = encrypted_value[:3]
|
||||||
@ -318,7 +327,7 @@ class WindowsChromeCookieDecryptor(ChromeCookieDecryptor):
|
|||||||
else:
|
else:
|
||||||
# any other prefix means the data is DPAPI encrypted
|
# any other prefix means the data is DPAPI encrypted
|
||||||
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_win.cc
|
# https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/os_crypt_win.cc
|
||||||
return _decrypt_windows_dpapi(encrypted_value)
|
return _decrypt_windows_dpapi(encrypted_value, self._logger)
|
||||||
|
|
||||||
|
|
||||||
def _get_linux_keyring_password(browser_keyring_name):
|
def _get_linux_keyring_password(browser_keyring_name):
|
||||||
@ -354,22 +363,24 @@ def _get_mac_keyring_password(browser_keyring_name):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_windows_v10_password(browser_root):
|
def _get_windows_v10_password(browser_root, logger):
|
||||||
path = _find_most_recently_used_file(browser_root, 'Local State')
|
path = _find_most_recently_used_file(browser_root, 'Local State')
|
||||||
if path is None:
|
if path is None:
|
||||||
print('could not find local state file')
|
logger.error('could not find local state file')
|
||||||
return None
|
return None
|
||||||
with open(path, 'r') as f:
|
with open(path, 'r') as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
try:
|
try:
|
||||||
base64_password = data['os_crypt']['encrypted_key']
|
base64_password = data['os_crypt']['encrypted_key']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
logger.error('no encrypted key in Local State')
|
||||||
return None
|
return None
|
||||||
encrypted_password = compat_b64decode(base64_password)
|
encrypted_password = compat_b64decode(base64_password)
|
||||||
prefix = b'DPAPI'
|
prefix = b'DPAPI'
|
||||||
if not encrypted_password.startswith(prefix):
|
if not encrypted_password.startswith(prefix):
|
||||||
|
logger.error('invalid key')
|
||||||
return None
|
return None
|
||||||
return _decrypt_windows_dpapi(encrypted_password[len(prefix):])
|
return _decrypt_windows_dpapi(encrypted_password[len(prefix):], logger)
|
||||||
|
|
||||||
|
|
||||||
def _decrypt_aes_cbc(ciphertext, key, initialization_vector=b' ' * 16):
|
def _decrypt_aes_cbc(ciphertext, key, initialization_vector=b' ' * 16):
|
||||||
@ -398,7 +409,7 @@ def _decrypt_aes_gcm(ciphertext, key, nonce, authentication_tag):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _decrypt_windows_dpapi(ciphertext):
|
def _decrypt_windows_dpapi(ciphertext, logger):
|
||||||
"""
|
"""
|
||||||
References:
|
References:
|
||||||
- https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptunprotectdata
|
- https://docs.microsoft.com/en-us/windows/win32/api/dpapi/nf-dpapi-cryptunprotectdata
|
||||||
@ -422,7 +433,7 @@ def _decrypt_windows_dpapi(ciphertext):
|
|||||||
ctypes.byref(blob_out) # pDataOut
|
ctypes.byref(blob_out) # pDataOut
|
||||||
)
|
)
|
||||||
if not ret:
|
if not ret:
|
||||||
print('failed to decrypt with DPAPI')
|
logger.info('failed to decrypt with DPAPI')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
result = ctypes.string_at(blob_out.pbData, blob_out.cbData)
|
result = ctypes.string_at(blob_out.pbData, blob_out.cbData)
|
||||||
@ -462,10 +473,21 @@ def _merge_cookie_jars(jars):
|
|||||||
return output_jar
|
return output_jar
|
||||||
|
|
||||||
|
|
||||||
def load_cookies(cookie_file, browser):
|
class YDLLogger(Logger):
|
||||||
|
def __init__(self, ydl):
|
||||||
|
self._ydl = ydl
|
||||||
|
|
||||||
|
def info(self, message):
|
||||||
|
self._ydl.to_screen(message)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
self._ydl.to_stderr(message)
|
||||||
|
|
||||||
|
|
||||||
|
def load_cookies(cookie_file, browser, ydl):
|
||||||
cookie_jars = []
|
cookie_jars = []
|
||||||
if browser is not None:
|
if browser is not None:
|
||||||
cookie_jars.append(extract_cookies_from_browser(browser))
|
cookie_jars.append(extract_cookies_from_browser(browser, YDLLogger(ydl)))
|
||||||
|
|
||||||
if cookie_file is not None:
|
if cookie_file is not None:
|
||||||
cookie_file = expand_path(cookie_file)
|
cookie_file = expand_path(cookie_file)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user