mirror of https://github.com/yt-dlp/yt-dlp.git
parent
ed39cac53d
commit
e6faf2be36
135
yt_dlp/update.py
135
yt_dlp/update.py
|
@ -48,10 +48,10 @@ def detect_variant():
|
||||||
_NON_UPDATEABLE_REASONS = {
|
_NON_UPDATEABLE_REASONS = {
|
||||||
'exe': None,
|
'exe': None,
|
||||||
'zip': None,
|
'zip': None,
|
||||||
'dir': 'Auto-update is not supported for unpackaged windows executable. Re-download the latest release',
|
'dir': 'Auto-update is not supported for unpackaged windows executable; Re-download the latest release',
|
||||||
'py2exe': 'There is no official release for py2exe executable. Build it again with the latest source code',
|
'py2exe': 'There is no official release for py2exe executable; Build it again with the latest source code',
|
||||||
'source': 'You cannot update when running from source code',
|
'source': 'You cannot update when running from source code; Use git to pull the latest changes',
|
||||||
'unknown': 'It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball. Use that to update',
|
'unknown': 'It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball; Use that to update',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,40 +59,6 @@ def is_non_updateable():
|
||||||
return _NON_UPDATEABLE_REASONS.get(detect_variant(), _NON_UPDATEABLE_REASONS['unknown'])
|
return _NON_UPDATEABLE_REASONS.get(detect_variant(), _NON_UPDATEABLE_REASONS['unknown'])
|
||||||
|
|
||||||
|
|
||||||
def update_self(to_screen, verbose, opener):
|
|
||||||
''' Exists for backward compatibility. Use run_update(ydl) instead '''
|
|
||||||
|
|
||||||
printfn = to_screen
|
|
||||||
|
|
||||||
class FakeYDL():
|
|
||||||
_opener = opener
|
|
||||||
to_screen = printfn
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def report_warning(msg, *args, **kwargs):
|
|
||||||
return printfn('WARNING: %s' % msg, *args, **kwargs)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def report_error(msg, tb=None):
|
|
||||||
printfn('ERROR: %s' % msg)
|
|
||||||
if not verbose:
|
|
||||||
return
|
|
||||||
if tb is None:
|
|
||||||
# Copied from YoutubeDl.trouble
|
|
||||||
if sys.exc_info()[0]:
|
|
||||||
tb = ''
|
|
||||||
if hasattr(sys.exc_info()[1], 'exc_info') and sys.exc_info()[1].exc_info[0]:
|
|
||||||
tb += ''.join(traceback.format_exception(*sys.exc_info()[1].exc_info))
|
|
||||||
tb += encode_compat_str(traceback.format_exc())
|
|
||||||
else:
|
|
||||||
tb_data = traceback.format_list(traceback.extract_stack())
|
|
||||||
tb = ''.join(tb_data)
|
|
||||||
if tb:
|
|
||||||
printfn(tb)
|
|
||||||
|
|
||||||
return run_update(FakeYDL())
|
|
||||||
|
|
||||||
|
|
||||||
def run_update(ydl):
|
def run_update(ydl):
|
||||||
"""
|
"""
|
||||||
Update the program file with the latest version from the repository
|
Update the program file with the latest version from the repository
|
||||||
|
@ -101,10 +67,17 @@ def run_update(ydl):
|
||||||
|
|
||||||
JSON_URL = 'https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest'
|
JSON_URL = 'https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest'
|
||||||
|
|
||||||
def report_error(msg, network=False, expected=False, delim=';'):
|
def report_error(msg, expected=False):
|
||||||
if network:
|
ydl.report_error(msg, tb='' if expected else None)
|
||||||
msg += '%s Visit https://github.com/yt-dlp/yt-dlp/releases/latest' % delim
|
|
||||||
ydl.report_error(msg, tb='' if network or expected else None)
|
def report_unable(action, expected=False):
|
||||||
|
report_error(f'Unable to {action}', expected)
|
||||||
|
|
||||||
|
def report_permission_error(file):
|
||||||
|
report_unable(f'write to {file}; Try running as administrator', True)
|
||||||
|
|
||||||
|
def report_network_error(action, delim=';'):
|
||||||
|
report_unable(f'{action}{delim} Visit https://github.com/yt-dlp/yt-dlp/releases/latest', True)
|
||||||
|
|
||||||
def calc_sha256sum(path):
|
def calc_sha256sum(path):
|
||||||
h = hashlib.sha256()
|
h = hashlib.sha256()
|
||||||
|
@ -120,7 +93,7 @@ def run_update(ydl):
|
||||||
version_info = ydl._opener.open(JSON_URL).read().decode('utf-8')
|
version_info = ydl._opener.open(JSON_URL).read().decode('utf-8')
|
||||||
version_info = json.loads(version_info)
|
version_info = json.loads(version_info)
|
||||||
except Exception:
|
except Exception:
|
||||||
return report_error('can\'t obtain versions info. Please try again later ', True, delim='or')
|
return report_network_error('obtain version info', delim='; Please try again later or')
|
||||||
|
|
||||||
def version_tuple(version_str):
|
def version_tuple(version_str):
|
||||||
return tuple(map(int, version_str.split('.')))
|
return tuple(map(int, version_str.split('.')))
|
||||||
|
@ -133,7 +106,7 @@ def run_update(ydl):
|
||||||
err = is_non_updateable()
|
err = is_non_updateable()
|
||||||
if err:
|
if err:
|
||||||
ydl.to_screen(f'Latest version: {version_id}, Current version: {__version__}')
|
ydl.to_screen(f'Latest version: {version_id}, Current version: {__version__}')
|
||||||
return report_error(err, expected=True)
|
return report_error(err, True)
|
||||||
|
|
||||||
# sys.executable is set to the full pathname of the exe-file for py2exe
|
# sys.executable is set to the full pathname of the exe-file for py2exe
|
||||||
# though symlinks are not followed so that we need to do this manually
|
# though symlinks are not followed so that we need to do this manually
|
||||||
|
@ -163,55 +136,57 @@ def run_update(ydl):
|
||||||
return dict(ln.split()[::-1] for ln in hash_data.splitlines()).get(filename)
|
return dict(ln.split()[::-1] for ln in hash_data.splitlines()).get(filename)
|
||||||
|
|
||||||
if not os.access(filename, os.W_OK):
|
if not os.access(filename, os.W_OK):
|
||||||
return report_error('no write permissions on %s' % filename, expected=True)
|
return report_permission_error(filename)
|
||||||
|
|
||||||
# PyInstaller
|
# PyInstaller
|
||||||
if hasattr(sys, 'frozen'):
|
if hasattr(sys, 'frozen'):
|
||||||
exe = filename
|
exe = filename
|
||||||
directory = os.path.dirname(exe)
|
directory = os.path.dirname(exe)
|
||||||
if not os.access(directory, os.W_OK):
|
if not os.access(directory, os.W_OK):
|
||||||
return report_error('no write permissions on %s' % directory, expected=True)
|
return report_permission_error(directory)
|
||||||
try:
|
try:
|
||||||
if os.path.exists(filename + '.old'):
|
if os.path.exists(filename + '.old'):
|
||||||
os.remove(filename + '.old')
|
os.remove(filename + '.old')
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
return report_error('unable to remove the old version')
|
return report_unable('remove the old version')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
arch = platform.architecture()[0][:2]
|
arch = platform.architecture()[0][:2]
|
||||||
url = get_bin_info('exe', arch).get('browser_download_url')
|
url = get_bin_info('exe', arch).get('browser_download_url')
|
||||||
if not url:
|
if not url:
|
||||||
return report_error('unable to fetch updates', True)
|
return report_network_error('fetch updates')
|
||||||
urlh = ydl._opener.open(url)
|
urlh = ydl._opener.open(url)
|
||||||
newcontent = urlh.read()
|
newcontent = urlh.read()
|
||||||
urlh.close()
|
urlh.close()
|
||||||
except (IOError, OSError, StopIteration):
|
except (IOError, OSError):
|
||||||
return report_error('unable to download latest version', True)
|
return report_network_error('download latest version')
|
||||||
|
|
||||||
|
if not os.access(exe + '.new', os.W_OK):
|
||||||
|
return report_permission_error(f'{exe}.new')
|
||||||
try:
|
try:
|
||||||
with open(exe + '.new', 'wb') as outf:
|
with open(exe + '.new', 'wb') as outf:
|
||||||
outf.write(newcontent)
|
outf.write(newcontent)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
return report_error('unable to write the new version')
|
return report_unable('write the new version')
|
||||||
|
|
||||||
expected_sum = get_sha256sum('exe', arch)
|
expected_sum = get_sha256sum('exe', arch)
|
||||||
if not expected_sum:
|
if not expected_sum:
|
||||||
ydl.report_warning('no hash information found for the release')
|
ydl.report_warning('no hash information found for the release')
|
||||||
elif calc_sha256sum(exe + '.new') != expected_sum:
|
elif calc_sha256sum(exe + '.new') != expected_sum:
|
||||||
report_error('unable to verify the new executable', True)
|
report_network_error('verify the new executable')
|
||||||
try:
|
try:
|
||||||
os.remove(exe + '.new')
|
os.remove(exe + '.new')
|
||||||
except OSError:
|
except OSError:
|
||||||
return report_error('unable to remove corrupt download')
|
return report_unable('remove corrupt download')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.rename(exe, exe + '.old')
|
os.rename(exe, exe + '.old')
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
return report_error('unable to move current version')
|
return report_unable('move current version')
|
||||||
try:
|
try:
|
||||||
os.rename(exe + '.new', exe)
|
os.rename(exe + '.new', exe)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
report_error('unable to overwrite current version')
|
report_unable('overwrite current version')
|
||||||
os.rename(exe + '.old', exe)
|
os.rename(exe + '.old', exe)
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
|
@ -222,31 +197,31 @@ def run_update(ydl):
|
||||||
ydl.to_screen('Updated yt-dlp to version %s' % version_id)
|
ydl.to_screen('Updated yt-dlp to version %s' % version_id)
|
||||||
return True # Exit app
|
return True # Exit app
|
||||||
except OSError:
|
except OSError:
|
||||||
report_error('unable to delete old version')
|
report_unable('delete the old version')
|
||||||
|
|
||||||
# Zip unix package
|
# Zip unix package
|
||||||
elif isinstance(globals().get('__loader__'), zipimporter):
|
elif isinstance(globals().get('__loader__'), zipimporter):
|
||||||
try:
|
try:
|
||||||
url = get_bin_info('zip', '3').get('browser_download_url')
|
url = get_bin_info('zip', '3').get('browser_download_url')
|
||||||
if not url:
|
if not url:
|
||||||
return report_error('unable to fetch updates', True)
|
return report_network_error('fetch updates')
|
||||||
urlh = ydl._opener.open(url)
|
urlh = ydl._opener.open(url)
|
||||||
newcontent = urlh.read()
|
newcontent = urlh.read()
|
||||||
urlh.close()
|
urlh.close()
|
||||||
except (IOError, OSError, StopIteration):
|
except (IOError, OSError):
|
||||||
return report_error('unable to download latest version', True)
|
return report_network_error('download the latest version')
|
||||||
|
|
||||||
expected_sum = get_sha256sum('zip', '3')
|
expected_sum = get_sha256sum('zip', '3')
|
||||||
if not expected_sum:
|
if not expected_sum:
|
||||||
ydl.report_warning('no hash information found for the release')
|
ydl.report_warning('no hash information found for the release')
|
||||||
elif hashlib.sha256(newcontent).hexdigest() != expected_sum:
|
elif hashlib.sha256(newcontent).hexdigest() != expected_sum:
|
||||||
return report_error('unable to verify the new zip', True)
|
return report_network_error('verify the new zip')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(filename, 'wb') as outf:
|
with open(filename, 'wb') as outf:
|
||||||
outf.write(newcontent)
|
outf.write(newcontent)
|
||||||
except (IOError, OSError):
|
except (IOError, OSError):
|
||||||
return report_error('unable to overwrite current version')
|
return report_unable('overwrite current version')
|
||||||
|
|
||||||
ydl.to_screen('Updated yt-dlp to version %s; Restart yt-dlp to use the new version' % version_id)
|
ydl.to_screen('Updated yt-dlp to version %s; Restart yt-dlp to use the new version' % version_id)
|
||||||
|
|
||||||
|
@ -267,3 +242,41 @@ def print_notes(to_screen, versions, fromVersion=__version__):
|
||||||
for note in notes:
|
for note in notes:
|
||||||
to_screen(note)
|
to_screen(note)
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def update_self(to_screen, verbose, opener):
|
||||||
|
''' Exists for backward compatibility '''
|
||||||
|
|
||||||
|
printfn = to_screen
|
||||||
|
|
||||||
|
printfn(
|
||||||
|
'WARNING: "yt_dlp.update.update_self" is deprecated and may be removed in a future version. '
|
||||||
|
'Use "yt_dlp.update.run_update(ydl)" instead')
|
||||||
|
|
||||||
|
class FakeYDL():
|
||||||
|
_opener = opener
|
||||||
|
to_screen = printfn
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def report_warning(msg, *args, **kwargs):
|
||||||
|
return printfn('WARNING: %s' % msg, *args, **kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def report_error(msg, tb=None):
|
||||||
|
printfn('ERROR: %s' % msg)
|
||||||
|
if not verbose:
|
||||||
|
return
|
||||||
|
if tb is None:
|
||||||
|
# Copied from YoutubeDl.trouble
|
||||||
|
if sys.exc_info()[0]:
|
||||||
|
tb = ''
|
||||||
|
if hasattr(sys.exc_info()[1], 'exc_info') and sys.exc_info()[1].exc_info[0]:
|
||||||
|
tb += ''.join(traceback.format_exception(*sys.exc_info()[1].exc_info))
|
||||||
|
tb += encode_compat_str(traceback.format_exc())
|
||||||
|
else:
|
||||||
|
tb_data = traceback.format_list(traceback.extract_stack())
|
||||||
|
tb = ''.join(tb_data)
|
||||||
|
if tb:
|
||||||
|
printfn(tb)
|
||||||
|
|
||||||
|
return run_update(FakeYDL())
|
||||||
|
|
Loading…
Reference in New Issue