[build] Allow building with py2exe (and misc fixes)

py2exe config is copied from youtube-dl
Closes #1160
This commit is contained in:
pukkandan 2021-10-04 02:25:13 +05:30
parent a1c3967307
commit 5d535b4a55
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698
5 changed files with 100 additions and 47 deletions

View File

@ -161,7 +161,7 @@ jobs:
- name: Print version
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
- name: Run PyInstaller Script
run: python pyinst.py 64
run: python pyinst.py
- name: Upload yt-dlp.exe Windows binary
id: upload-release-windows
uses: actions/upload-release-asset@v1
@ -179,7 +179,7 @@ jobs:
id: sha512_win
run: echo "::set-output name=sha512_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
- name: Run PyInstaller Script with --onedir
run: python pyinst.py 64 --onedir
run: python pyinst.py --onedir
- uses: papeloto/action-zip@v1
with:
files: ./dist/yt-dlp
@ -227,7 +227,7 @@ jobs:
- name: Print version
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
- name: Run PyInstaller Script for 32 Bit
run: python pyinst.py 32
run: python pyinst.py
- name: Upload Executable yt-dlp_x86.exe
id: upload-release-windows32
uses: actions/upload-release-asset@v1

View File

@ -13,11 +13,18 @@
)
import PyInstaller.__main__
arch = sys.argv[1] if len(sys.argv) > 1 else platform.architecture()[0][:2]
arch = platform.architecture()[0][:2]
assert arch in ('32', '64')
_x86 = '_x86' if arch == '32' else ''
opts = sys.argv[2:] or ['--onefile']
# Compatability with older arguments
opts = sys.argv[1:]
if opts[0:1] in (['32'], ['64']):
if arch != opts[0]:
raise Exception(f'{opts[0]}bit executable cannot be built on a {arch}bit system')
opts = opts[1:]
opts = opts or ['--onefile']
print(f'Building {arch}bit version with options {opts}')
FILE_DESCRIPTION = 'yt-dlp%s' % (' (32 Bit)' if _x86 else '')
@ -82,4 +89,4 @@
*opts,
'yt_dlp/__main__.py',
])
SetVersion('dist/yt-dlp%s.exe' % _x86, VERSION_FILE)
SetVersion('dist/%syt-dlp%s.exe' % ('yt-dlp/' if '--onedir' in opts else '', _x86), VERSION_FILE)

View File

@ -1,12 +1,16 @@
#!/usr/bin/env python3
# coding: utf-8
from setuptools import setup, Command, find_packages
import os.path
import warnings
import sys
from distutils.spawn import spawn
try:
from setuptools import setup, Command, find_packages
setuptools_available = True
except ImportError:
from distutils.core import setup, Command
setuptools_available = False
from distutils.spawn import spawn
# Get the version from yt_dlp/version.py without importing the package
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
@ -21,32 +25,62 @@
REQUIREMENTS = ['mutagen', 'pycryptodome', 'websockets']
if sys.argv[1:2] == ['py2exe']:
raise NotImplementedError('py2exe is not currently supported; instead, use "pyinst.py" to build with pyinstaller')
import py2exe
warnings.warn(
'Building with py2exe is not officially supported. '
'The recommended way is to use "pyinst.py" to build using pyinstaller')
params = {
'console': [{
'script': './yt_dlp/__main__.py',
'dest_base': 'yt-dlp',
'version': __version__,
'description': DESCRIPTION,
'comments': LONG_DESCRIPTION.split('\n')[0],
'product_name': 'yt-dlp',
'product_version': __version__,
}],
'options': {
'py2exe': {
'bundle_files': 0,
'compressed': 1,
'optimize': 2,
'dist_dir': './dist',
'excludes': ['Crypto', 'Cryptodome'], # py2exe cannot import Crypto
'dll_excludes': ['w9xpopen.exe', 'crypt32.dll'],
}
},
'zipfile': None
}
else:
files_spec = [
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
('share/doc/yt_dlp', ['README.txt']),
('share/man/man1', ['yt-dlp.1'])
]
root = os.path.dirname(os.path.abspath(__file__))
data_files = []
for dirname, files in files_spec:
resfiles = []
for fn in files:
if not os.path.exists(fn):
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first' % fn)
else:
resfiles.append(fn)
data_files.append((dirname, resfiles))
files_spec = [
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
('share/doc/yt_dlp', ['README.txt']),
('share/man/man1', ['yt-dlp.1'])
]
root = os.path.dirname(os.path.abspath(__file__))
data_files = []
for dirname, files in files_spec:
resfiles = []
for fn in files:
if not os.path.exists(fn):
warnings.warn('Skipping file %s since it is not present. Try running `make pypi-files` first' % fn)
else:
resfiles.append(fn)
data_files.append((dirname, resfiles))
params = {
'data_files': data_files,
}
params = {
'data_files': data_files,
}
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
if setuptools_available:
params['entry_points'] = {'console_scripts': ['yt-dlp = yt_dlp:main']}
else:
params['scripts'] = ['yt-dlp']
class build_lazy_extractors(Command):
@ -64,7 +98,11 @@ def run(self):
dry_run=self.dry_run)
packages = find_packages(exclude=('youtube_dl', 'test', 'ytdlp_plugins'))
if setuptools_available:
packages = find_packages(exclude=('youtube_dl', 'youtube_dlc', 'test', 'ytdlp_plugins'))
else:
packages = ['yt_dlp', 'yt_dlp.downloader', 'yt_dlp.extractor', 'yt_dlp.postprocessor']
setup(
name='yt-dlp',

View File

@ -32,10 +32,12 @@ def rsa_verify(message, signature, key):
def detect_variant():
if hasattr(sys, 'frozen') and getattr(sys, '_MEIPASS', None):
if sys._MEIPASS == os.path.dirname(sys.executable):
return 'dir'
return 'exe'
if hasattr(sys, 'frozen'):
if getattr(sys, '_MEIPASS', None):
if sys._MEIPASS == os.path.dirname(sys.executable):
return 'dir'
return 'exe'
return 'py2exe'
elif isinstance(globals().get('__loader__'), zipimporter):
return 'zip'
elif os.path.basename(sys.argv[0]) == '__main__.py':
@ -43,6 +45,20 @@ def detect_variant():
return 'unknown'
_NON_UPDATEABLE_REASONS = {
'exe': None,
'zip': None,
'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',
'source': 'You cannot update when running from source code',
'unknown': 'It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball. Use that to update',
}
def is_non_updateable():
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 '''
@ -114,14 +130,7 @@ def version_tuple(version_str):
ydl.to_screen(f'yt-dlp is up to date ({__version__})')
return
ERRORS = {
'exe': None,
'zip': None,
'dir': 'Auto-update is not supported for unpackaged windows executable. Re-download the latest release',
'source': 'You cannot update when running from source code',
'unknown': 'It looks like you installed yt-dlp with a package manager, pip, setup.py or a tarball. Use that to update',
}
err = ERRORS.get(detect_variant(), ERRORS['unknown'])
err = is_non_updateable()
if err:
ydl.to_screen(f'Latest version: {version_id}, Current version: {__version__}')
return report_error(err, expected=True)

View File

@ -4521,11 +4521,10 @@ def is_outdated_version(version, limit, assume_new=True):
def ytdl_is_updateable():
""" Returns if yt-dlp can be updated with -U """
return False
from zipimport import zipimporter
from .update import is_non_updateable
return isinstance(globals().get('__loader__'), zipimporter) or hasattr(sys, 'frozen')
return not is_non_updateable()
def args_to_str(args):