diff --git a/.github/ISSUE_TEMPLATE/1_broken_site.md b/.github/ISSUE_TEMPLATE/1_broken_site.md
index 4eb505231..e5405c235 100644
--- a/.github/ISSUE_TEMPLATE/1_broken_site.md
+++ b/.github/ISSUE_TEMPLATE/1_broken_site.md
@@ -18,7 +18,7 @@ title: ''
- [ ] I'm reporting a broken site support
-- [ ] I've verified that I'm running youtube-dl version **2021.06.06**
+- [ ] I've verified that I'm running youtube-dl version **2021.12.17**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [ ] I've searched the bugtracker for similar issues including closed ones
@@ -41,7 +41,7 @@ Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <
[debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
- [debug] youtube-dl version 2021.06.06
+ [debug] youtube-dl version 2021.12.17
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {}
diff --git a/.github/ISSUE_TEMPLATE/2_site_support_request.md b/.github/ISSUE_TEMPLATE/2_site_support_request.md
index 9fed0b489..33b01ce7f 100644
--- a/.github/ISSUE_TEMPLATE/2_site_support_request.md
+++ b/.github/ISSUE_TEMPLATE/2_site_support_request.md
@@ -19,7 +19,7 @@ labels: 'site-support-request'
- [ ] I'm reporting a new site support request
-- [ ] I've verified that I'm running youtube-dl version **2021.06.06**
+- [ ] I've verified that I'm running youtube-dl version **2021.12.17**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that none of provided URLs violate any copyrights
- [ ] I've searched the bugtracker for similar site support requests including closed ones
diff --git a/.github/ISSUE_TEMPLATE/3_site_feature_request.md b/.github/ISSUE_TEMPLATE/3_site_feature_request.md
index 573e8ded0..285610cc7 100644
--- a/.github/ISSUE_TEMPLATE/3_site_feature_request.md
+++ b/.github/ISSUE_TEMPLATE/3_site_feature_request.md
@@ -18,13 +18,13 @@ title: ''
- [ ] I'm reporting a site feature request
-- [ ] I've verified that I'm running youtube-dl version **2021.06.06**
+- [ ] I've verified that I'm running youtube-dl version **2021.12.17**
- [ ] I've searched the bugtracker for similar site feature requests including closed ones
diff --git a/.github/ISSUE_TEMPLATE/4_bug_report.md b/.github/ISSUE_TEMPLATE/4_bug_report.md
index c0031bf7a..af73525fb 100644
--- a/.github/ISSUE_TEMPLATE/4_bug_report.md
+++ b/.github/ISSUE_TEMPLATE/4_bug_report.md
@@ -18,7 +18,7 @@ title: ''
- [ ] I'm reporting a broken site support issue
-- [ ] I've verified that I'm running youtube-dl version **2021.06.06**
+- [ ] I've verified that I'm running youtube-dl version **2021.12.17**
- [ ] I've checked that all provided URLs are alive and playable in a browser
- [ ] I've checked that all URLs and arguments with special characters are properly quoted or escaped
- [ ] I've searched the bugtracker for similar bug reports including closed ones
@@ -43,7 +43,7 @@ Add the `-v` flag to your command line you run youtube-dl with (`youtube-dl -v <
[debug] User config: []
[debug] Command-line args: [u'-v', u'http://www.youtube.com/watch?v=BaW_jenozKcj']
[debug] Encodings: locale cp1251, fs mbcs, out cp866, pref cp1251
- [debug] youtube-dl version 2021.06.06
+ [debug] youtube-dl version 2021.12.17
[debug] Python version 2.7.11 - Windows-2003Server-5.2.3790-SP2
[debug] exe versions: ffmpeg N-75573-g1d0487f, ffprobe N-75573-g1d0487f, rtmpdump 2.4
[debug] Proxy map: {}
diff --git a/.github/ISSUE_TEMPLATE/5_feature_request.md b/.github/ISSUE_TEMPLATE/5_feature_request.md
index 1138ab2ca..42c878b83 100644
--- a/.github/ISSUE_TEMPLATE/5_feature_request.md
+++ b/.github/ISSUE_TEMPLATE/5_feature_request.md
@@ -19,13 +19,13 @@ labels: 'request'
- [ ] I'm reporting a feature request
-- [ ] I've verified that I'm running youtube-dl version **2021.06.06**
+- [ ] I've verified that I'm running youtube-dl version **2021.12.17**
- [ ] I've searched the bugtracker for similar feature requests including closed ones
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..3ba13e0ce
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1 @@
+blank_issues_enabled: false
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 90bd63c32..c3aabde47 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,81 +1,387 @@
name: CI
-on: [push, pull_request]
+
+env:
+ # add 3.10+ after patching nose (https://github.com/nose-devs/nose/issues/1099)
+ # or switching to fork of https://github.com/mdmintz/pynose
+ all-cpython-versions: 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9
+ main-cpython-versions: 2.7, 3.2, 3.5, 3.9
+ pypy-versions: pypy-2.7, pypy-3.6, pypy-3.7
+ cpython-versions: main
+ test-set: both
+
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+ inputs:
+ cpython-versions:
+ type: choice
+ description: CPython versions (main = 2.7, 3.2, 3.5, 3.9)
+ options:
+ - all
+ - main
+ required: true
+ default: main
+ test-set:
+ type: choice
+ description: core, download
+ options:
+ - both
+ - core
+ - download
+ required: true
+ default: core
+
+permissions:
+ contents: read
+
jobs:
+ select:
+ name: Select tests from inputs
+ runs-on: ubuntu-latest
+ outputs:
+ cpython-versions: ${{ steps.run.outputs.cpython-versions }}
+ test-set: ${{ steps.run.outputs.test-set }}
+ own-pip-versions: ${{ steps.run.outputs.own-pip-versions }}
+ steps:
+ - id: run
+ run: |
+ # Make a JSON Array from comma/space-separated string (no extra escaping)
+ json_list() { \
+ ret=""; IFS="${IFS},"; set -- $*; \
+ for a in "$@"; do \
+ ret=$(printf '%s"%s"' "${ret}${ret:+, }" "$a"); \
+ done; \
+ printf '[%s]' "$ret"; }
+ tests="${{ inputs.test-set || env.test-set }}"
+ [ $tests = both ] && tests="core download"
+ printf 'test-set=%s\n' "$(json_list $tests)" >> "$GITHUB_OUTPUT"
+ versions="${{ inputs.cpython-versions || env.cpython-versions }}"
+ if [ "$versions" = all ]; then \
+ versions="${{ env.all-cpython-versions }}"; else \
+ versions="${{ env.main-cpython-versions }}"; \
+ fi
+ printf 'cpython-versions=%s\n' \
+ "$(json_list ${versions}${versions:+, }${{ env.pypy-versions }})" >> "$GITHUB_OUTPUT"
+ # versions with a special get-pip.py in a per-version subdirectory
+ printf 'own-pip-versions=%s\n' \
+ "$(json_list 2.6, 2.7, 3.2, 3.3, 3.4, 3.5, 3.6)" >> "$GITHUB_OUTPUT"
+
tests:
- name: Tests
+ name: Run tests
+ needs: select
+ permissions:
+ contents: read
+ packages: write
runs-on: ${{ matrix.os }}
+ env:
+ PIP: python -m pip
+ PIP_DISABLE_PIP_VERSION_CHECK: true
+ PIP_NO_PYTHON_VERSION_WARNING: true
strategy:
fail-fast: true
matrix:
- os: [ubuntu-18.04]
- # TODO: python 2.6
- python-version: [2.7, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, pypy-2.7, pypy-3.6, pypy-3.7]
+ os: [ubuntu-20.04]
+ # outside steps, use github.env...., not env....
+ python-version: ${{ fromJSON(needs.select.outputs.cpython-versions) }}
python-impl: [cpython]
- ytdl-test-set: [core, download]
+ ytdl-test-set: ${{ fromJSON(needs.select.outputs.test-set) }}
run-tests-ext: [sh]
include:
- # python 3.2 is only available on windows via setup-python
- - os: windows-latest
+ - os: windows-2019
python-version: 3.2
python-impl: cpython
- ytdl-test-set: core
+ ytdl-test-set: ${{ contains(needs.select.outputs.test-set, 'core') && 'core' || 'nocore' }}
run-tests-ext: bat
- - os: windows-latest
+ - os: windows-2019
python-version: 3.2
python-impl: cpython
- ytdl-test-set: download
+ ytdl-test-set: ${{ contains(needs.select.outputs.test-set, 'download') && 'download' || 'nodownload' }}
run-tests-ext: bat
# jython
- - os: ubuntu-18.04
+ - os: ubuntu-20.04
python-impl: jython
- ytdl-test-set: core
+ ytdl-test-set: ${{ contains(needs.select.outputs.test-set, 'core') && 'core' || 'nocore' }}
run-tests-ext: sh
- - os: ubuntu-18.04
+ - os: ubuntu-20.04
python-impl: jython
- ytdl-test-set: download
+ ytdl-test-set: ${{ contains(needs.select.outputs.test-set, 'download') && 'download' || 'nodownload' }}
run-tests-ext: sh
steps:
- - uses: actions/checkout@v2
- - name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
- if: ${{ matrix.python-impl == 'cpython' }}
+ - name: Checkout
+ uses: actions/checkout@v3
+ #-------- Python 3 -----
+ - name: Set up supported Python ${{ matrix.python-version }}
+ id: setup-python
+ if: ${{ matrix.python-impl == 'cpython' && matrix.python-version != '2.6' && matrix.python-version != '2.7'}}
+ # wrap broken actions/setup-python@v4
+ uses: ytdl-org/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
+ cache-build: true
+ allow-build: info
+ - name: Locate supported Python ${{ matrix.python-version }}
+ if: ${{ env.pythonLocation }}
+ shell: bash
+ run: |
+ echo "PYTHONHOME=${pythonLocation}" >> "$GITHUB_ENV"
+ export expected="${{ steps.setup-python.outputs.python-path }}"
+ dirname() { printf '%s\n' \
+ 'import os, sys' \
+ 'print(os.path.dirname(sys.argv[1]))' \
+ | ${expected} - "$1"; }
+ expd="$(dirname "$expected")"
+ export python="$(command -v python)"
+ [ "$expd" = "$(dirname "$python")" ] || echo "PATH=$expd:${PATH}" >> "$GITHUB_ENV"
+ [ -x "$python" ] || printf '%s\n' \
+ 'import os' \
+ 'exp = os.environ["expected"]' \
+ 'python = os.environ["python"]' \
+ 'exps = os.path.split(exp)' \
+ 'if python and (os.path.dirname(python) == exp[0]):' \
+ ' exit(0)' \
+ 'exps[1] = "python" + os.path.splitext(exps[1])[1]' \
+ 'python = os.path.join(*exps)' \
+ 'try:' \
+ ' os.symlink(exp, python)' \
+ 'except AttributeError:' \
+ ' os.rename(exp, python)' \
+ | ${expected} -
+ printf '%s\n' \
+ 'import sys' \
+ 'print(sys.path)' \
+ | ${expected} -
+ #-------- Python 2.7 --
+ - name: Set up Python 2.7
+ if: ${{ matrix.python-version == '2.7' }}
+ # install 2.7
+ shell: bash
+ run: |
+ sudo apt-get install -y python2 python-is-python2
+ echo "PYTHONHOME=/usr" >> "$GITHUB_ENV"
+ #-------- Python 2.6 --
+ - name: Set up Python 2.6 environment
+ if: ${{ matrix.python-version == '2.6' }}
+ shell: bash
+ run: |
+ openssl_name=openssl-1.0.2u
+ echo "openssl_name=${openssl_name}" >> "$GITHUB_ENV"
+ openssl_dir=$HOME/.local/opt/$openssl_name
+ echo "openssl_dir=${openssl_dir}" >> "$GITHUB_ENV"
+ PYENV_ROOT=$HOME/.local/share/pyenv
+ echo "PYENV_ROOT=${PYENV_ROOT}" >> "$GITHUB_ENV"
+ sudo apt-get install -y openssl ca-certificates
+ - name: Cache Python 2.6
+ id: cache26
+ if: ${{ matrix.python-version == '2.6' }}
+ uses: actions/cache@v3
+ with:
+ key: python-2.6.9
+ path: |
+ ${{ env.openssl_dir }}
+ ${{ env.PYENV_ROOT }}
+ - name: Build and set up Python 2.6
+ if: ${{ matrix.python-version == '2.6' && ! steps.cache26.outputs.cache-hit }}
+ # dl and build locally
+ shell: bash
+ run: |
+ # Install build environment
+ sudo apt-get install -y build-essential llvm libssl-dev tk-dev \
+ libncursesw5-dev libreadline-dev libsqlite3-dev \
+ libffi-dev xz-utils zlib1g-dev libbz2-dev liblzma-dev
+ # Download and install OpenSSL 1.0.2, back in time
+ openssl_name=${{ env.openssl_name }}
+ openssl_targz=${openssl_name}.tar.gz
+ openssl_dir=${{ env.openssl_dir }}
+ openssl_inc=$openssl_dir/include
+ openssl_lib=$openssl_dir/lib
+ openssl_ssl=$openssl_dir/ssl
+ curl -L "https://www.openssl.org/source/$openssl_targz" -o $openssl_targz
+ tar -xf $openssl_targz
+ ( cd $openssl_name; \
+ ./config --prefix=$openssl_dir --openssldir=${openssl_dir}/ssl \
+ --libdir=lib -Wl,-rpath=${openssl_dir}/lib shared zlib-dynamic && \
+ make && \
+ make install )
+ rm -rf $openssl_name
+ rmdir $openssl_ssl/certs && ln -s /etc/ssl/certs $openssl_ssl/certs
+
+ # Download PyEnv from its GitHub repository.
+ export PYENV_ROOT=${{ env.PYENV_ROOT }}
+ export PATH=$PYENV_ROOT/bin:$PATH
+ git clone "https://github.com/pyenv/pyenv.git" "$PYENV_ROOT"
+
+ # Prevent pyenv build trying (and failing) to update pip
+ export GET_PIP=get-pip-2.6.py
+ echo 'import sys; sys.exit(0)' > ${GET_PIP}
+ GET_PIP=$(realpath $GET_PIP)
+
+ # Build and install Python
+ export CFLAGS="-I$openssl_inc"
+ export LDFLAGS="-L$openssl_lib"
+ export LD_LIBRARY_PATH="$openssl_lib"
+ pyenv install 2.6.9
+ - name: Locate Python 2.6
+ if: ${{ matrix.python-version == '2.6' }}
+ shell: bash
+ run: |
+ PYTHONHOME="${{ env.PYENV_ROOT }}/versions/2.6.9"
+ echo "PYTHONHOME=$PYTHONHOME" >> "$GITHUB_ENV"
+ echo "PATH=${PYTHONHOME}/bin:$PATH" >> "$GITHUB_ENV"
+ echo "LD_LIBRARY_PATH=${{ env.openssl_dir }}/lib${LD_LIBRARY_PATH:+:}${LD_LIBRARY_PATH}" >> "$GITHUB_ENV"
+ #-------- Jython ------
- name: Set up Java 8
if: ${{ matrix.python-impl == 'jython' }}
- uses: actions/setup-java@v1
+ uses: actions/setup-java@v2
with:
java-version: 8
+ distribution: 'zulu'
+ - name: Setup Jython environment
+ if: ${{ matrix.python-impl == 'jython' }}
+ shell: bash
+ run: |
+ echo "JYTHON_ROOT=${HOME}/jython" >> "$GITHUB_ENV"
+ echo "PIP=pip" >> "$GITHUB_ENV"
+ - name: Cache Jython
+ id: cachejy
+ if: ${{ matrix.python-impl == 'jython' }}
+ uses: actions/cache@v3
+ with:
+ # 2.7.3 now available, may solve SNI issue
+ key: jython-2.7.1
+ path: |
+ ${{ env.JYTHON_ROOT }}
- name: Install Jython
- if: ${{ matrix.python-impl == 'jython' }}
+ if: ${{ matrix.python-impl == 'jython' && ! steps.cachejy.outputs.cache-hit }}
+ shell: bash
run: |
- wget https://repo1.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar -O jython-installer.jar
- java -jar jython-installer.jar -s -d "$HOME/jython"
- echo "$HOME/jython/bin" >> $GITHUB_PATH
- - name: Install nose
- if: ${{ matrix.python-impl != 'jython' }}
- run: pip install nose
- - name: Install nose (Jython)
- if: ${{ matrix.python-impl == 'jython' }}
- # Working around deprecation of support for non-SNI clients at PyPI CDN (see https://status.python.org/incidents/hzmjhqsdjqgb)
+ JYTHON_ROOT="${{ env.JYTHON_ROOT }}"
+ curl -L "https://repo1.maven.org/maven2/org/python/jython-installer/2.7.1/jython-installer-2.7.1.jar" -o jython-installer.jar
+ java -jar jython-installer.jar -s -d "${JYTHON_ROOT}"
+ echo "${JYTHON_ROOT}/bin" >> "$GITHUB_PATH"
+ - name: Set up cached Jython
+ if: ${{ steps.cachejy.outputs.cache-hit }}
+ shell: bash
run: |
- wget https://files.pythonhosted.org/packages/99/4f/13fb671119e65c4dce97c60e67d3fd9e6f7f809f2b307e2611f4701205cb/nose-1.3.7-py2-none-any.whl
- pip install nose-1.3.7-py2-none-any.whl
+ JYTHON_ROOT="${{ env.JYTHON_ROOT }}"
+ echo "${JYTHON_ROOT}/bin" >> $GITHUB_PATH
+ #-------- pip ---------
+ - name: Set up supported Python ${{ matrix.python-version }} pip
+ if: ${{ (matrix.python-version != '3.2' && steps.setup-python.outputs.python-path) || matrix.python-version == '2.7' }}
+ # This step may run in either Linux or Windows
+ shell: bash
+ run: |
+ echo "$PATH"
+ echo "$PYTHONHOME"
+ # curl is available on both Windows and Linux, -L follows redirects, -O gets name
+ python -m ensurepip || python -m pip --version || { \
+ get_pip="${{ contains(needs.select.outputs.own-pip-versions, matrix.python-version) && format('{0}/', matrix.python-version) || '' }}"; \
+ curl -L -O "https://bootstrap.pypa.io/pip/${get_pip}get-pip.py"; \
+ python get-pip.py; }
+ - name: Set up Python 2.6 pip
+ if: ${{ matrix.python-version == '2.6' }}
+ shell: bash
+ run: |
+ python -m pip --version || { \
+ curl -L -O "https://bootstrap.pypa.io/pip/2.6/get-pip.py"; \
+ curl -L -O "https://files.pythonhosted.org/packages/ac/95/a05b56bb975efa78d3557efa36acaf9cf5d2fd0ee0062060493687432e03/pip-9.0.3-py2.py3-none-any.whl"; \
+ python get-pip.py --no-setuptools --no-wheel pip-9.0.3-py2.py3-none-any.whl; }
+ # work-around to invoke pip module on 2.6: https://bugs.python.org/issue2751
+ echo "PIP=python -m pip.__main__" >> "$GITHUB_ENV"
+ - name: Set up other Python ${{ matrix.python-version }} pip
+ if: ${{ matrix.python-version == '3.2' && steps.setup-python.outputs.python-path }}
+ shell: bash
+ run: |
+ python -m pip --version || { \
+ curl -L -O "https://bootstrap.pypa.io/pip/3.2/get-pip.py"; \
+ curl -L -O "https://files.pythonhosted.org/packages/b2/d0/cd115fe345dd6f07ec1c780020a7dfe74966fceeb171e0f20d1d4905b0b7/pip-7.1.2-py2.py3-none-any.whl"; \
+ python get-pip.py --no-setuptools --no-wheel pip-7.1.2-py2.py3-none-any.whl; }
+ #-------- unittest ----
+ - name: Upgrade Unittest for Python 2.6
+ if: ${{ matrix.python-version == '2.6' }}
+ shell: bash
+ run: |
+ # Work around deprecation of support for non-SNI clients at PyPI CDN (see https://status.python.org/incidents/hzmjhqsdjqgb)
+ $PIP -qq show unittest2 || { \
+ for u in "65/26/32b8464df2a97e6dd1b656ed26b2c194606c16fe163c695a992b36c11cdf/six-1.13.0-py2.py3-none-any.whl" \
+ "f2/94/3af39d34be01a24a6e65433d19e107099374224905f1e0cc6bbe1fd22a2f/argparse-1.4.0-py2.py3-none-any.whl" \
+ "c7/a3/c5da2a44c85bfbb6eebcfc1dde24933f8704441b98fdde6528f4831757a6/linecache2-1.0.0-py2.py3-none-any.whl" \
+ "17/0a/6ac05a3723017a967193456a2efa0aa9ac4b51456891af1e2353bb9de21e/traceback2-1.4.0-py2.py3-none-any.whl" \
+ "72/20/7f0f433060a962200b7272b8c12ba90ef5b903e218174301d0abfd523813/unittest2-1.1.0-py2.py3-none-any.whl"; do \
+ curl -L -O "https://files.pythonhosted.org/packages/${u}"; \
+ $PIP install ${u##*/}; \
+ done; }
+ # make tests use unittest2
+ for test in ./test/test_*.py ./test/helper.py; do
+ sed -r -i -e '/^import unittest$/s/test/test2 as unittest/' "$test"
+ done
+ #-------- nose --------
+ - name: Install nose for Python ${{ matrix.python-version }}
+ if: ${{ (matrix.python-version != '3.2' && steps.setup-python.outputs.python-path) || matrix.python-version == '2.7' }}
+ shell: bash
+ run: |
+ echo "$PATH"
+ echo "$PYTHONHOME"
+ $PIP -qq show nose || $PIP install nose
+ - name: Install nose for other Python 2
+ if: ${{ matrix.python-impl == 'jython' || matrix.python-version == '2.6' }}
+ shell: bash
+ run: |
+ # Work around deprecation of support for non-SNI clients at PyPI CDN (see https://status.python.org/incidents/hzmjhqsdjqgb)
+ $PIP -qq show nose || { \
+ curl -L -O "https://files.pythonhosted.org/packages/99/4f/13fb671119e65c4dce97c60e67d3fd9e6f7f809f2b307e2611f4701205cb/nose-1.3.7-py2-none-any.whl"; \
+ $PIP install nose-1.3.7-py2-none-any.whl; }
+ - name: Install nose for other Python 3
+ if: ${{ matrix.python-version == '3.2' && steps.setup-python.outputs.python-path }}
+ shell: bash
+ run: |
+ $PIP -qq show nose || { \
+ curl -L -O "https://files.pythonhosted.org/packages/15/d8/dd071918c040f50fa1cf80da16423af51ff8ce4a0f2399b7bf8de45ac3d9/nose-1.3.7-py3-none-any.whl"; \
+ $PIP install nose-1.3.7-py3-none-any.whl; }
+ - name: Set up nosetest test
+ if: ${{ contains(needs.select.outputs.test-set, matrix.ytdl-test-set ) }}
+ shell: bash
+ run: |
+ # define a test to validate the Python version used by nosetests
+ printf '%s\n' \
+ 'from __future__ import unicode_literals' \
+ 'import sys, os, platform' \
+ 'try:' \
+ ' import unittest2 as unittest' \
+ 'except ImportError:' \
+ ' import unittest' \
+ 'class TestPython(unittest.TestCase):' \
+ ' def setUp(self):' \
+ ' self.ver = os.environ["PYTHON_VER"].split("-")' \
+ ' def test_python_ver(self):' \
+ ' self.assertEqual(sys.version[:3], self.ver[-1])' \
+ ' self.assertTrue(sys.version.startswith(self.ver[-1]))' \
+ ' self.assertIn(self.ver[0], sys.version.lower())' \
+ ' def test_python_impl(self):' \
+ ' self.assertIn(platform.python_implementation().lower(), (os.environ["PYTHON_IMPL"], self.ver[0]))' \
+ > test/test_python.py
+ #-------- TESTS -------
- name: Run tests
+ if: ${{ contains(needs.select.outputs.test-set, matrix.ytdl-test-set ) }}
continue-on-error: ${{ matrix.ytdl-test-set == 'download' || matrix.python-impl == 'jython' }}
env:
YTDL_TEST_SET: ${{ matrix.ytdl-test-set }}
- run: ./devscripts/run_tests.${{ matrix.run-tests-ext }}
+ PYTHON_VER: ${{ matrix.python-version }}
+ PYTHON_IMPL: ${{ matrix.python-impl }}
+ run: |
+ ./devscripts/run_tests.${{ matrix.run-tests-ext }}
+
flake8:
name: Linter
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.9
- name: Install flake8
run: pip install flake8
- name: Run flake8
run: flake8 .
+
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 58ab3a4b8..ff40cef78 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -150,7 +150,7 @@ After you have ensured this site is distributing its content legally, you can fo
# TODO more properties (see youtube_dl/extractor/common.py)
}
```
-5. Add an import in [`youtube_dl/extractor/extractors.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/extractors.py).
+5. Add an import in [`youtube_dl/extractor/extractors.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/extractors.py). This makes the extractor available for use, as long as the class ends with `IE`.
6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc. Note that tests with `only_matching` key in test's dict are not counted in.
7. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L94-L303). Add tests and code for as many as you want.
8. Make sure your code follows [youtube-dl coding conventions](#youtube-dl-coding-conventions) and check the code with [flake8](https://flake8.pycqa.org/en/latest/index.html#quickstart):
diff --git a/ChangeLog b/ChangeLog
index 680fffdf8..658864282 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+version 2021.12.17
+
+Core
+* [postprocessor/ffmpeg] Show ffmpeg output on error (#22680, #29336)
+
+Extractors
+* [youtube] Update signature function patterns (#30363, #30366)
+* [peertube] Only call description endpoint if necessary (#29383)
+* [periscope] Pass referer to HLS requests (#29419)
+- [liveleak] Remove extractor (#17625, #24222, #29331)
++ [pornhub] Add support for pornhubthbh7ap3u.onion
+* [pornhub] Detect geo restriction
+* [pornhub] Dismiss tbr extracted from download URLs (#28927)
+* [curiositystream:collection] Extend _VALID_URL (#26326, #29117)
+* [youtube] Make get_video_info processing more robust (#29333)
+* [youtube] Workaround for get_video_info request (#29333)
+* [bilibili] Strip uploader name (#29202)
+* [youtube] Update invidious instance list (#29281)
+* [umg:de] Update GraphQL API URL (#29304)
+* [nrk] Switch psapi URL to https (#29344)
++ [egghead] Add support for app.egghead.io (#28404, #29303)
+* [appleconnect] Fix extraction (#29208)
++ [orf:tvthek] Add support for MPD formats (#28672, #29236)
+
+
version 2021.06.06
Extractors
diff --git a/README.md b/README.md
index 2841ed68f..14a3d6c86 100644
--- a/README.md
+++ b/README.md
@@ -632,7 +632,7 @@ To use percent literals in an output template use `%%`. To output to stdout use
The current default template is `%(title)s-%(id)s.%(ext)s`.
-In some cases, you don't want special characters such as 中, spaces, or &, such as when transferring the downloaded filename to a Windows system or the filename through an 8bit-unsafe channel. In these cases, add the `--restrict-filenames` flag to get a shorter title:
+In some cases, you don't want special characters such as 中, spaces, or &, such as when transferring the downloaded filename to a Windows system or the filename through an 8bit-unsafe channel. In these cases, add the `--restrict-filenames` flag to get a shorter title.
#### Output template and Windows batch files
@@ -918,7 +918,7 @@ Either prepend `https://www.youtube.com/watch?v=` or separate the ID from the op
Use the `--cookies` option, for example `--cookies /path/to/cookies/file.txt`.
-In order to extract cookies from browser use any conforming browser extension for exporting cookies. For example, [Get cookies.txt](https://chrome.google.com/webstore/detail/get-cookiestxt/bgaddhkoddajcdgocldbbfleckgcbcid/) (for Chrome) or [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/) (for Firefox).
+In order to extract cookies from browser use any conforming browser extension for exporting cookies. For example, [Get cookies.txt LOCALLY](https://chrome.google.com/webstore/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc) (for Chrome) or [cookies.txt](https://addons.mozilla.org/en-US/firefox/addon/cookies-txt/) (for Firefox).
Note that the cookies file must be in Mozilla/Netscape format and the first line of the cookies file must be either `# HTTP Cookie File` or `# Netscape HTTP Cookie File`. Make sure you have correct [newline format](https://en.wikipedia.org/wiki/Newline) in the cookies file and convert newlines if necessary to correspond with your OS, namely `CRLF` (`\r\n`) for Windows and `LF` (`\n`) for Unix and Unix-like systems (Linux, macOS, etc.). `HTTP Error 400: Bad Request` when using `--cookies` is a good sign of invalid newline format.
@@ -1069,9 +1069,11 @@ After you have ensured this site is distributing its content legally, you can fo
}
```
5. Add an import in [`youtube_dl/extractor/extractors.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/extractors.py).
-6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test, then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc. Note that tests with `only_matching` key in test's dict are not counted in.
-7. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L94-L303). Add tests and code for as many as you want.
-8. Make sure your code follows [youtube-dl coding conventions](#youtube-dl-coding-conventions) and check the code with [flake8](https://flake8.pycqa.org/en/latest/index.html#quickstart):
+6. Run `python test/test_download.py TestDownload.test_YourExtractor`. This *should fail* at first, but you can continually re-run it until you're done. If you decide to add more than one test (actually, test case) then rename ``_TEST`` to ``_TESTS`` and make it into a list of dictionaries. The tests will then be named `TestDownload.test_YourExtractor`, `TestDownload.test_YourExtractor_1`, `TestDownload.test_YourExtractor_2`, etc. Note:
+ * the test names use the extractor class name **without the trailing `IE`**
+ * tests with `only_matching` key in test's dict are not counted.
+8. Have a look at [`youtube_dl/extractor/common.py`](https://github.com/ytdl-org/youtube-dl/blob/master/youtube_dl/extractor/common.py) for possible helper methods and a [detailed description of what your extractor should and may return](https://github.com/ytdl-org/youtube-dl/blob/7f41a598b3fba1bcab2817de64a08941200aa3c8/youtube_dl/extractor/common.py#L94-L303). Add tests and code for as many as you want.
+9. Make sure your code follows [youtube-dl coding conventions](#youtube-dl-coding-conventions) and check the code with [flake8](https://flake8.pycqa.org/en/latest/index.html#quickstart):
$ flake8 youtube_dl/extractor/yourextractor.py
@@ -1406,7 +1408,11 @@ with youtube_dl.YoutubeDL(ydl_opts) as ydl:
# BUGS
-Bugs and suggestions should be reported at: Decoy text418 I'm a teapot
"
@@ -35,13 +53,13 @@ class InfoExtractorTestRequestHandler(compat_http_server.BaseHTTPRequestHandler)
assert False
-class TestIE(InfoExtractor):
+class DummyIE(InfoExtractor):
pass
class TestInfoExtractor(unittest.TestCase):
def setUp(self):
- self.ie = TestIE(FakeYDL())
+ self.ie = DummyIE(FakeYDL())
def test_ie_key(self):
self.assertEqual(get_info_extractor(YoutubeIE.ie_key()), YoutubeIE)
@@ -62,6 +80,7 @@ class TestInfoExtractor(unittest.TestCase):
+
'''
self.assertEqual(ie._og_search_title(html), 'Foo')
self.assertEqual(ie._og_search_description(html), 'Some video\'s description ')
@@ -74,6 +93,7 @@ class TestInfoExtractor(unittest.TestCase):
self.assertEqual(ie._og_search_property(('test0', 'test1'), html), 'foo > < bar')
self.assertRaises(RegexNotFoundError, ie._og_search_property, 'test0', html, None, fatal=True)
self.assertRaises(RegexNotFoundError, ie._og_search_property, ('test0', 'test00'), html, None, fatal=True)
+ self.assertEqual(ie._og_search_property('test4', html), 'unquoted-value')
def test_html_search_meta(self):
ie = self.ie
@@ -98,6 +118,71 @@ class TestInfoExtractor(unittest.TestCase):
self.assertRaises(RegexNotFoundError, ie._html_search_meta, 'z', html, None, fatal=True)
self.assertRaises(RegexNotFoundError, ie._html_search_meta, ('z', 'x'), html, None, fatal=True)
+ def test_search_nextjs_data(self):
+ html = '''
+
+
+
+
+
+ Example heading
+ ;
"|\'|\b)(?P