mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2026-05-19 13:52:36 +00:00
[cleanup] Misc (#16452)
* Include `pin*` extras in lockfile * Fix and clean up `devscripts/update_requirements.py` * Improve release channel documentation * Remove false statement from `--prefer-insecure` documentation * Assorted code cleanup * Set `GH_TELEMETRY=false` in CI/CD whenever `gh` is used * Add comments about required checks in CI workflows * Run `test-workflows.yml` for every PR so its checks can be required * Verify actionlint attestation in CI * Remove zizmor version to reduce workflow maintenance burden (zizmor-action handles pinning on its end) Authored by: bashonly
This commit is contained in:
parent
27973bae5e
commit
35684c1171
4
.github/workflows/challenge-tests.yml
vendored
4
.github/workflows/challenge-tests.yml
vendored
@ -1,6 +1,7 @@
|
|||||||
name: Challenge Tests
|
name: Challenge Tests
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: ['master']
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/challenge-tests.yml
|
- .github/workflows/challenge-tests.yml
|
||||||
- test/test_jsc/*.py
|
- test/test_jsc/*.py
|
||||||
@ -9,6 +10,7 @@ on:
|
|||||||
- yt_dlp/extractor/youtube/pot/**.py
|
- yt_dlp/extractor/youtube/pot/**.py
|
||||||
- yt_dlp/utils/_jsruntime.py
|
- yt_dlp/utils/_jsruntime.py
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches: ['**']
|
||||||
paths:
|
paths:
|
||||||
- .github/workflows/challenge-tests.yml
|
- .github/workflows/challenge-tests.yml
|
||||||
- test/test_jsc/*.py
|
- test/test_jsc/*.py
|
||||||
@ -25,7 +27,7 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: Challenge Tests
|
name: Challenge tests
|
||||||
if: ${{ !contains(github.event.head_commit.message, ':ci skip') }}
|
if: ${{ !contains(github.event.head_commit.message, ':ci skip') }}
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
4
.github/workflows/core.yml
vendored
4
.github/workflows/core.yml
vendored
@ -1,6 +1,7 @@
|
|||||||
name: Core Tests
|
name: Core Tests
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: ['master']
|
||||||
paths:
|
paths:
|
||||||
- pyproject.toml
|
- pyproject.toml
|
||||||
- .github/**
|
- .github/**
|
||||||
@ -13,6 +14,7 @@ on:
|
|||||||
- yt_dlp/extractor/common.py
|
- yt_dlp/extractor/common.py
|
||||||
- yt_dlp/extractor/extractors.py
|
- yt_dlp/extractor/extractors.py
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches: ['**']
|
||||||
paths:
|
paths:
|
||||||
- pyproject.toml
|
- pyproject.toml
|
||||||
- .github/**
|
- .github/**
|
||||||
@ -33,7 +35,7 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: Core Tests
|
name: Core tests
|
||||||
if: ${{ !contains(github.event.head_commit.message, ':ci skip') }}
|
if: ${{ !contains(github.event.head_commit.message, ':ci skip') }}
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
7
.github/workflows/issue-lockdown.yml
vendored
7
.github/workflows/issue-lockdown.yml
vendored
@ -5,9 +5,12 @@ on:
|
|||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_TELEMETRY: "false"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lockdown:
|
lockdown:
|
||||||
name: Issue Lockdown
|
name: Issue lockdown
|
||||||
if: vars.ISSUE_LOCKDOWN
|
if: vars.ISSUE_LOCKDOWN
|
||||||
permissions:
|
permissions:
|
||||||
issues: write # Needed to lock issues
|
issues: write # Needed to lock issues
|
||||||
@ -19,4 +22,4 @@ jobs:
|
|||||||
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
ISSUE_NUMBER: ${{ github.event.issue.number }}
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
run: |
|
run: |
|
||||||
gh issue lock "${ISSUE_NUMBER}" -R "${REPOSITORY}"
|
gh issue lock -R "${REPOSITORY}" "${ISSUE_NUMBER}"
|
||||||
|
|||||||
14
.github/workflows/quick-test.yml
vendored
14
.github/workflows/quick-test.yml
vendored
@ -1,5 +1,10 @@
|
|||||||
name: Quick Test
|
name: Quick Test
|
||||||
on: [push, pull_request]
|
on:
|
||||||
|
push:
|
||||||
|
branches: ['master']
|
||||||
|
# This workflow contains required checks and needs to run for EVERY pull_request
|
||||||
|
pull_request:
|
||||||
|
branches: ['**']
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
@ -9,7 +14,8 @@ concurrency:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: Core Test
|
# Required check; do not change name
|
||||||
|
name: Core test
|
||||||
if: ${{ !contains(github.event.head_commit.message, ':ci skip all') }}
|
if: ${{ !contains(github.event.head_commit.message, ':ci skip all') }}
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@ -31,7 +37,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
python3 -m yt_dlp -v || true
|
python3 -m yt_dlp -v || true
|
||||||
python3 ./devscripts/run_tests.py --pytest-args '--reruns 2 --reruns-delay 3.0' core
|
python3 ./devscripts/run_tests.py --pytest-args '--reruns 2 --reruns-delay 3.0' core
|
||||||
|
|
||||||
check:
|
check:
|
||||||
|
# Required check; do not change name
|
||||||
name: Code check
|
name: Code check
|
||||||
if: ${{ !contains(github.event.head_commit.message, ':ci skip all') }}
|
if: ${{ !contains(github.event.head_commit.message, ':ci skip all') }}
|
||||||
permissions:
|
permissions:
|
||||||
@ -43,7 +51,7 @@ jobs:
|
|||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.10'
|
python-version: '3.14'
|
||||||
- name: Install dev dependencies
|
- name: Install dev dependencies
|
||||||
run: python ./devscripts/install_deps.py --omit-default --include-group static-analysis
|
run: python ./devscripts/install_deps.py --omit-default --include-group static-analysis
|
||||||
- name: Make lazy extractors
|
- name: Make lazy extractors
|
||||||
|
|||||||
2
.github/workflows/release-master.yml
vendored
2
.github/workflows/release-master.yml
vendored
@ -19,7 +19,7 @@ permissions: {}
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Publish Github release
|
name: Publish GitHub release
|
||||||
if: vars.BUILD_MASTER
|
if: vars.BUILD_MASTER
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # May be needed to publish release
|
contents: write # May be needed to publish release
|
||||||
|
|||||||
2
.github/workflows/release-nightly.yml
vendored
2
.github/workflows/release-nightly.yml
vendored
@ -70,7 +70,7 @@ jobs:
|
|||||||
run: echo "${HEAD}" | tee .nightly_commit_hash
|
run: echo "${HEAD}" | tee .nightly_commit_hash
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Publish Github release
|
name: Publish GitHub release
|
||||||
needs: [check_nightly]
|
needs: [check_nightly]
|
||||||
if: needs.check_nightly.outputs.commit
|
if: needs.check_nightly.outputs.commit
|
||||||
permissions:
|
permissions:
|
||||||
|
|||||||
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@ -65,6 +65,9 @@ on:
|
|||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_TELEMETRY: "false"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
prepare:
|
prepare:
|
||||||
name: Prepare
|
name: Prepare
|
||||||
@ -226,7 +229,7 @@ jobs:
|
|||||||
verbose: true
|
verbose: true
|
||||||
|
|
||||||
publish:
|
publish:
|
||||||
name: Publish Github release
|
name: Publish GitHub release
|
||||||
needs: [prepare, build]
|
needs: [prepare, build]
|
||||||
permissions:
|
permissions:
|
||||||
contents: write # Needed by gh to publish release to Github
|
contents: write # Needed by gh to publish release to Github
|
||||||
|
|||||||
38
.github/workflows/test-workflows.yml
vendored
38
.github/workflows/test-workflows.yml
vendored
@ -1,23 +1,10 @@
|
|||||||
name: Test and lint workflows
|
name: Test and lint workflows
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches: ['master']
|
||||||
paths:
|
# This workflow contains required checks and needs to run for EVERY pull_request
|
||||||
- .github/*.yml
|
|
||||||
- .github/workflows/*
|
|
||||||
- bundle/docker/linux/*.sh
|
|
||||||
- devscripts/setup_variables.py
|
|
||||||
- devscripts/setup_variables_tests.py
|
|
||||||
- devscripts/utils.py
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [master]
|
branches: ['**']
|
||||||
paths:
|
|
||||||
- .github/*.yml
|
|
||||||
- .github/workflows/*
|
|
||||||
- bundle/docker/linux/*.sh
|
|
||||||
- devscripts/setup_variables.py
|
|
||||||
- devscripts/setup_variables_tests.py
|
|
||||||
- devscripts/utils.py
|
|
||||||
|
|
||||||
permissions: {}
|
permissions: {}
|
||||||
|
|
||||||
@ -28,10 +15,12 @@ concurrency:
|
|||||||
env:
|
env:
|
||||||
ACTIONLINT_VERSION: "1.7.11"
|
ACTIONLINT_VERSION: "1.7.11"
|
||||||
ACTIONLINT_SHA256SUM: 900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a
|
ACTIONLINT_SHA256SUM: 900919a84f2229bac68ca9cd4103ea297abc35e9689ebb842c6e34a3d1b01b0a
|
||||||
ACTIONLINT_REPO: https://github.com/rhysd/actionlint
|
ACTIONLINT_REPO: rhysd/actionlint
|
||||||
|
GH_TELEMETRY: "false"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
|
# Required check; do not change name
|
||||||
name: Check workflows
|
name: Check workflows
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@ -45,19 +34,26 @@ jobs:
|
|||||||
python-version: "3.13" # Keep this in sync with release.yml's prepare job
|
python-version: "3.13" # Keep this in sync with release.yml's prepare job
|
||||||
- name: Install requirements
|
- name: Install requirements
|
||||||
env:
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
ACTIONLINT_TARBALL: ${{ format('actionlint_{0}_linux_amd64.tar.gz', env.ACTIONLINT_VERSION) }}
|
ACTIONLINT_TARBALL: ${{ format('actionlint_{0}_linux_amd64.tar.gz', env.ACTIONLINT_VERSION) }}
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
python -m devscripts.install_deps --omit-default --include-group test
|
python -m devscripts.install_deps --omit-default --include-group test
|
||||||
sudo apt -y install shellcheck
|
sudo apt -y install shellcheck
|
||||||
python -m pip install -U pyflakes
|
python -m pip install -U pyflakes
|
||||||
curl -LO "${ACTIONLINT_REPO}/releases/download/v${ACTIONLINT_VERSION}/${ACTIONLINT_TARBALL}"
|
gh release download \
|
||||||
|
--repo "${ACTIONLINT_REPO}" \
|
||||||
|
--pattern "${ACTIONLINT_TARBALL}" \
|
||||||
|
"v${ACTIONLINT_VERSION}"
|
||||||
|
gh attestation verify \
|
||||||
|
--repo "${ACTIONLINT_REPO}" \
|
||||||
|
"${ACTIONLINT_TARBALL}"
|
||||||
printf '%s %s' "${ACTIONLINT_SHA256SUM}" "${ACTIONLINT_TARBALL}" | sha256sum -c -
|
printf '%s %s' "${ACTIONLINT_SHA256SUM}" "${ACTIONLINT_TARBALL}" | sha256sum -c -
|
||||||
tar xvzf "${ACTIONLINT_TARBALL}" actionlint
|
tar xvzf "${ACTIONLINT_TARBALL}" actionlint
|
||||||
chmod +x actionlint
|
sudo install -D --mode=755 actionlint /usr/bin/
|
||||||
- name: Run actionlint
|
- name: Run actionlint
|
||||||
run: |
|
run: |
|
||||||
./actionlint -color
|
actionlint -color
|
||||||
- name: Check Docker shell scripts
|
- name: Check Docker shell scripts
|
||||||
run: |
|
run: |
|
||||||
shellcheck bundle/docker/linux/*.sh
|
shellcheck bundle/docker/linux/*.sh
|
||||||
@ -66,6 +62,7 @@ jobs:
|
|||||||
pytest -Werror --tb=short --color=yes devscripts/setup_variables_tests.py
|
pytest -Werror --tb=short --color=yes devscripts/setup_variables_tests.py
|
||||||
|
|
||||||
zizmor:
|
zizmor:
|
||||||
|
# Required check; do not change name
|
||||||
name: Run zizmor
|
name: Run zizmor
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
@ -80,4 +77,3 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
advanced-security: false
|
advanced-security: false
|
||||||
persona: pedantic
|
persona: pedantic
|
||||||
version: v1.23.1
|
|
||||||
|
|||||||
7
Makefile
7
Makefile
@ -3,7 +3,7 @@ all-extra: lazy-extractors yt-dlp-extra doc pypi-files
|
|||||||
clean: clean-test clean-dist
|
clean: clean-test clean-dist
|
||||||
clean-all: clean clean-cache
|
clean-all: clean clean-cache
|
||||||
completions: completion-bash completion-fish completion-zsh
|
completions: completion-bash completion-fish completion-zsh
|
||||||
doc: README.md CONTRIBUTING.md CONTRIBUTORS issuetemplates supportedsites
|
doc: README.md CONTRIBUTORS issuetemplates supportedsites
|
||||||
ot: offlinetest
|
ot: offlinetest
|
||||||
tar: yt-dlp.tar.gz
|
tar: yt-dlp.tar.gz
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ clean-test:
|
|||||||
test/testdata/sigs/player-*.js test/testdata/thumbnails/empty.webp "test/testdata/thumbnails/foo %d bar/foo_%d."*
|
test/testdata/sigs/player-*.js test/testdata/thumbnails/empty.webp "test/testdata/thumbnails/foo %d bar/foo_%d."*
|
||||||
clean-dist:
|
clean-dist:
|
||||||
rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ \
|
rm -rf yt-dlp.1.temp.md yt-dlp.1 README.txt MANIFEST build/ dist/ .coverage cover/ yt-dlp.tar.gz completions/ \
|
||||||
yt_dlp/extractor/lazy_extractors.py *.spec CONTRIBUTING.md.tmp yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS \
|
yt_dlp/extractor/lazy_extractors.py *.spec yt-dlp yt-dlp.exe yt_dlp.egg-info/ AUTHORS \
|
||||||
yt-dlp.zip .ejs-* yt_dlp_ejs/
|
yt-dlp.zip .ejs-* yt_dlp_ejs/
|
||||||
clean-cache:
|
clean-cache:
|
||||||
find . \( \
|
find . \( \
|
||||||
@ -132,9 +132,6 @@ yt-dlp: yt-dlp.zip
|
|||||||
README.md: $(PY_CODE_FILES) devscripts/make_readme.py
|
README.md: $(PY_CODE_FILES) devscripts/make_readme.py
|
||||||
COLUMNS=80 $(PYTHON) yt_dlp/__main__.py --ignore-config --help | $(PYTHON) devscripts/make_readme.py
|
COLUMNS=80 $(PYTHON) yt_dlp/__main__.py --ignore-config --help | $(PYTHON) devscripts/make_readme.py
|
||||||
|
|
||||||
CONTRIBUTING.md: README.md devscripts/make_contributing.py
|
|
||||||
$(PYTHON) devscripts/make_contributing.py README.md CONTRIBUTING.md
|
|
||||||
|
|
||||||
issuetemplates: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml .github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml .github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml yt_dlp/version.py
|
issuetemplates: devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE_tmpl/3_site_feature_request.yml .github/ISSUE_TEMPLATE_tmpl/4_bug_report.yml .github/ISSUE_TEMPLATE_tmpl/5_feature_request.yml yt_dlp/version.py
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE/1_broken_site.yml
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/1_broken_site.yml .github/ISSUE_TEMPLATE/1_broken_site.yml
|
||||||
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE/2_site_support_request.yml
|
$(PYTHON) devscripts/make_issue_template.py .github/ISSUE_TEMPLATE_tmpl/2_site_support_request.yml .github/ISSUE_TEMPLATE/2_site_support_request.yml
|
||||||
|
|||||||
@ -167,9 +167,9 @@ For other third-party package managers, see [the wiki](https://github.com/yt-dlp
|
|||||||
|
|
||||||
There are currently three release channels for binaries: `stable`, `nightly` and `master`.
|
There are currently three release channels for binaries: `stable`, `nightly` and `master`.
|
||||||
|
|
||||||
* `stable` is the default channel, and many of its changes have been tested by users of the `nightly` and `master` channels.
|
* `stable` is the default channel, which offers releases published on a (mostly) monthly schedule. While it is named `stable` due to many of its changes having been tested by users of the `nightly` or `master` release channels, the latest `stable` release is often "stale" and prone to external breakage (i.e. sites changing things on their end and breaking yt-dlp).
|
||||||
* The `nightly` channel has releases scheduled to build every day around midnight UTC, for a snapshot of the project's new patches and changes. This is the **recommended channel for regular users** of yt-dlp. The `nightly` releases are available from [yt-dlp/yt-dlp-nightly-builds](https://github.com/yt-dlp/yt-dlp-nightly-builds/releases) or as development releases of the `yt-dlp` PyPI package (which can be installed with pip's `--pre` flag).
|
* The `nightly` channel offers releases that publish shortly before midnight UTC on any day that sees changes to the codebase. This channel serves as a snapshot of the project's development, and it is the **recommended channel for regular users** of yt-dlp. The `nightly` releases are available from [yt-dlp/yt-dlp-nightly-builds](https://github.com/yt-dlp/yt-dlp-nightly-builds/releases) or as development releases of the `yt-dlp` PyPI package (which can be installed with pip's `--pre` flag).
|
||||||
* The `master` channel features releases that are built after each push to the master branch, and these will have the very latest fixes and additions, but may also be more prone to regressions. They are available from [yt-dlp/yt-dlp-master-builds](https://github.com/yt-dlp/yt-dlp-master-builds/releases).
|
* The `master` channel offers "canary" releases that publish after each push to the master branch. This channel will always provide the very latest fixes and features, but may be prone to bugs or regressions. The `master` releases are available from [yt-dlp/yt-dlp-master-builds](https://github.com/yt-dlp/yt-dlp-master-builds/releases).
|
||||||
|
|
||||||
When using `--update`/`-U`, a release binary will only update to its current channel.
|
When using `--update`/`-U`, a release binary will only update to its current channel.
|
||||||
`--update-to CHANNEL` can be used to switch to a different channel when a newer version is available. `--update-to [CHANNEL@]TAG` can also be used to upgrade or downgrade to specific tags from a channel.
|
`--update-to CHANNEL` can be used to switch to a different channel when a newer version is available. `--update-to [CHANNEL@]TAG` can also be used to upgrade or downgrade to specific tags from a channel.
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import optparse
|
|
||||||
import re
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
return # This is unused in yt-dlp
|
|
||||||
|
|
||||||
parser = optparse.OptionParser(usage='%prog INFILE OUTFILE')
|
|
||||||
_, args = parser.parse_args()
|
|
||||||
if len(args) != 2:
|
|
||||||
parser.error('Expected an input and an output filename')
|
|
||||||
|
|
||||||
infile, outfile = args
|
|
||||||
|
|
||||||
with open(infile, encoding='utf-8') as inf:
|
|
||||||
readme = inf.read()
|
|
||||||
|
|
||||||
bug_text = re.search(
|
|
||||||
r'(?s)#\s*BUGS\s*[^\n]*\s*(.*?)#\s*COPYRIGHT', readme).group(1)
|
|
||||||
dev_text = re.search(
|
|
||||||
r'(?s)(#\s*DEVELOPER INSTRUCTIONS.*?)#\s*EMBEDDING yt-dlp', readme).group(1)
|
|
||||||
|
|
||||||
out = bug_text + dev_text
|
|
||||||
|
|
||||||
with open(outfile, 'w', encoding='utf-8') as outf:
|
|
||||||
outf.write(out)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@ -47,12 +47,6 @@ PINNED_EXTRAS = {
|
|||||||
'pin-deno': 'deno',
|
'pin-deno': 'deno',
|
||||||
}
|
}
|
||||||
|
|
||||||
WELLKNOWN_PACKAGES = {
|
|
||||||
'deno': {'owner': 'denoland', 'repo': 'deno'},
|
|
||||||
'protobug': {'owner': 'yt-dlp', 'repo': 'protobug'},
|
|
||||||
'yt-dlp-ejs': {'owner': 'yt-dlp', 'repo': 'ejs'},
|
|
||||||
}
|
|
||||||
|
|
||||||
EJS_ASSETS = {
|
EJS_ASSETS = {
|
||||||
'yt.solver.lib.js': False,
|
'yt.solver.lib.js': False,
|
||||||
'yt.solver.lib.min.js': False,
|
'yt.solver.lib.min.js': False,
|
||||||
@ -120,10 +114,15 @@ PYINSTALLER_BUILDS_TARGETS = {
|
|||||||
'win-arm64-pyinstaller': 'win_arm64',
|
'win-arm64-pyinstaller': 'win_arm64',
|
||||||
}
|
}
|
||||||
|
|
||||||
PYINSTALLER_BUILDS_TMPL = '''\
|
WELLKNOWN_PACKAGES = {
|
||||||
{}pyinstaller @ {} \\
|
'deno': {'owner': 'denoland', 'repo': 'deno'},
|
||||||
--hash={}
|
'protobug': {'owner': 'yt-dlp', 'repo': 'protobug'},
|
||||||
'''
|
'yt-dlp-ejs': {'owner': 'yt-dlp', 'repo': 'ejs'},
|
||||||
|
**{
|
||||||
|
f'pyinstaller[{asset_tag}]': {'owner': 'pyinstaller', 'repo': 'pyinstaller'}
|
||||||
|
for asset_tag in PYINSTALLER_BUILDS_TARGETS.values()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def call_pypi_api(project: str) -> dict[str, dict[str, typing.Any]]:
|
def call_pypi_api(project: str) -> dict[str, dict[str, typing.Any]]:
|
||||||
@ -447,7 +446,7 @@ def parse_version_from_dist(filename: str, name: str, *, require: bool = False)
|
|||||||
normalized_name = re.sub(r'[-_.]+', '-', name).lower().replace('-', '_')
|
normalized_name = re.sub(r'[-_.]+', '-', name).lower().replace('-', '_')
|
||||||
|
|
||||||
# Ref: https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers
|
# Ref: https://packaging.python.org/en/latest/specifications/version-specifiers/#version-specifiers
|
||||||
if mobj := re.match(rf'{normalized_name}-(?P<version>[^-]+)-', filename):
|
if mobj := re.fullmatch(rf'{normalized_name}-(?P<version>[^-]+)(?:-.+\.whl|\.tar\.gz)', filename):
|
||||||
return mobj.group('version')
|
return mobj.group('version')
|
||||||
|
|
||||||
if require:
|
if require:
|
||||||
@ -579,27 +578,33 @@ def update_requirements(
|
|||||||
all_updates = package_diff_dict(old_packages, new_packages)
|
all_updates = package_diff_dict(old_packages, new_packages)
|
||||||
|
|
||||||
# Update Windows PyInstaller requirements; need to compare before & after .txt's for reporting
|
# Update Windows PyInstaller requirements; need to compare before & after .txt's for reporting
|
||||||
if not upgrade_only or upgrade_only.lower() == 'pyinstaller':
|
if not upgrade_only:
|
||||||
info = fetch_latest_github_release('yt-dlp', 'Pyinstaller-Builds')
|
info = fetch_latest_github_release('yt-dlp', 'Pyinstaller-Builds')
|
||||||
for target_suffix, asset_tag in PYINSTALLER_BUILDS_TARGETS.items():
|
for target_suffix, asset_tag in PYINSTALLER_BUILDS_TARGETS.items():
|
||||||
asset_info = next(asset for asset in info['assets'] if asset_tag in asset['name'])
|
asset_info = next(asset for asset in info['assets'] if asset_tag in asset['name'])
|
||||||
pyinstaller_version = parse_version_from_dist(
|
|
||||||
asset_info['name'], 'pyinstaller', require=True)
|
|
||||||
pyinstaller_builds_deps = run_pip_compile(
|
|
||||||
'--no-emit-package=pyinstaller',
|
|
||||||
upgrade_arg,
|
|
||||||
input_line=f'pyinstaller=={pyinstaller_version}',
|
|
||||||
env=env)
|
|
||||||
requirements_path = REQUIREMENTS_PATH / REQS_OUTPUT_TMPL.format(target_suffix)
|
requirements_path = REQUIREMENTS_PATH / REQS_OUTPUT_TMPL.format(target_suffix)
|
||||||
if requirements_path.is_file():
|
if requirements_path.is_file():
|
||||||
old_requirements_txt = requirements_path.read_text()
|
old_requirements_txt = requirements_path.read_text()
|
||||||
else:
|
else:
|
||||||
old_requirements_txt = ''
|
old_requirements_txt = ''
|
||||||
|
|
||||||
new_requirements_txt = PYINSTALLER_BUILDS_TMPL.format(
|
run_pip_compile(
|
||||||
pyinstaller_builds_deps, asset_info['browser_download_url'], asset_info['digest'])
|
upgrade_arg,
|
||||||
requirements_path.write_text(new_requirements_txt)
|
input_line=f'pyinstaller @ {asset_info["browser_download_url"]}',
|
||||||
all_updates.update(evaluate_requirements_txt(old_requirements_txt, new_requirements_txt))
|
output_file=requirements_path,
|
||||||
|
env=env)
|
||||||
|
|
||||||
|
new_requirements_txt = requirements_path.read_text()
|
||||||
|
if asset_info['digest'] not in new_requirements_txt:
|
||||||
|
raise ValueError(
|
||||||
|
f'expected pyinstaller wheel hash {asset_info["digest"]} '
|
||||||
|
f'not found in {requirements_path}')
|
||||||
|
|
||||||
|
diff_dict = evaluate_requirements_txt(old_requirements_txt, new_requirements_txt)
|
||||||
|
if pyinstaller_diff := diff_dict.get('pyinstaller'):
|
||||||
|
# NB: this depends on 'pyinstaller[asset_tag]' keys in WELLKNOWN_PACKAGES
|
||||||
|
all_updates.update({f'pyinstaller[{asset_tag}]': pyinstaller_diff})
|
||||||
|
|
||||||
# Export bundle requirements; any updates to these are already recorded w/ uv.lock package diff
|
# Export bundle requirements; any updates to these are already recorded w/ uv.lock package diff
|
||||||
for target_suffix, target in BUNDLE_TARGETS.items():
|
for target_suffix, target in BUNDLE_TARGETS.items():
|
||||||
@ -640,6 +645,10 @@ def update_requirements(
|
|||||||
# Write the finalized pyproject.toml
|
# Write the finalized pyproject.toml
|
||||||
modify_and_write_pyproject(pyproject_text, table_name=EXTRAS_TABLE, table=extras)
|
modify_and_write_pyproject(pyproject_text, table_name=EXTRAS_TABLE, table=extras)
|
||||||
|
|
||||||
|
# Generate/upgrade final lockfile that includes pinned extras
|
||||||
|
print(f'Running: uv lock {upgrade_arg}', file=sys.stderr)
|
||||||
|
run_process('uv', 'lock', upgrade_arg, env=env)
|
||||||
|
|
||||||
return all_updates
|
return all_updates
|
||||||
|
|
||||||
|
|
||||||
@ -682,7 +691,9 @@ def generate_report(
|
|||||||
|
|
||||||
if offset is not None:
|
if offset is not None:
|
||||||
md_old = '.'.join(old_parts[:offset]) + '.***' + '.'.join(old_parts[offset:]) + '***'
|
md_old = '.'.join(old_parts[:offset]) + '.***' + '.'.join(old_parts[offset:]) + '***'
|
||||||
|
md_old = md_old.lstrip('.')
|
||||||
md_new = '.'.join(new_parts[:offset]) + '.***' + '.'.join(new_parts[offset:]) + '***'
|
md_new = '.'.join(new_parts[:offset]) + '.***' + '.'.join(new_parts[offset:]) + '***'
|
||||||
|
md_new = md_new.lstrip('.')
|
||||||
|
|
||||||
compare = ''
|
compare = ''
|
||||||
if github_info:
|
if github_info:
|
||||||
@ -692,14 +703,15 @@ def generate_report(
|
|||||||
new_tag = tags_info.get(new) and tags_info[new]['name']
|
new_tag = tags_info.get(new) and tags_info[new]['name']
|
||||||
github_url = 'https://github.com/{owner}/{repo}'.format(**github_info)
|
github_url = 'https://github.com/{owner}/{repo}'.format(**github_info)
|
||||||
if new_tag:
|
if new_tag:
|
||||||
md_new = f'[{md_new}]({github_url}/releases/tag/{new_tag})'
|
md_new = f'[{md_new}](<{github_url}/releases/tag/{new_tag}>)'
|
||||||
if old_tag:
|
if old_tag:
|
||||||
md_old = f'[{md_old}]({github_url}/releases/tag/{old_tag})'
|
md_old = f'[{md_old}](<{github_url}/releases/tag/{old_tag}>)'
|
||||||
if new_tag and old_tag:
|
if new_tag and old_tag:
|
||||||
compare = f'[`{old_tag}...{new_tag}`]({github_url}/compare/{old_tag}...{new_tag})'
|
compare = f'[`{old_tag}...{new_tag}`](<{github_url}/compare/{old_tag}...{new_tag}>)'
|
||||||
|
|
||||||
yield ' | '.join((
|
yield ' | '.join((
|
||||||
f'[**`{package}`**](https://pypi.org/project/{package})',
|
# Strip the [win*] tag from package in the URL (e.g. pyinstaller[win32])
|
||||||
|
f'[**`{package}`**](<https://pypi.org/project/{package.split("[")[0]}/>)',
|
||||||
md_old,
|
md_old,
|
||||||
md_new,
|
md_new,
|
||||||
compare,
|
compare,
|
||||||
|
|||||||
@ -180,9 +180,6 @@ exclude = [
|
|||||||
path = "yt_dlp/version.py"
|
path = "yt_dlp/version.py"
|
||||||
pattern = "_pkg_version = '(?P<version>[^']+)'"
|
pattern = "_pkg_version = '(?P<version>[^']+)'"
|
||||||
|
|
||||||
[tool.hatch.metadata]
|
|
||||||
allow-direct-references = true
|
|
||||||
|
|
||||||
[tool.hatch.envs.default]
|
[tool.hatch.envs.default]
|
||||||
features = [
|
features = [
|
||||||
"curl-cffi",
|
"curl-cffi",
|
||||||
|
|||||||
66
uv.lock
generated
66
uv.lock
generated
@ -1166,6 +1166,42 @@ default = [
|
|||||||
deno = [
|
deno = [
|
||||||
{ name = "deno" },
|
{ name = "deno" },
|
||||||
]
|
]
|
||||||
|
pin = [
|
||||||
|
{ name = "brotli", marker = "implementation_name == 'cpython' and sys_platform != 'ios'" },
|
||||||
|
{ name = "brotlicffi", marker = "implementation_name != 'cpython'" },
|
||||||
|
{ name = "certifi" },
|
||||||
|
{ name = "cffi", marker = "implementation_name != 'cpython'" },
|
||||||
|
{ name = "charset-normalizer" },
|
||||||
|
{ name = "idna" },
|
||||||
|
{ name = "mutagen" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy' and implementation_name != 'cpython'" },
|
||||||
|
{ name = "pycryptodomex" },
|
||||||
|
{ name = "requests" },
|
||||||
|
{ name = "urllib3" },
|
||||||
|
{ name = "websockets" },
|
||||||
|
{ name = "yt-dlp-ejs" },
|
||||||
|
]
|
||||||
|
pin-curl-cffi = [
|
||||||
|
{ name = "certifi", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "cffi", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "curl-cffi", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "markdown-it-py", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "mdurl", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "pygments", marker = "implementation_name == 'cpython'" },
|
||||||
|
{ name = "rich", marker = "implementation_name == 'cpython'" },
|
||||||
|
]
|
||||||
|
pin-deno = [
|
||||||
|
{ name = "deno" },
|
||||||
|
]
|
||||||
|
pin-secretstorage = [
|
||||||
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
|
{ name = "cryptography" },
|
||||||
|
{ name = "jeepney" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy' and platform_python_implementation != 'PyPy'" },
|
||||||
|
{ name = "secretstorage" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||||
|
]
|
||||||
secretstorage = [
|
secretstorage = [
|
||||||
{ name = "secretstorage" },
|
{ name = "secretstorage" },
|
||||||
]
|
]
|
||||||
@ -1200,19 +1236,47 @@ test = [
|
|||||||
[package.metadata]
|
[package.metadata]
|
||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "brotli", marker = "implementation_name == 'cpython' and sys_platform != 'ios' and extra == 'default'" },
|
{ name = "brotli", marker = "implementation_name == 'cpython' and sys_platform != 'ios' and extra == 'default'" },
|
||||||
|
{ name = "brotli", marker = "implementation_name == 'cpython' and sys_platform != 'ios' and extra == 'pin'", specifier = "==1.2.0" },
|
||||||
{ name = "brotlicffi", marker = "implementation_name != 'cpython' and extra == 'default'" },
|
{ name = "brotlicffi", marker = "implementation_name != 'cpython' and extra == 'default'" },
|
||||||
|
{ name = "brotlicffi", marker = "implementation_name != 'cpython' and extra == 'pin'", specifier = "==1.2.0.1" },
|
||||||
|
{ name = "certifi", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==2026.2.25" },
|
||||||
{ name = "certifi", marker = "extra == 'default'" },
|
{ name = "certifi", marker = "extra == 'default'" },
|
||||||
|
{ name = "certifi", marker = "extra == 'pin'", specifier = "==2026.2.25" },
|
||||||
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy' and extra == 'pin-secretstorage'", specifier = "==2.0.0" },
|
||||||
|
{ name = "cffi", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==2.0.0" },
|
||||||
|
{ name = "cffi", marker = "implementation_name != 'cpython' and extra == 'pin'", specifier = "==2.0.0" },
|
||||||
|
{ name = "charset-normalizer", marker = "extra == 'pin'", specifier = "==3.4.6" },
|
||||||
|
{ name = "cryptography", marker = "extra == 'pin-secretstorage'", specifier = "==46.0.6" },
|
||||||
{ name = "curl-cffi", marker = "implementation_name == 'cpython' and extra == 'curl-cffi'", specifier = ">=0.5.10,!=0.6.*,!=0.7.*,!=0.8.*,!=0.9.*,<0.16" },
|
{ name = "curl-cffi", marker = "implementation_name == 'cpython' and extra == 'curl-cffi'", specifier = ">=0.5.10,!=0.6.*,!=0.7.*,!=0.8.*,!=0.9.*,<0.16" },
|
||||||
|
{ name = "curl-cffi", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==0.15.0" },
|
||||||
{ name = "deno", marker = "extra == 'deno'", specifier = ">=2.6.6" },
|
{ name = "deno", marker = "extra == 'deno'", specifier = ">=2.6.6" },
|
||||||
|
{ name = "deno", marker = "extra == 'pin-deno'", specifier = "==2.7.8" },
|
||||||
|
{ name = "idna", marker = "extra == 'pin'", specifier = "==3.11" },
|
||||||
|
{ name = "jeepney", marker = "extra == 'pin-secretstorage'", specifier = "==0.9.0" },
|
||||||
|
{ name = "markdown-it-py", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==4.0.0" },
|
||||||
|
{ name = "mdurl", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==0.1.2" },
|
||||||
{ name = "mutagen", marker = "extra == 'default'" },
|
{ name = "mutagen", marker = "extra == 'default'" },
|
||||||
|
{ name = "mutagen", marker = "extra == 'pin'", specifier = "==1.47.0" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy' and platform_python_implementation != 'PyPy' and extra == 'pin-secretstorage'", specifier = "==3.0" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name != 'PyPy' and implementation_name != 'cpython' and extra == 'pin'", specifier = "==3.0" },
|
||||||
|
{ name = "pycparser", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==3.0" },
|
||||||
{ name = "pycryptodomex", marker = "extra == 'default'" },
|
{ name = "pycryptodomex", marker = "extra == 'default'" },
|
||||||
|
{ name = "pycryptodomex", marker = "extra == 'pin'", specifier = "==3.23.0" },
|
||||||
|
{ name = "pygments", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==2.19.2" },
|
||||||
{ name = "requests", marker = "extra == 'default'", specifier = ">=2.32.2,<3" },
|
{ name = "requests", marker = "extra == 'default'", specifier = ">=2.32.2,<3" },
|
||||||
|
{ name = "requests", marker = "extra == 'pin'", specifier = "==2.33.0" },
|
||||||
|
{ name = "rich", marker = "implementation_name == 'cpython' and extra == 'pin-curl-cffi'", specifier = "==14.3.3" },
|
||||||
|
{ name = "secretstorage", marker = "extra == 'pin-secretstorage'", specifier = "==3.5.0" },
|
||||||
{ name = "secretstorage", marker = "extra == 'secretstorage'" },
|
{ name = "secretstorage", marker = "extra == 'secretstorage'" },
|
||||||
|
{ name = "typing-extensions", marker = "python_full_version < '3.11' and extra == 'pin-secretstorage'", specifier = "==4.15.0" },
|
||||||
{ name = "urllib3", marker = "extra == 'default'", specifier = ">=2.0.2,<3" },
|
{ name = "urllib3", marker = "extra == 'default'", specifier = ">=2.0.2,<3" },
|
||||||
|
{ name = "urllib3", marker = "extra == 'pin'", specifier = "==2.6.3" },
|
||||||
{ name = "websockets", marker = "extra == 'default'", specifier = ">=13.0" },
|
{ name = "websockets", marker = "extra == 'default'", specifier = ">=13.0" },
|
||||||
|
{ name = "websockets", marker = "extra == 'pin'", specifier = "==16.0" },
|
||||||
{ name = "yt-dlp-ejs", marker = "extra == 'default'", specifier = "==0.8.0" },
|
{ name = "yt-dlp-ejs", marker = "extra == 'default'", specifier = "==0.8.0" },
|
||||||
|
{ name = "yt-dlp-ejs", marker = "extra == 'pin'", specifier = "==0.8.0" },
|
||||||
]
|
]
|
||||||
provides-extras = ["curl-cffi", "default", "deno", "secretstorage"]
|
provides-extras = ["curl-cffi", "default", "deno", "pin", "pin-curl-cffi", "pin-deno", "pin-secretstorage", "secretstorage"]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
build = [
|
build = [
|
||||||
|
|||||||
@ -3,9 +3,7 @@ import collections
|
|||||||
import contextlib
|
import contextlib
|
||||||
import functools
|
import functools
|
||||||
import getpass
|
import getpass
|
||||||
import http.client
|
|
||||||
import http.cookiejar
|
import http.cookiejar
|
||||||
import http.cookies
|
|
||||||
import inspect
|
import inspect
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
|
|||||||
@ -1322,7 +1322,7 @@ class PeerTubeIE(InfoExtractor):
|
|||||||
)
|
)
|
||||||
(?P<id>{_UUID_RE})
|
(?P<id>{_UUID_RE})
|
||||||
'''
|
'''
|
||||||
_EMBED_REGEX = [r'''(?x)<iframe[^>]+\bsrc=["\'](?P<url>(?:https?:)?//{_INSTANCES_RE}/videos/embed/{cls._UUID_RE})''']
|
_EMBED_REGEX = [rf'''(?x)<iframe[^>]+\bsrc=["\'](?P<url>(?:https?:)?//{_INSTANCES_RE}/videos/embed/{_UUID_RE})''']
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d',
|
'url': 'https://framatube.org/videos/watch/9c9de5e8-0a1e-484a-b099-e80766180a6d',
|
||||||
'md5': '8563064d245a4be5705bddb22bb00a28',
|
'md5': '8563064d245a4be5705bddb22bb00a28',
|
||||||
|
|||||||
@ -1180,7 +1180,7 @@ def create_parser():
|
|||||||
workarounds.add_option(
|
workarounds.add_option(
|
||||||
'--prefer-insecure', '--prefer-unsecure',
|
'--prefer-insecure', '--prefer-unsecure',
|
||||||
action='store_true', dest='prefer_insecure',
|
action='store_true', dest='prefer_insecure',
|
||||||
help='Use an unencrypted connection to retrieve information about the video (Currently supported only for YouTube)')
|
help='Use an unencrypted connection to retrieve information about the video')
|
||||||
workarounds.add_option(
|
workarounds.add_option(
|
||||||
'--user-agent',
|
'--user-agent',
|
||||||
metavar='UA', dest='user_agent',
|
metavar='UA', dest='user_agent',
|
||||||
|
|||||||
@ -41,12 +41,12 @@ def _find_exe(basename: str) -> str:
|
|||||||
else:
|
else:
|
||||||
exts = tuple(ext for ext in pathext.split(os.pathsep) if ext)
|
exts = tuple(ext for ext in pathext.split(os.pathsep) if ext)
|
||||||
|
|
||||||
visited = []
|
visited = set()
|
||||||
for path in map(os.path.realpath, paths):
|
for path in map(os.path.realpath, paths):
|
||||||
normed = os.path.normcase(path)
|
normed = os.path.normcase(path)
|
||||||
if normed in visited:
|
if normed in visited:
|
||||||
continue
|
continue
|
||||||
visited.append(normed)
|
visited.add(normed)
|
||||||
|
|
||||||
for ext in exts:
|
for ext in exts:
|
||||||
binary = os.path.join(path, f'{basename}{ext}')
|
binary = os.path.join(path, f'{basename}{ext}')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user