Improve build/updater

* Fix `get_executable_path` in UNIX
* Update `x86.exe` correctly
* Exit immediately in windows once the update process starts so that the file handle is released correctly
* Show `exe`/`zip`/`source` and 32/64bit in verbose message
* Look for both `yt-dlp` and `youtube-dlc` in releases. This ensures that the updater will keep working when the binary name is changed to yt-dlp
* Disable pycryptodome in win_x86 since it causes `distutils.errors.DistutilsPlatformError: Microsoft Visual C++ 10.0 is required`
This commit is contained in:
pukkandan 2021-02-14 22:40:54 +05:30
parent 273762c8d0
commit e5813e53f0
6 changed files with 52 additions and 29 deletions

View File

@ -122,7 +122,7 @@ jobs:
python-version: '3.4.4' python-version: '3.4.4'
architecture: 'x86' architecture: 'x86'
- name: Install Requirements for 32 Bit - name: Install Requirements for 32 Bit
run: pip install pyinstaller==3.5 mutagen pycryptodome run: pip install pyinstaller==3.5 mutagen Crypto
- name: Bump version - name: Bump version
id: bump_version id: bump_version
run: python devscripts/update-version.py run: python devscripts/update-version.py

View File

@ -72,7 +72,7 @@ PyInstaller.__main__.run([
'--exclude-module=test', '--exclude-module=test',
'--exclude-module=ytdlp_plugins', '--exclude-module=ytdlp_plugins',
'--hidden-import=mutagen', '--hidden-import=mutagen',
'--hidden-import=pycryptodome', '--hidden-import=%s' % ('Crypto' if _x86 else 'pycryptodome'),
'youtube_dlc/__main__.py', 'youtube_dlc/__main__.py',
]) ])
SetVersion('dist/youtube-dlc%s.exe' % _x86, VERSION_FILE) SetVersion('dist/youtube-dlc%s.exe' % _x86, VERSION_FILE)

View File

@ -27,6 +27,7 @@ import traceback
import random import random
from string import ascii_letters from string import ascii_letters
from zipimport import zipimporter
from .compat import ( from .compat import (
compat_basestring, compat_basestring,
@ -2770,7 +2771,12 @@ class YoutubeDL(object):
self.get_encoding())) self.get_encoding()))
write_string(encoding_str, encoding=None) write_string(encoding_str, encoding=None)
self._write_string('[debug] yt-dlp version %s\n' % __version__) source = (
'(exe)' if hasattr(sys, 'frozen')
else '(zip)' if isinstance(globals().get('__loader__'), zipimporter)
else '(source)' if os.path.basename(sys.argv[0]) == '__main__.py'
else '')
self._write_string('[debug] yt-dlp version %s %s\n' % (__version__, source))
if _LAZY_LOADER: if _LAZY_LOADER:
self._write_string('[debug] Lazy loading extractors enabled\n') self._write_string('[debug] Lazy loading extractors enabled\n')
if _PLUGIN_CLASSES: if _PLUGIN_CLASSES:
@ -2797,8 +2803,10 @@ class YoutubeDL(object):
return impl_name + ' version %d.%d.%d' % sys.pypy_version_info[:3] return impl_name + ' version %d.%d.%d' % sys.pypy_version_info[:3]
return impl_name return impl_name
self._write_string('[debug] Python version %s (%s) - %s\n' % ( self._write_string('[debug] Python version %s (%s %s) - %s\n' % (
platform.python_version(), python_implementation(), platform.python_version(),
python_implementation(),
platform.architecture()[0],
platform_name())) platform_name()))
exe_versions = FFmpegPostProcessor.get_versions(self) exe_versions = FFmpegPostProcessor.get_versions(self)

View File

@ -549,16 +549,22 @@ def _real_main(argv=None):
} }
with YoutubeDL(ydl_opts) as ydl: with YoutubeDL(ydl_opts) as ydl:
# Update version actual_use = len(all_urls) or opts.load_info_filename
if opts.update_self:
update_self(ydl.to_screen, opts.verbose, ydl._opener)
# Remove cache dir # Remove cache dir
if opts.rm_cachedir: if opts.rm_cachedir:
ydl.cache.remove() ydl.cache.remove()
# Update version
if opts.update_self:
# If updater returns True, exit. Required for windows
if update_self(ydl.to_screen, opts.verbose, ydl._opener):
if actual_use:
parser.error('The program must exit for the update to complete')
sys.exit()
# Maybe do nothing # Maybe do nothing
if (len(all_urls) < 1) and (opts.load_info_filename is None): if not actual_use:
if opts.update_self or opts.rm_cachedir: if opts.update_self or opts.rm_cachedir:
sys.exit() sys.exit()

View File

@ -5,6 +5,7 @@ import json
import traceback import traceback
import hashlib import hashlib
import os import os
import platform
import subprocess import subprocess
import sys import sys
from zipimport import zipimporter from zipimport import zipimporter
@ -32,7 +33,10 @@ def rsa_verify(message, signature, key):
def update_self(to_screen, verbose, opener): def update_self(to_screen, verbose, opener):
"""Update the program file with the latest version from the repository""" """
Update the program file with the latest version from the repository
Returns whether the program should terminate
"""
JSON_URL = 'https://api.github.com/repos/pukkandan/yt-dlp/releases/latest' JSON_URL = 'https://api.github.com/repos/pukkandan/yt-dlp/releases/latest'
@ -48,7 +52,7 @@ def update_self(to_screen, verbose, opener):
to_screen('Current Build Hash %s' % sha256sum()) to_screen('Current Build Hash %s' % sha256sum())
if not isinstance(globals().get('__loader__'), zipimporter) and not hasattr(sys, 'frozen'): if not isinstance(globals().get('__loader__'), zipimporter) and not hasattr(sys, 'frozen'):
to_screen('It looks like you installed youtube-dlc with a package manager, pip, setup.py or a tarball. Please use that to update.') to_screen('It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball. Please use that to update.')
return return
# Download and check versions info # Download and check versions info
@ -62,25 +66,28 @@ def update_self(to_screen, verbose, opener):
to_screen('Visit https://github.com/pukkandan/yt-dlp/releases/latest') to_screen('Visit https://github.com/pukkandan/yt-dlp/releases/latest')
return return
version_id = version_info['tag_name']
if version_id == __version__:
to_screen('youtube-dlc is up-to-date (' + __version__ + ')')
return
def version_tuple(version_str): def version_tuple(version_str):
return tuple(map(int, version_str.split('.'))) return tuple(map(int, version_str.split('.')))
version_id = version_info['tag_name']
if version_tuple(__version__) >= version_tuple(version_id): if version_tuple(__version__) >= version_tuple(version_id):
to_screen('youtube-dlc is up to date (%s)' % __version__) to_screen('yt-dlp is up to date (%s)' % __version__)
return return
to_screen('Updating to version ' + version_id + ' ...') to_screen('Updating to version ' + version_id + ' ...')
version = { def get_bin_info(bin_or_exe, version):
'bin': next(i for i in version_info['assets'] if i['name'] == 'youtube-dlc'), labels = {
'exe': next(i for i in version_info['assets'] if i['name'] == 'youtube-dlc.exe'), 'zip_3': '',
'exe_x86': next(i for i in version_info['assets'] if i['name'] == 'youtube-dlc_x86.exe'), 'zip_2': '',
} # 'zip_2': '_py2',
'exe_64': '.exe',
'exe_32': '_x86.exe',
}
label = labels['%s_%s' % (bin_or_exe, version)]
return next(
i for i in version_info['assets']
if i['name'] in ('yt-dlp%s' % label, 'youtube-dlc%s' % label))
# 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
@ -100,10 +107,11 @@ def update_self(to_screen, verbose, opener):
return return
try: try:
urlh = opener.open(version['exe']['browser_download_url']) arch = platform.architecture()[0][:2]
urlh = opener.open(get_bin_info('exe', arch)['browser_download_url'])
newcontent = urlh.read() newcontent = urlh.read()
urlh.close() urlh.close()
except (IOError, OSError): except (IOError, OSError, StopIteration):
if verbose: if verbose:
to_screen(encode_compat_str(traceback.format_exc())) to_screen(encode_compat_str(traceback.format_exc()))
to_screen('ERROR: unable to download latest version') to_screen('ERROR: unable to download latest version')
@ -127,7 +135,7 @@ def update_self(to_screen, verbose, opener):
echo.Waiting for file handle to be closed ... echo.Waiting for file handle to be closed ...
ping 127.0.0.1 -n 5 -w 1000 > NUL ping 127.0.0.1 -n 5 -w 1000 > NUL
move /Y "%s.new" "%s" > NUL move /Y "%s.new" "%s" > NUL
echo.Updated youtube-dlc to version %s. echo.Updated yt-dlp to version %s.
) )
@start /b "" cmd /c del "%%~f0"&exit /b @start /b "" cmd /c del "%%~f0"&exit /b
''' % (exe, exe, version_id)) ''' % (exe, exe, version_id))
@ -143,10 +151,11 @@ def update_self(to_screen, verbose, opener):
# Zip unix package # Zip unix package
elif isinstance(globals().get('__loader__'), zipimporter): elif isinstance(globals().get('__loader__'), zipimporter):
try: try:
urlh = opener.open(version['bin']['browser_download_url']) py_ver = platform.python_version()[0]
urlh = opener.open(get_bin_info('zip', py_ver)['browser_download_url'])
newcontent = urlh.read() newcontent = urlh.read()
urlh.close() urlh.close()
except (IOError, OSError): except (IOError, OSError, StopIteration):
if verbose: if verbose:
to_screen(encode_compat_str(traceback.format_exc())) to_screen(encode_compat_str(traceback.format_exc()))
to_screen('ERROR: unable to download latest version') to_screen('ERROR: unable to download latest version')
@ -162,7 +171,7 @@ def update_self(to_screen, verbose, opener):
to_screen('ERROR: unable to overwrite current version') to_screen('ERROR: unable to overwrite current version')
return return
to_screen('Updated youtube-dlc. Restart youtube-dlc to use the new version.') to_screen('Updated yt-dlp. Restart youtube-dlc to use the new version.')
''' # UNUSED ''' # UNUSED

View File

@ -5936,7 +5936,7 @@ def make_dir(path, to_screen=None):
def get_executable_path(): def get_executable_path():
path = os.path.dirname(sys.argv[0]) path = os.path.dirname(sys.argv[0])
if os.path.abspath(sys.argv[0]) != os.path.abspath(sys.executable): # Not packaged if os.path.basename(sys.argv[0]) == '__main__': # Running from source
path = os.path.join(path, '..') path = os.path.join(path, '..')
return os.path.abspath(path) return os.path.abspath(path)