mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2024-10-31 23:02:40 +00:00
[build] Allow building with py2exe (and misc fixes)
py2exe config is copied from youtube-dl Closes #1160
This commit is contained in:
parent
a1c3967307
commit
5d535b4a55
5 changed files with 100 additions and 47 deletions
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
|
@ -161,7 +161,7 @@ jobs:
|
||||||
- name: Print version
|
- name: Print version
|
||||||
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
||||||
- name: Run PyInstaller Script
|
- name: Run PyInstaller Script
|
||||||
run: python pyinst.py 64
|
run: python pyinst.py
|
||||||
- name: Upload yt-dlp.exe Windows binary
|
- name: Upload yt-dlp.exe Windows binary
|
||||||
id: upload-release-windows
|
id: upload-release-windows
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
@ -179,7 +179,7 @@ jobs:
|
||||||
id: sha512_win
|
id: sha512_win
|
||||||
run: echo "::set-output name=sha512_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
|
run: echo "::set-output name=sha512_win::$((Get-FileHash dist\yt-dlp.exe -Algorithm SHA512).Hash.ToLower())"
|
||||||
- name: Run PyInstaller Script with --onedir
|
- name: Run PyInstaller Script with --onedir
|
||||||
run: python pyinst.py 64 --onedir
|
run: python pyinst.py --onedir
|
||||||
- uses: papeloto/action-zip@v1
|
- uses: papeloto/action-zip@v1
|
||||||
with:
|
with:
|
||||||
files: ./dist/yt-dlp
|
files: ./dist/yt-dlp
|
||||||
|
@ -227,7 +227,7 @@ jobs:
|
||||||
- name: Print version
|
- name: Print version
|
||||||
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
run: echo "${{ steps.bump_version.outputs.ytdlp_version }}"
|
||||||
- name: Run PyInstaller Script for 32 Bit
|
- name: Run PyInstaller Script for 32 Bit
|
||||||
run: python pyinst.py 32
|
run: python pyinst.py
|
||||||
- name: Upload Executable yt-dlp_x86.exe
|
- name: Upload Executable yt-dlp_x86.exe
|
||||||
id: upload-release-windows32
|
id: upload-release-windows32
|
||||||
uses: actions/upload-release-asset@v1
|
uses: actions/upload-release-asset@v1
|
||||||
|
|
13
pyinst.py
13
pyinst.py
|
@ -13,11 +13,18 @@
|
||||||
)
|
)
|
||||||
import PyInstaller.__main__
|
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')
|
assert arch in ('32', '64')
|
||||||
_x86 = '_x86' if arch == '32' else ''
|
_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}')
|
print(f'Building {arch}bit version with options {opts}')
|
||||||
|
|
||||||
FILE_DESCRIPTION = 'yt-dlp%s' % (' (32 Bit)' if _x86 else '')
|
FILE_DESCRIPTION = 'yt-dlp%s' % (' (32 Bit)' if _x86 else '')
|
||||||
|
@ -82,4 +89,4 @@
|
||||||
*opts,
|
*opts,
|
||||||
'yt_dlp/__main__.py',
|
'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)
|
||||||
|
|
66
setup.py
66
setup.py
|
@ -1,12 +1,16 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
from setuptools import setup, Command, find_packages
|
|
||||||
import os.path
|
import os.path
|
||||||
import warnings
|
import warnings
|
||||||
import sys
|
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
|
# 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'))
|
exec(compile(open('yt_dlp/version.py').read(), 'yt_dlp/version.py', 'exec'))
|
||||||
|
@ -21,20 +25,46 @@
|
||||||
|
|
||||||
REQUIREMENTS = ['mutagen', 'pycryptodome', 'websockets']
|
REQUIREMENTS = ['mutagen', 'pycryptodome', 'websockets']
|
||||||
|
|
||||||
|
|
||||||
if sys.argv[1:2] == ['py2exe']:
|
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 = [
|
files_spec = [
|
||||||
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
|
('share/bash-completion/completions', ['completions/bash/yt-dlp']),
|
||||||
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
|
('share/zsh/site-functions', ['completions/zsh/_yt-dlp']),
|
||||||
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
|
('share/fish/vendor_completions.d', ['completions/fish/yt-dlp.fish']),
|
||||||
('share/doc/yt_dlp', ['README.txt']),
|
('share/doc/yt_dlp', ['README.txt']),
|
||||||
('share/man/man1', ['yt-dlp.1'])
|
('share/man/man1', ['yt-dlp.1'])
|
||||||
]
|
]
|
||||||
root = os.path.dirname(os.path.abspath(__file__))
|
root = os.path.dirname(os.path.abspath(__file__))
|
||||||
data_files = []
|
data_files = []
|
||||||
for dirname, files in files_spec:
|
for dirname, files in files_spec:
|
||||||
resfiles = []
|
resfiles = []
|
||||||
for fn in files:
|
for fn in files:
|
||||||
if not os.path.exists(fn):
|
if not os.path.exists(fn):
|
||||||
|
@ -43,10 +73,14 @@
|
||||||
resfiles.append(fn)
|
resfiles.append(fn)
|
||||||
data_files.append((dirname, resfiles))
|
data_files.append((dirname, resfiles))
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
'data_files': data_files,
|
'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):
|
class build_lazy_extractors(Command):
|
||||||
|
@ -64,7 +98,11 @@ def run(self):
|
||||||
dry_run=self.dry_run)
|
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(
|
setup(
|
||||||
name='yt-dlp',
|
name='yt-dlp',
|
||||||
|
|
|
@ -32,10 +32,12 @@ def rsa_verify(message, signature, key):
|
||||||
|
|
||||||
|
|
||||||
def detect_variant():
|
def detect_variant():
|
||||||
if hasattr(sys, 'frozen') and getattr(sys, '_MEIPASS', None):
|
if hasattr(sys, 'frozen'):
|
||||||
|
if getattr(sys, '_MEIPASS', None):
|
||||||
if sys._MEIPASS == os.path.dirname(sys.executable):
|
if sys._MEIPASS == os.path.dirname(sys.executable):
|
||||||
return 'dir'
|
return 'dir'
|
||||||
return 'exe'
|
return 'exe'
|
||||||
|
return 'py2exe'
|
||||||
elif isinstance(globals().get('__loader__'), zipimporter):
|
elif isinstance(globals().get('__loader__'), zipimporter):
|
||||||
return 'zip'
|
return 'zip'
|
||||||
elif os.path.basename(sys.argv[0]) == '__main__.py':
|
elif os.path.basename(sys.argv[0]) == '__main__.py':
|
||||||
|
@ -43,6 +45,20 @@ def detect_variant():
|
||||||
return 'unknown'
|
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):
|
def update_self(to_screen, verbose, opener):
|
||||||
''' Exists for backward compatibility. Use run_update(ydl) instead '''
|
''' 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__})')
|
ydl.to_screen(f'yt-dlp is up to date ({__version__})')
|
||||||
return
|
return
|
||||||
|
|
||||||
ERRORS = {
|
err = is_non_updateable()
|
||||||
'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'])
|
|
||||||
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, expected=True)
|
||||||
|
|
|
@ -4521,11 +4521,10 @@ def is_outdated_version(version, limit, assume_new=True):
|
||||||
|
|
||||||
def ytdl_is_updateable():
|
def ytdl_is_updateable():
|
||||||
""" Returns if yt-dlp can be updated with -U """
|
""" 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):
|
def args_to_str(args):
|
||||||
|
|
Loading…
Reference in a new issue