diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b9d901c3..6901aff00 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,6 +15,9 @@ on: linux: default: true type: boolean + musllinux: + default: true + type: boolean macos: default: true type: boolean @@ -50,7 +53,11 @@ on: default: true type: boolean linux: - description: yt-dlp_linux, yt-dlp_linux.zip, yt-dlp_linux_aarch64, yt-dlp_linux_aarch64.zip + description: yt-dlp_linux, yt-dlp_linux.zip, yt-dlp_linux_aarch64, yt-dlp_linux_aarch64.zip, yt-dlp_linux_armv7l + default: true + type: boolean + musllinux: + description: yt-dlp_musllinux, yt-dlp_musllinux.zip, yt-dlp_musllinux_aarch64, yt-dlp_musllinux_aarch64.zip default: true type: boolean macos: @@ -141,8 +148,16 @@ jobs: - exe: yt-dlp_linux_aarch64 platform: aarch64 runner: ubuntu-24.04-arm + - exe: yt-dlp_linux_armv7l + platform: armv7l + runner: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 + - name: Set up QEMU + if: matrix.platform == 'armv7l' + uses: docker/setup-qemu-action@v3 + with: + platforms: linux/arm/v7 - name: Build executable env: EXE_NAME: ${{ matrix.exe }} @@ -154,24 +169,67 @@ jobs: cd bundle/docker docker compose up --build linux_${{ matrix.platform }} sudo chown "${USER}:docker" ~/build/${{ matrix.exe }} - sudo chown "${USER}:docker" ~/build/${{ matrix.exe }}.zip - chmod +x ~/build/${{ matrix.exe }} - ~/build/${{ matrix.exe }} --version - name: Verify --update-to - if: vars.UPDATE_TO_VERIFICATION + if: vars.UPDATE_TO_VERIFICATION && matrix.platform != 'armv7l' run: | + chmod +x ~/build/${{ matrix.exe }} cp ~/build/${{ matrix.exe }} ~/build/${{ matrix.exe }}_downgraded version="$(~/build/${{ matrix.exe }} --version)" ~/build/${{ matrix.exe }}_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04 downgraded_version="$(~/build/${{ matrix.exe }}_downgraded --version)" + rm -f "${{ matrix.exe }}_downgraded" [[ "$version" != "$downgraded_version" ]] - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: build-bin-${{ github.job }}_${{ matrix.platform }} path: | - ~/build/${{ matrix.exe }} - ~/build/${{ matrix.exe }}.zip + ~/build/${{ matrix.exe }}* + compression-level: 0 + + musllinux: + needs: process + if: inputs.musllinux + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + - exe: yt-dlp_musllinux + platform: x86_64 + runner: ubuntu-24.04 + - exe: yt-dlp_musllinux_aarch64 + platform: aarch64 + runner: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + - name: Build executable + env: + EXE_NAME: ${{ matrix.exe }} + CHANNEL: ${{ inputs.channel }} + ORIGIN: ${{ needs.process.outputs.origin }} + VERSION: ${{ inputs.version }} + run: | + mkdir ~/build + cd bundle/docker + docker compose up --build musllinux_${{ matrix.platform }} + sudo chown "${USER}:docker" ~/build/${{ matrix.exe }} + # - name: Verify --update-to + # if: vars.UPDATE_TO_VERIFICATION + # run: | + # chmod +x ~/build/${{ matrix.exe }} + # cp ~/build/${{ matrix.exe }} ~/build/${{ matrix.exe }}_downgraded + # version="$(~/build/${{ matrix.exe }} --version)" + # ~/build/${{ matrix.exe }}_downgraded -v --update-to yt-dlp/yt-dlp@2023.03.04 + # downgraded_version="$(~/build/${{ matrix.exe }}_downgraded --version)" + # rm -f "${{ matrix.exe }}_downgraded" + # [[ "$version" != "$downgraded_version" ]] + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: build-bin-${{ github.job }}_${{ matrix.platform }} + path: | + ~/build/${{ matrix.exe }}* compression-level: 0 macos: @@ -382,6 +440,7 @@ jobs: - process - unix - linux + - musllinux - macos - windows - windows32 diff --git a/README.md b/README.md index 624ea1993..37514bf54 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,11 @@ #### Alternatives [yt-dlp_linux.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux.zip)|Unpackaged Linux (glibc 2.17+) x86_64 executable (no auto-update) [yt-dlp_linux_aarch64](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux_aarch64)|Linux (glibc 2.17+) standalone aarch64 binary [yt-dlp_linux_aarch64.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux_aarch64.zip)|Unpackaged Linux (glibc 2.17+) aarch64 executable (no auto-update) +[yt-dlp_linux_armv7l](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_linux_armv7l)|Linux (glibc 2.31+) standalone armv7l binary +[yt-dlp_musllinux](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_musllinux)|Linux (musl 1.2+) standalone x86_64 binary +[yt-dlp_musllinux.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_musllinux.zip)|Unpackaged Linux (musl 1.2+) x86_64 executable (no auto-update) +[yt-dlp_musllinux_aarch64](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_musllinux_aarch64)|Linux (musl 1.2+) standalone aarch64 binary +[yt-dlp_musllinux_aarch64.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_musllinux_aarch64.zip)|Unpackaged Linux (musl 1.2+) aarch64 executable (no auto-update) [yt-dlp_win.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_win.zip)|Unpackaged Windows (Win8+) executable (no auto-update) [yt-dlp_macos.zip](https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp_macos.zip)|Unpackaged MacOS (10.15+) executable (no auto-update) @@ -204,7 +209,7 @@ #### Impersonation * [**curl_cffi**](https://github.com/lexiforest/curl_cffi) (recommended) - Python binding for [curl-impersonate](https://github.com/lexiforest/curl-impersonate). Provides impersonation targets for Chrome, Edge and Safari. Licensed under [MIT](https://github.com/lexiforest/curl_cffi/blob/main/LICENSE) * Can be installed with the `curl-cffi` group, e.g. `pip install "yt-dlp[default,curl-cffi]"` - * Currently included in `yt-dlp.exe`, `yt-dlp_linux` and `yt-dlp_macos` builds + * Currently included in all builds *except* `yt-dlp_x86` (Windows 32-bit) and `yt-dlp` (Unix zipimport binary) ### Metadata diff --git a/bundle/docker/compose.yml b/bundle/docker/compose.yml index 30a28d666..7b116b22e 100644 --- a/bundle/docker/compose.yml +++ b/bundle/docker/compose.yml @@ -1,4 +1,5 @@ services: + linux_x86_64: build: context: linux @@ -14,6 +15,7 @@ services: volumes: - ~/build:/build - ../..:/yt-dlp + linux_aarch64: build: context: linux @@ -29,3 +31,55 @@ services: volumes: - ~/build:/build - ../..:/yt-dlp + + linux_armv7l: + build: + context: linux + platforms: + - "linux/arm/v7" + args: + BASEIMAGE: ghcr.io/bashonly/manylinux_2_31_armv7l_builds:latest + environment: + EXE_NAME: ${EXE_NAME} + CHANNEL: ${CHANNEL} + ORIGIN: ${ORIGIN} + VERSION: ${VERSION} + PIP_EXTRA_INDEX_URL: https://www.piwheels.org/simple + PIP_PREFER_BINARY: "1" + USE_PYTHON_VERSION: "3.11" + SKIP_ONEDIR_BUILD: "1" + volumes: + - ~/build:/build + - ../..:/yt-dlp + + musllinux_x86_64: + build: + context: linux + platforms: + - "linux/amd64" + args: + BASEIMAGE: ghcr.io/bashonly/musllinux_1_2_x86_64_builds:latest + environment: + EXE_NAME: ${EXE_NAME} + CHANNEL: ${CHANNEL} + ORIGIN: ${ORIGIN} + VERSION: ${VERSION} + volumes: + - ~/build:/build + - ../..:/yt-dlp + + musllinux_aarch64: + build: + context: linux + platforms: + - "linux/arm64" + args: + BASEIMAGE: ghcr.io/bashonly/musllinux_1_2_aarch64_builds:latest + environment: + EXE_NAME: ${EXE_NAME} + CHANNEL: ${CHANNEL} + ORIGIN: ${ORIGIN} + VERSION: ${VERSION} + volumes: + - ~/build:/build + - ../..:/yt-dlp diff --git a/bundle/docker/linux/entrypoint.sh b/bundle/docker/linux/entrypoint.sh index e230c5f8b..5e314cb2a 100755 --- a/bundle/docker/linux/entrypoint.sh +++ b/bundle/docker/linux/entrypoint.sh @@ -1,15 +1,27 @@ #!/bin/bash set -exuo pipefail -python3 -m venv ~/yt-dlp-build-venv +function runpy { + case ${USE_PYTHON_VERSION:-} in + "3.11") python3.11 "$@";; + "3.13") python3.13 "$@";; + *) python3 "$@";; + esac +} + +runpy -m venv ~/yt-dlp-build-venv source ~/yt-dlp-build-venv/bin/activate -python3 -m devscripts.install_deps -o --include build -python3 -m devscripts.install_deps --include secretstorage --include curl-cffi --include pyinstaller -python3 -m devscripts.make_lazy_extractors -python3 devscripts/update-version.py -c "${CHANNEL}" -r "${ORIGIN}" "${VERSION}" -python3 -m bundle.pyinstaller --onedir -pushd "./dist/${EXE_NAME}" -python3 -m zipfile -c "/build/${EXE_NAME}.zip" ./ -popd -python3 -m bundle.pyinstaller +runpy -m devscripts.install_deps -o --include build +runpy -m devscripts.install_deps --include secretstorage --include curl-cffi --include pyinstaller +runpy -m devscripts.make_lazy_extractors +runpy devscripts/update-version.py -c "${CHANNEL}" -r "${ORIGIN}" "${VERSION}" + +if [[ -z "${SKIP_ONEDIR_BUILD:-}" ]]; then + runpy -m bundle.pyinstaller --onedir + pushd "./dist/${EXE_NAME}" + runpy -m zipfile -c "/build/${EXE_NAME}.zip" ./ + popd +fi + +runpy -m bundle.pyinstaller mv "./dist/${EXE_NAME}" /build/ diff --git a/bundle/pyinstaller.py b/bundle/pyinstaller.py index 0597f602d..8286f077a 100755 --- a/bundle/pyinstaller.py +++ b/bundle/pyinstaller.py @@ -13,6 +13,8 @@ from devscripts.utils import read_version OS_NAME, MACHINE, ARCH = sys.platform, platform.machine().lower(), platform.architecture()[0][:2] +if OS_NAME == 'linux' and platform.libc_ver()[0] != 'glibc': + OS_NAME = 'musllinux' if MACHINE in ('x86', 'x86_64', 'amd64', 'i386', 'i686'): MACHINE = 'x86' if ARCH == '32' else '' diff --git a/yt_dlp/update.py b/yt_dlp/update.py index 6d66256e3..e5ca596bb 100644 --- a/yt_dlp/update.py +++ b/yt_dlp/update.py @@ -68,6 +68,10 @@ def _get_variant_and_executable_path(): machine = '_legacy' if version_tuple(platform.mac_ver()[0]) < (10, 15) else '' return f'darwin{machine}_{suffix}', path + system_platform = remove_end(sys.platform, '32') + if system_platform == 'linux' and platform.libc_ver()[0] != 'glibc': + system_platform = 'musllinux' + machine = f'_{platform.machine().lower()}' is_64bits = sys.maxsize > 2**32 # Ref: https://en.wikipedia.org/wiki/Uname#Examples @@ -82,7 +86,7 @@ def _get_variant_and_executable_path(): if static_exe_path := os.getenv('STATICX_PROG_PATH'): path = static_exe_path - return f'{remove_end(sys.platform, "32")}{machine}_{suffix}', path + return f'{system_platform}{machine}_{suffix}', path path = os.path.dirname(__file__) if isinstance(__loader__, zipimporter): @@ -117,6 +121,9 @@ def current_git_head(): 'darwin_exe': '_macos', 'linux_exe': '_linux', 'linux_aarch64_exe': '_linux_aarch64', + 'linux_armv7l_exe': '_linux_armv7l', + 'musllinux_exe': '_musllinux', + 'musllinux_aarch64_exe': '_musllinux_aarch64', } _NON_UPDATEABLE_REASONS = {