Skip to content

Commit

Permalink
[rh:curlcffi] Add support for curl_cffi
Browse files Browse the repository at this point in the history
Authored by: coletdjnz, Grub4K, pukkandan, bashonly

Co-authored-by: Simon Sawicki <contact@grub4k.xyz>
Co-authored-by: pukkandan <pukkandan.ytdlp@gmail.com>
Co-authored-by: bashonly <bashonly@protonmail.com>
  • Loading branch information
4 people committed Mar 17, 2024
1 parent 0b81d4d commit 52f5be1
Show file tree
Hide file tree
Showing 14 changed files with 629 additions and 141 deletions.
22 changes: 19 additions & 3 deletions .github/workflows/build.yml
Expand Up @@ -247,9 +247,25 @@ jobs:
run: |
brew install coreutils
python3 devscripts/install_deps.py --user -o --include build
python3 devscripts/install_deps.py --print --include pyinstaller > requirements.txt
python3 devscripts/install_deps.py --print --include pyinstaller_macos > requirements.txt
# We need to ignore wheels otherwise we break universal2 builds
python3 -m pip install -U --user --no-binary :all: -r requirements.txt
# We need to fuse our own universal2 wheels for curl_cffi
python3 -m pip install -U --user delocate
mkdir curl_cffi_whls curl_cffi_universal2
python3 devscripts/install_deps.py --print -o --include curl_cffi > requirements.txt
for platform in "macosx_11_0_arm64" "macosx_11_0_x86_64"; do
python3 -m pip download \
--only-binary=:all: \
--platform "${platform}" \
--pre -d curl_cffi_whls \
-r requirements.txt
done
python3 -m delocate.cmd.delocate_fuse curl_cffi_whls/curl_cffi*.whl -w curl_cffi_universal2
python3 -m delocate.cmd.delocate_fuse curl_cffi_whls/cffi*.whl -w curl_cffi_universal2
cd curl_cffi_universal2
for wheel in *cffi*.whl; do mv -n -- "${wheel}" "${wheel/x86_64/universal2}"; done
python3 -m pip install -U --user *cffi*.whl
- name: Prepare
run: |
Expand Down Expand Up @@ -303,7 +319,7 @@ jobs:
run: |
brew install coreutils
python3 devscripts/install_deps.py --user -o --include build
python3 devscripts/install_deps.py --user --include pyinstaller
python3 devscripts/install_deps.py --user --include pyinstaller_macos --include curl_cffi
- name: Prepare
run: |
Expand Down Expand Up @@ -345,7 +361,7 @@ jobs:
- name: Install Requirements
run: | # Custom pyinstaller built with https://github.com/yt-dlp/pyinstaller-builds
python devscripts/install_deps.py -o --include build
python devscripts/install_deps.py --include py2exe
python devscripts/install_deps.py --include py2exe --include curl_cffi
python -m pip install -U "https://yt-dlp.github.io/Pyinstaller-Builds/x86_64/pyinstaller-5.8.0-py3-none-any.whl"
- name: Prepare
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/core.yml
Expand Up @@ -53,7 +53,7 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install test requirements
run: python3 ./devscripts/install_deps.py --include dev
run: python3 ./devscripts/install_deps.py --include dev --include curl_cffi
- name: Run tests
continue-on-error: False
run: |
Expand Down
9 changes: 9 additions & 0 deletions README.md
Expand Up @@ -196,6 +196,15 @@ While all the other dependencies are optional, `ffmpeg` and `ffprobe` are highly
* [**websockets**](https://github.com/aaugustin/websockets)\* - For downloading over websocket. Licensed under [BSD-3-Clause](https://github.com/aaugustin/websockets/blob/main/LICENSE)
* [**requests**](https://github.com/psf/requests)\* - HTTP library. For HTTPS proxy and persistent connections support. Licensed under [Apache-2.0](https://github.com/psf/requests/blob/main/LICENSE)

#### Impersonation

The following provide support for impersonating browser requests. This may be required for some sites that employ TLS fingerprinting.

* [**curl_cffi**](https://github.com/yifeikong/curl_cffi) (recommended) - Python binding for [curl-impersonate](https://github.com/lwthiker/curl-impersonate). Provides impersonation targets for Chrome, Edge and Safari. Licensed under [MIT](https://github.com/yifeikong/curl_cffi/blob/main/LICENSE)
* Can be installed with the `curl_cffi` group, e.g. `pip install yt-dlp[default,curl_cffi]`
* Only included in `yt-dlp.exe`, `yt-dlp_macos` and `yt-dlp_macos_legacy` builds


### Metadata

* [**mutagen**](https://github.com/quodlibet/mutagen)\* - For `--embed-thumbnail` in certain formats. Licensed under [GPLv2+](https://github.com/quodlibet/mutagen/blob/master/COPYING)
Expand Down
2 changes: 2 additions & 0 deletions pyproject.toml
Expand Up @@ -53,6 +53,7 @@ dependencies = [

[project.optional-dependencies]
default = []
curl_cffi = ["curl-cffi==0.5.10; implementation_name=='cpython'"]
secretstorage = [
"cffi",
"secretstorage",
Expand All @@ -69,6 +70,7 @@ dev = [
"pytest",
]
pyinstaller = ["pyinstaller>=6.3"]
pyinstaller_macos = ["pyinstaller==5.13.2"] # needed for curl_cffi builds
py2exe = ["py2exe>=0.12"]

[project.urls]
Expand Down

3 comments on commit 52f5be1

@someziggyman
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello guys.
Was not sure, if I should have created an issue for that, but decided to write my bug report here, cause I think things broken down for me after these changes.

The problem is - now I can not build a "portable" version of yt-dlp for myself using pyinstaller. I'm running macOS Sonoma 14.3.1, M1 CPU. Using this script:
/usr/local/bin/python3 /Users/sy/Downloads/myDLP/bundle/pyinstaller.py --target-architecture universal2 --onedir

Full log below:

/usr/local/bin/python3 ./yt-dlp/bundle/pyinstaller.py --target-architecture universal2
Building yt-dlp v2024.03.10 for darwin arm64 with options ['--target-architecture', 'universal2', '--onefile']
Remember to update the version using "devscripts/update-version.py"
WARNING: Building without lazy_extractors. Run "devscripts/make_lazy_extractors.py" to build lazy extractors
Destination: dist/yt-dlp_macos_arm64

Running PyInstaller with ['--name=yt-dlp_macos_arm64', '--icon=devscripts/logo.ico', '--upx-exclude=vcruntime140.dll', '--noconfirm', '--additional-hooks-dir=yt_dlp/__pyinstaller', '--target-architecture', 'universal2', '--onefile', 'yt_dlp/main.py']
26 INFO: PyInstaller: 4.8
26 INFO: Python: 3.10.2
31 INFO: Platform: macOS-14.3.1-arm64-arm-64bit
32 INFO: wrote ./yt-dlp/yt-dlp_macos_arm64.spec
33 INFO: UPX is not available.
34 INFO: Extending PYTHONPATH with paths
['./yt-dlp']
95 INFO: checking Analysis
95 INFO: Building Analysis because Analysis-00.toc is non existent
95 INFO: Initializing module dependency graph...
95 INFO: Caching module graph hooks...
98 INFO: Analyzing base_library.zip ...
1802 INFO: Caching module dependency graph...
1854 INFO: running Analysis Analysis-00.toc
1858 INFO: Analyzing ./yt-dlp/yt_dlp/main.py
4742 INFO: Processing module hooks...
4742 INFO: Loading module hook 'hook-yt_dlp.py' from './yt-dlp/yt_dlp/__pyinstaller'...
Adding imports: ['yt_dlp.compat._legacy', 'yt_dlp.compat._deprecated', 'yt_dlp.utils._legacy', 'yt_dlp.utils._deprecated', 'Cryptodome', 'websockets.legacy.http', 'websockets.legacy.protocol', 'websockets.legacy.handshake', 'websockets.datastructures', 'websockets.imports', 'websockets.main', 'websockets.headers', 'websockets.legacy.compatibility', 'websockets.extensions.permessage_deflate', 'websockets.connection', 'websockets.extensions', 'websockets.exceptions', 'websockets.legacy.server', 'websockets', 'websockets.uri', 'websockets.utils', 'websockets.frames', 'websockets.extensions.base', 'websockets.legacy.framing', 'websockets.legacy.auth', 'websockets.server', 'websockets.version', 'websockets.client', 'websockets.legacy', 'websockets.streams', 'websockets.http', 'websockets.legacy.client', 'websockets.auth', 'websockets.http11', 'websockets.typing', 'websockets.speedups', 'mutagen', 'brotli', 'certifi', 'secretstorage', 'curl_cffi']
Traceback (most recent call last):
File "", line 2, in
ModuleNotFoundError: No module named 'curl_cffi'
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/hooks/init.py", line 366, in get_module_file_attribute
attr = loader.get_filename(package)
AttributeError: 'NoneType' object has no attribute 'get_filename'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/depend/imphook.py", line 361, in _load_hook_module
self._hook_module = importlib_load_source(self.hook_module_name, self.hook_filename)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/compat.py", line 606, in importlib_load_source
return mod_loader.load_module()
File "", line 548, in _check_name_wrapper
File "", line 1063, in load_module
File "", line 888, in load_module
File "", line 290, in _load_module_shim
File "", line 719, in _load
File "", line 688, in _load_unlocked
File "", line 883, in exec_module
File "", line 241, in _call_with_frames_removed
File "./yt-dlp/yt_dlp/__pyinstaller/hook-yt_dlp.py", line 36, in
datas = collect_data_files('curl_cffi', includes=['cacert.pem'])
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/hooks/init.py", line 723, in collect_data_files
pkg_base, pkg_dir = get_package_paths(package)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/hooks/init.py", line 518, in get_package_paths
file_attr = get_module_file_attribute(package)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/utils/hooks/init.py", line 383, in get_module_file_attribute
raise ImportError('Unable to load module attribute') from e
ImportError: Unable to load module attribute

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "./yt-dlp/bundle/pyinstaller.py", line 132, in
main()
File "./yt-dlp/bundle/pyinstaller.py", line 46, in main
run_pyinstaller(opts)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/main.py", line 124, in run
run_build(pyi_config, spec_file, **vars(args))
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/main.py", line 58, in run_build
PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 793, in main
build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 725, in build
exec(code, spec_namespace)
File "./yt-dlp/yt-dlp_macos_arm64.spec", line 7, in
a = Analysis(['yt_dlp/main.py'],
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 277, in init
self.postinit()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/datastruct.py", line 155, in postinit
self.assemble()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/building/build_main.py", line 445, in assemble
self.graph.process_post_graph_hooks(self)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/depend/analysis.py", line 326, in process_post_graph_hooks
module_hook.post_graph(analysis)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/depend/imphook.py", line 398, in post_graph
self._load_hook_module()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/PyInstaller/depend/imphook.py", line 364, in _load_hook_module
raise ImportErrorWhenRunningHook(self.hook_module_name, self.hook_filename)
PyInstaller.exceptions.ImportErrorWhenRunningHook: Failed to import module __PyInstaller_hooks_0_yt_dlp required by hook for module ./yt-dlp/yt_dlp/__pyinstaller/hook-yt_dlp.py. Please check whether module __PyInstaller_hooks_0_yt_dlp actually exists and whether the hook is compatible with your version of ./yt-dlp/yt_dlp/__pyinstaller/hook-yt_dlp.py: You might want to read more about hooks in the manual and provide a pull-request to improve PyInstaller.

@bashonly
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@someziggyman try upgrading pyinstaller to 5.13.2

if you still have problems then open a new issue please

@someziggyman
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I did have version 4.8 as it turned out. upgraded to 6.5.0 via pip install --upgrade pyinstaller (as they say on their website). Now my pyinstaller --version in Terminal reruns 6.5.0 and the issue is till there. Opening new issue. Thanks for advice.

Please sign in to comment.