feat: initial tauri desktop app rewrite with ui and settings wired

This commit is contained in:
NimBold
2026-06-12 16:21:16 +03:30
parent e6ab997b00
commit d6690c7769
198 changed files with 13473 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
+7
View File
@@ -0,0 +1,7 @@
# Tauri + React + Typescript
This template should help get you started developing with Tauri, React and Typescript in Vite.
## Recommended IDE Setup
- [VS Code](https://code.visualstudio.com/) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)
+14
View File
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + React + Typescript</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
+2765
View File
File diff suppressed because it is too large Load Diff
+34
View File
@@ -0,0 +1,34 @@
{
"name": "tauri-app",
"private": true,
"version": "0.1.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"tauri": "tauri"
},
"dependencies": {
"@tailwindcss/vite": "^4.3.0",
"@tauri-apps/api": "^2",
"@tauri-apps/plugin-dialog": "^2.7.1",
"@tauri-apps/plugin-notification": "^2.3.3",
"@tauri-apps/plugin-opener": "^2",
"lucide-react": "^1.17.0",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"zustand": "^5.0.14"
},
"devDependencies": {
"@tauri-apps/cli": "^2",
"@types/react": "^19.1.8",
"@types/react-dom": "^19.1.6",
"@vitejs/plugin-react": "^4.6.0",
"autoprefixer": "^10.5.0",
"postcss": "^8.5.15",
"tailwindcss": "^4.3.0",
"typescript": "~5.8.3",
"vite": "^7.0.4"
}
}
+6
View File
@@ -0,0 +1,6 @@
<svg width="206" height="231" viewBox="0 0 206 231" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M143.143 84C143.143 96.1503 133.293 106 121.143 106C108.992 106 99.1426 96.1503 99.1426 84C99.1426 71.8497 108.992 62 121.143 62C133.293 62 143.143 71.8497 143.143 84Z" fill="#FFC131"/>
<ellipse cx="84.1426" cy="147" rx="22" ry="22" transform="rotate(180 84.1426 147)" fill="#24C8DB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M166.738 154.548C157.86 160.286 148.023 164.269 137.757 166.341C139.858 160.282 141 153.774 141 147C141 144.543 140.85 142.121 140.558 139.743C144.975 138.204 149.215 136.139 153.183 133.575C162.73 127.404 170.292 118.608 174.961 108.244C179.63 97.8797 181.207 86.3876 179.502 75.1487C177.798 63.9098 172.884 53.4021 165.352 44.8883C157.82 36.3744 147.99 30.2165 137.042 27.1546C126.095 24.0926 114.496 24.2568 103.64 27.6274C92.7839 30.998 83.1319 37.4317 75.8437 46.1553C74.9102 47.2727 74.0206 48.4216 73.176 49.5993C61.9292 50.8488 51.0363 54.0318 40.9629 58.9556C44.2417 48.4586 49.5653 38.6591 56.679 30.1442C67.0505 17.7298 80.7861 8.57426 96.2354 3.77762C111.685 -1.01901 128.19 -1.25267 143.769 3.10474C159.348 7.46215 173.337 16.2252 184.056 28.3411C194.775 40.457 201.767 55.4101 204.193 71.404C206.619 87.3978 204.374 103.752 197.73 118.501C191.086 133.25 180.324 145.767 166.738 154.548ZM41.9631 74.275L62.5557 76.8042C63.0459 72.813 63.9401 68.9018 65.2138 65.1274C57.0465 67.0016 49.2088 70.087 41.9631 74.275Z" fill="#FFC131"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M38.4045 76.4519C47.3493 70.6709 57.2677 66.6712 67.6171 64.6132C65.2774 70.9669 64 77.8343 64 85.0001C64 87.1434 64.1143 89.26 64.3371 91.3442C60.0093 92.8732 55.8533 94.9092 51.9599 97.4256C42.4128 103.596 34.8505 112.392 30.1816 122.756C25.5126 133.12 23.9357 144.612 25.6403 155.851C27.3449 167.09 32.2584 177.598 39.7906 186.112C47.3227 194.626 57.153 200.784 68.1003 203.846C79.0476 206.907 90.6462 206.743 101.502 203.373C112.359 200.002 122.011 193.568 129.299 184.845C130.237 183.722 131.131 182.567 131.979 181.383C143.235 180.114 154.132 176.91 164.205 171.962C160.929 182.49 155.596 192.319 148.464 200.856C138.092 213.27 124.357 222.426 108.907 227.222C93.458 232.019 76.9524 232.253 61.3736 227.895C45.7948 223.538 31.8055 214.775 21.0867 202.659C10.3679 190.543 3.37557 175.59 0.949823 159.596C-1.47592 143.602 0.768139 127.248 7.41237 112.499C14.0566 97.7497 24.8183 85.2327 38.4045 76.4519ZM163.062 156.711L163.062 156.711C162.954 156.773 162.846 156.835 162.738 156.897C162.846 156.835 162.954 156.773 163.062 156.711Z" fill="#24C8DB"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+1
View File
@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+7
View File
@@ -0,0 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
# Generated by Tauri
# will have schema files for capabilities auto-completion
/gen/schemas
+5830
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
[package]
name = "tauri-app"
version = "0.1.0"
description = "A Tauri App"
authors = ["you"]
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
# The `_lib` suffix may seem redundant but it is necessary
# to make the lib name unique and wouldn't conflict with the bin name.
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
name = "tauri_app_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-opener = "2"
tauri-plugin-dialog = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["process", "io-util", "rt", "macros"] }
regex = "1.10"
reqwest = "0.12"
tauri-plugin-notification = "2.3.3"
sysinfo = "0.39.3"
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>Python</string>
<key>CFBundleIdentifier</key>
<string>org.python.python</string>
<key>CFBundleVersion</key>
<string>3.14.5</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Python</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>3.14.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2001 Python Software Foundation. All rights reserved.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>Python</string>
<key>CFBundleIdentifier</key>
<string>org.python.python</string>
<key>CFBundleVersion</key>
<string>3.14.5</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Python</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>3.14.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2001 Python Software Foundation. All rights reserved.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key>
<string>Python</string>
<key>CFBundleIdentifier</key>
<string>org.python.python</string>
<key>CFBundleVersion</key>
<string>3.14.5</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleExecutable</key>
<string>Python</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleShortVersionString</key>
<string>3.14.5</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>MacOSX</string>
</array>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2001 Python Software Foundation. All rights reserved.</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleAllowMixedLocalizations</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,403 @@
Metadata-Version: 2.4
Name: curl_cffi
Version: 0.15.0
Summary: libcurl ffi bindings for Python, with impersonation support.
Author-email: lexiforest <infinitesheldon@gmail.com>
License-Expression: MIT
Project-URL: repository, https://github.com/lexiforest/curl_cffi
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Free Threading
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cffi>=2.0.0
Requires-Dist: certifi>=2024.2.2
Requires-Dist: rich
Provides-Extra: extra
Requires-Dist: readability-lxml>=0.8.1; extra == "extra"
Requires-Dist: markdownify>=1.1.0; extra == "extra"
Requires-Dist: lxml_html_clean; extra == "extra"
Provides-Extra: dev
Requires-Dist: charset_normalizer<4.0,>=3.3.2; extra == "dev"
Requires-Dist: coverage<7.0,>=6.4.1; extra == "dev"
Requires-Dist: cryptography<47.0,>=46.0.4; extra == "dev"
Requires-Dist: httpx==0.23.1; extra == "dev"
Requires-Dist: mypy<2.0,>=1.9.0; extra == "dev"
Requires-Dist: pytest<9.0,>=8.1.1; extra == "dev"
Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "dev"
Requires-Dist: pytest-trio<1.0,>=0.8.0; extra == "dev"
Requires-Dist: ruff<1.0,>=0.3.5; extra == "dev"
Requires-Dist: trio<1.0,>=0.25.0; extra == "dev"
Requires-Dist: trustme<2.0,>=1.1.0; extra == "dev"
Requires-Dist: uvicorn<1.0,>=0.29.0; extra == "dev"
Requires-Dist: websockets>=14.0; extra == "dev"
Requires-Dist: typing_extensions; extra == "dev"
Provides-Extra: build
Requires-Dist: cibuildwheel; extra == "build"
Requires-Dist: wheel; extra == "build"
Provides-Extra: test
Requires-Dist: charset_normalizer<4.0,>=3.3.2; extra == "test"
Requires-Dist: cryptography<47.0,>=46.0.4; extra == "test"
Requires-Dist: litestar<3.0,>=2.19.0; extra == "test"
Requires-Dist: httpx==0.23.1; extra == "test"
Requires-Dist: proxy.py<3.0,>=2.4.3; extra == "test"
Requires-Dist: pytest<9.0,>=8.1.1; extra == "test"
Requires-Dist: pytest-asyncio<1.0,>=0.23.6; extra == "test"
Requires-Dist: pytest-trio<1.0,>=0.8.0; extra == "test"
Requires-Dist: python-multipart<1.0,>=0.0.9; extra == "test"
Requires-Dist: trio<1.0,>=0.25.0; extra == "test"
Requires-Dist: trustme<2.0,>=1.1.0; extra == "test"
Requires-Dist: uvicorn<1.0,>=0.29.0; extra == "test"
Requires-Dist: websockets>=14.0; extra == "test"
Requires-Dist: typing_extensions; extra == "test"
Dynamic: license-file
# curl_cffi
[![PyPI Downloads](https://static.pepy.tech/badge/curl-cffi/week)](https://pepy.tech/projects/curl-cffi)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/curl_cffi)
[![PyPI version](https://badge.fury.io/py/curl-cffi.svg)](https://badge.fury.io/py/curl-cffi)
[![Generic badge](https://img.shields.io/badge/Telegram%20Channel-join-blue?logo=telegram)](https://t.me/impersonate_pro)
[![Generic badge](https://img.shields.io/badge/Discord-join-purple?logo=blue)](https://discord.gg/kJqMHHgdn2)
[Documentation](https://curl-cffi.readthedocs.io)
Python binding for [curl-impersonate fork](https://github.com/lexiforest/curl-impersonate)
via [cffi](https://cffi.readthedocs.io/en/latest/). For commercial support, visit [impersonate.pro](https://impersonate.pro).
`curl_cffi` is the most popular Python binding for `curl`. Unlike other pure
python http clients like `httpx` or `requests`, `curl_cffi` can impersonate
browsers' TLS/JA3 and HTTP/2 fingerprints. If you are blocked by some
website for no obvious reason, you can give `curl_cffi` a try.
Python 3.10 is the minimum supported version since v0.14.
## Recent highlights
- 💨 http/3 fingerprints and UDP socks5 proxy support was added in `v0.15.0`!
- 🦞 Added `curl-cffi` CLI and skills for debugging and for claws/agents.
## Recall.ai - API for meeting recordings
<a href="https://www.recall.ai/?utm_source=github&utm_medium=sponsorship&utm_campaign=lexiforest-curl_cffi" target="_blank"><img src="https://cdn.prod.website-files.com/620d732b1f1f7b244ac89f0e/66b294e51ee15f18dd2b171e_recall-logo.svg" alt="Recall.ai" height="47" width="149"></a>
If youre looking for a meeting recording API, consider checking out [Recall.ai](https://www.recall.ai/?utm_source=github&utm_medium=sponsorship&utm_campaign=lexiforest-curl_cffi), an API that records Zoom, Google Meet, Microsoft Teams, in-person meetings, and more.
## Residential Proxies
<a href="https://www.thordata.com/?ls=github&lk=curl_" target="_blank"><img src="https://raw.githubusercontent.com/lexiforest/curl_cffi/main/assets/thordata.png" alt="Thordata" height="126" width="240"></a>
Thordata: A reliable and cost-effective proxy service provider. One-click collection of public network data, providing enterprises and developers with stable, efficient, and compliant global proxy IP services. Register for a free trial of [residential proxies](https://www.thordata.com/?ls=github&lk=curl_) and receive 2000 free SERP API calls.
## Sponsors
Maintenance of this project is made possible by all the <a href="https://github.com/lexiforest/curl_cffi/graphs/contributors">contributors</a> and <a href="https://github.com/sponsors/lexiforest">sponsors</a>. If you'd like to sponsor this project and have your avatar or company logo appear below <a href="https://github.com/sponsors/lexiforest">click here</a>. 💖
------
### Bypass Cloudflare with API
<a href="https://yescaptcha.com/i/stfnIO" target="_blank"><img src="https://raw.githubusercontent.com/lexiforest/curl_cffi/main/assets/yescaptcha.png" alt="Yes Captcha!" height="47" width="149"></a>
Yescaptcha is a proxy service that bypasses Cloudflare and uses the API interface to
obtain verified cookies (e.g. `cf_clearance`). Click [here](https://yescaptcha.com/i/stfnIO)
to register: <https://yescaptcha.com/i/stfnIO>
------
<a href="https://hypersolutions.co/?utm_source=github&utm_medium=readme&utm_campaign=curl_cffi" target="_blank"><img src="https://raw.githubusercontent.com/lexiforest/curl_cffi/main/assets/hypersolutions.png" height="47" width="149"></a>
TLS fingerprinting alone isn't enough for modern bot protection. [Hyper Solutions](https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=curl_cffi) provides the missing piece - API endpoints that generate valid antibot tokens for:
Akamai • DataDome • Kasada • Incapsula
No browser automation. Just simple API calls that return the exact cookies and headers these systems require.
🚀 [Get Your API Key](https://hypersolutions.co?utm_source=github&utm_medium=readme&utm_campaign=curl_cffi) | 📖 [Docs](https://docs.justhyped.dev) | 💬 [Discord](https://discord.gg/akamai)
------
## Features
- Supports JA3/TLS and http2 fingerprints impersonation, including recent browsers and custom fingerprints.
- Much faster than requests/httpx, on par with aiohttp/pycurl, see [benchmarks](https://github.com/lexiforest/curl_cffi/tree/main/benchmark).
- Mimics the requests API, no need to learn another one.
- Pre-compiled, so you don't have to compile on your machine.
- Supports `asyncio` with proxy rotation on each request.
- Supports http 2.0, which requests does not.
- Supports http 3.0, with fingerprints and udp proxy.
- Supports websocket.
- MIT licensed.
||requests|aiohttp|httpx|pycurl|curl_cffi|
|---|---|---|---|---|---|
|http/2|❌|❌|✅|✅|✅|
|http/3|❌|❌|❌|☑️<sup>1</sup>|✅<sup>2</sup>|
|sync|✅|❌|✅|✅|✅|
|async|❌|✅|✅|❌|✅|
|websocket|❌|✅|❌|❌|✅|
|native retry|❌|❌|❌|❌|✅|
|fingerprints|❌|❌|❌|❌|✅|
|speed|🐇|🐇🐇|🐇|🐇🐇|🐇🐇|
Notes:
1. For pycurl, http/3 is usually disabled at compile time by default.
2. http/3 support since v0.11.4, http/3 proxy and fingerprints since v0.15.0.
### curl-cffi CLI(new)
Since v0.15, `curl_cffi` comes with a CLI called `curl-cffi`, you can use it for debugging
a certain url with the `--impersonate` option. It can also serve as a `web_fetch`
replacement for "claws" and "agents".
||curl|httpie|curl-cffi|
|---|---|---|---|
|http/2|✅|❌|✅|
|http/3|☑️<sup>1</sup>|❌|✅|
|human-friendly|☑️<sup>2</sup>|✅|✅|
|colorful|❌|✅|✅|
|fingerprints|❌|❌|✅|
Notes:
1. You need an http/3 enabled curl build, it's not enabled by default, at leat on my machine.
2. As a long time command line user, I personally feel very comfortable using `curl -X POST httpbin.org`, but some users may prefer `http GET httpbin.org` syntax. If you prefer the curl syntax, you can keep using `curl-impersonate`.
## Install
pip install curl_cffi --upgrade
This should work on Linux, macOS and Windows out of the box.
If it does not work on you platform, you may need to compile and install `curl-impersonate`
first and set some environment variables like `LD_LIBRARY_PATH`.
Android support, including Termux, is currently in beta, you can install the beta release for testing.
For BSD systems, we need to get libcurl-impersonate compile first, and then add support in curl_cffi.
If you are using these OSes, please lend an hand.
To install beta releases:
pip install curl_cffi --upgrade --pre
To install unstable version from GitHub:
git clone https://github.com/lexiforest/curl_cffi/
cd curl_cffi
make preprocess
pip install .
## Usage
`curl_cffi` comes with a low-level `curl` API and a high-level `requests`-like API.
`curl_cffi` also bundles with a CLI called `curl-cffi`.
### CLI
```sh
curl-cffi get tls.browserleaks.com/json
# curl-cffi can be hard to type, use an alias if you want
alias imp=curl-cffi
imp get tls.browserleaks.com/json --impersonate chrome
```
For a complete CLI guide, see [docs](https://curl-cffi.readthedocs.io).
### requests-like
```python
import curl_cffi
# Notice the impersonate parameter
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome")
print(r.json())
# output: {..., "ja3n_hash": "aa56c057ad164ec4fdcb7a5a283be9fc", ...}
# the js3n fingerprint should be the same as target browser
# To keep using the latest browser version as `curl_cffi` updates,
# simply set impersonate="chrome" without specifying a version.
# Other similar values are: "safari" and "safari_ios"
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome")
# Use http/3 with impersonation
r = curl_cffi.get(
"https://fp.impersonate.pro/api/http3",
http_version="v3",
impersonate="chrome"
)
# Randomly choose a browser version based on current market share in real world
# from: https://caniuse.com/usage-table
# NOTE: this is a pro feature.
r = curl_cffi.get("https://example.com", impersonate="realworld")
# To pin a specific version, use version numbers together.
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome124")
# To impersonate other than browsers, bring your own ja3/akamai strings
# See examples directory for details.
r = curl_cffi.get("https://tls.browserleaks.com/json", ja3=..., akamai=...)
# http/socks proxies are supported
proxies = {"https": "http://localhost:3128"}
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome", proxies=proxies)
proxies = {"https": "socks://localhost:3128"}
r = curl_cffi.get("https://tls.browserleaks.com/json", impersonate="chrome", proxies=proxies)
```
### Sessions
```python
s = curl_cffi.Session()
# httpbin is a http test website, this endpoint makes the server set cookies
s.get("https://httpbin.org/cookies/set/foo/bar")
print(s.cookies)
# <Cookies[<Cookie foo=bar for httpbin.org />]>
# retrieve cookies again to verify
r = s.get("https://httpbin.org/cookies")
print(r.json())
# {'cookies': {'foo': 'bar'}}
```
### Supported impersonate browsers
`curl_cffi` supports the same browser versions as supported by my [fork](https://github.com/lexiforest/curl-impersonate) of [curl-impersonate](https://github.com/lwthiker/curl-impersonate):
Open source version of curl_cffi includes versions whose fingerprints differ from previous versions.
If you see a version, e.g. `chrome135`, were skipped, you can simply impersonate it with your own headers and the previous version.
If you don't want to look up the headers etc, by yourself, consider buying commercial support from [impersonate.pro](https://impersonate.pro),
we have comprehensive browser fingerprints database for almost all the browser versions on various platforms.
If you are trying to impersonate a target other than a browser, use `ja3=...` and `akamai=...`
to specify your own customized fingerprints. See the [docs on impersonation](https://curl-cffi.readthedocs.io/en/latest/impersonate/_index.html) for details.
|Browser|Open Source| Pro version|
|---|---|---|
|Chrome|chrome99, chrome100, chrome101, chrome104, chrome107, chrome110, chrome116<sup>[1]</sup>, chrome119<sup>[1]</sup>, chrome120<sup>[1]</sup>, chrome123<sup>[3]</sup>, chrome124<sup>[3]</sup>, chrome131<sup>[4]</sup>, chrome133a<sup>[5][6]</sup>, chrome136<sup>[6]</sup>, chrome142, chrome145<sup>[9]</sup>, chrome146<sup>[9]</sup>|chrome132, chrome134, chrome135|
|Chrome Android| chrome99_android, chrome131_android <sup>[4]</sup>|chrome132_android, chrome133_android, chrome134_android, chrome135_android|
|Chrome iOS|N/A|coming soon|
|Safari <sup>[7]</sup>|safari153 <sup>[2]</sup>, safari155 <sup>[2]</sup>, safari170 <sup>[1]</sup>, safari180 <sup>[4]</sup>, safari184 <sup>[6]</sup>, safari260 <sup>[8]</sup>|coming soon|
|Safari iOS <sup>[7]</sup>| safari172_ios<sup>[1]</sup>, safari180_ios<sup>[4]</sup>, safari184_ios <sup>[6]</sup>, safari260_ios <sup>[8]</sup>|coming soon|
|Firefox|firefox133<sup>[5]</sup>, firefox135<sup>[7]</sup>, firefox144, firefox147<sup>[9]</sup>|coming soon|
|Firefox Android|N/A|firefox135_android|
|Tor|tor145 <sup>[7]</sup>|coming soon|
|Edge|edge99, edge101|edge133, edge135|
|Opera|N/A|coming soon|
|Brave|N/A|coming soon|
Notes:
1. Added in version `0.6.0`.
2. Fixed in version `0.6.0`, previous http2 fingerprints were [not correct](https://github.com/lwthiker/curl-impersonate/issues/215).
3. Added in version `0.7.0`.
4. Added in version `0.8.0`.
5. Added in version `0.9.0`.
6. The version postfix `-a`(e.g. `chrome133a`) means that this is an alternative version, i.e. the fingerprint has not been officially updated by browser, but has been observed because of A/B testing.
5. Added in version `0.10.0`.
6. Added in version `0.11.0`.
7. Since `0.11.0`, the format `safari184_ios` is preferred over `safari18_4_ios`, both are supported, but the latter is quite confusing and hard to parse.
8. Added in `0.12.0`.
9. http3 support included.
### Asyncio
```python
from curl_cffi import AsyncSession
async with AsyncSession() as s:
r = await s.get("https://example.com")
```
More concurrency:
```python
import asyncio
from curl_cffi import AsyncSession
urls = [
"https://google.com/",
"https://facebook.com/",
"https://twitter.com/",
]
async with AsyncSession() as s:
tasks = []
for url in urls:
task = s.get(url)
tasks.append(task)
results = await asyncio.gather(*tasks)
```
For low-level APIs, Scrapy integration and other advanced topics, see the
[docs](https://curl-cffi.readthedocs.io) for more details.
### WebSockets
```python
from curl_cffi import WebSocket
def on_message(ws: WebSocket, message: str | bytes):
print(message)
ws = WebSocket(on_message=on_message)
ws.run_forever("wss://api.gemini.com/v1/marketdata/BTCUSD")
```
### Asyncio WebSockets
```python
import asyncio
from curl_cffi import AsyncSession
async with AsyncSession() as session:
async with session.ws_connect("wss://echo.websocket.org") as ws:
await asyncio.gather(*[ws.send_str("Hello, World!") for _ in range(10)])
async for message in ws:
print(message)
```
## Ecosystem
- Integrating with Scrapy: [divtiply/scrapy-curl-cffi](https://github.com/divtiply/scrapy-curl-cffi), [jxlil/scrapy-impersonate](https://github.com/jxlil/scrapy-impersonate) and [tieyongjie/scrapy-fingerprint](https://github.com/tieyongjie/scrapy-fingerprint).
- Integrating with [requests](https://github.com/el1s7/curl-adapter), [httpx](https://github.com/vgavro/httpx-curl-cffi) as adapter.
- Integrating with captcha resolvers: [YesCaptcha](https://yescaptcha.atlassian.net/wiki/spaces/YESCAPTCHA/overview). Please see the head area for promo code and link.
## Acknowledgement
- Originally forked from [multippt/python_curl_cffi](https://github.com/multippt/python_curl_cffi), which is under the MIT license.
- Headers/Cookies files are copied from [httpx](https://github.com/encode/httpx/blob/master/httpx/_models.py), which is under the BSD license.
- Asyncio support is inspired by Tornado's curl http client.
- The synchronous WebSocket API is inspired by [websocket_client](https://github.com/websocket-client/websocket-client).
- The asynchronous WebSocket API is inspired by [aiohttp](https://github.com/aio-libs/aiohttp).
## Contributing
When submitting an PR, please use a different branch other than `main` and check the
"Allow edits by maintainers" box, so I can update your PR with lint or style fixes. Thanks!
### AI Policy
- Using AI is neither encouraged nor discouraged, use it by your own choice.
- The bottom line here is that every line of code should be **reviewed by human**, and should be [proven to work](https://simonwillison.net/2025/Dec/18/code-proven-to-work/).
- It's not guaranteed that AI will come up with the cleanest solution, you are responsible to guide it to the right way you know.
- Fix any lint errors, make sure your code follows the established convention in this project.
- LLM tends to generate extensive or none comments, revise the comments and make sure they are concise and helpful.
- It's absolutely **not acceptable** to generate the entire PR summary by LLM. To communicate with other human, use words from a human.
- The only acceptable exception is to fix grammar issues if you are not a native English speaker.
- The essence here is to keep [Human in the loop](https://discourse.llvm.org/t/rfc-llvm-ai-tool-policy-human-in-the-loop/89159)
You can even feed the policy above to your "copilot" to let it adjust the style for you. :P
@@ -0,0 +1,60 @@
../../../bin/curl-cffi,sha256=1WNmf_w0emP0-PeIpDGlHiBy4Gdet6ASfQxBOR-BNMA,187
curl_cffi-0.15.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
curl_cffi-0.15.0.dist-info/METADATA,sha256=ryYvNCZOl96BIMI2134ZhyRWy7sr-0-xOc0Q_TfaU9A,18405
curl_cffi-0.15.0.dist-info/RECORD,,
curl_cffi-0.15.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
curl_cffi-0.15.0.dist-info/WHEEL,sha256=BX73HzL_Z8VmcUg66xwFel1CJ1goP9ZPbeeVSSFaesY,140
curl_cffi-0.15.0.dist-info/direct_url.json,sha256=lpNNgQ8844-2Q1nCwxiwtLw07Je0dsNXHPwhnLfnit4,313
curl_cffi-0.15.0.dist-info/entry_points.txt,sha256=HzTwoUpbiKIo5uJrqnxPk5OdxZ0PhT0dPTSqUP8Js70,49
curl_cffi-0.15.0.dist-info/licenses/LICENSE,sha256=PoiwKbULav021rGGQs5Mi27uTJA_HPq-9bgR9h4HBQs,1106
curl_cffi-0.15.0.dist-info/top_level.txt,sha256=b51YB50I_vu6XAbSERmqtgaYciYADCA_baVoZ_T5Lzs,10
curl_cffi/__init__.py,sha256=fPBkVIThnbk_a7U41V5S3Qwhh1_WxZkMerXQNv1iOpA,1781
curl_cffi/__main__.py,sha256=L0AH-xyDlgmsPM-HTecPVb1_hV9X35Qf1Mw7h7JVnx0,39
curl_cffi/__pycache__/__init__.cpython-314.pyc,,
curl_cffi/__pycache__/__main__.cpython-314.pyc,,
curl_cffi/__pycache__/__version__.cpython-314.pyc,,
curl_cffi/__pycache__/_asyncio_selector.cpython-314.pyc,,
curl_cffi/__pycache__/aio.cpython-314.pyc,,
curl_cffi/__pycache__/const.cpython-314.pyc,,
curl_cffi/__pycache__/curl.cpython-314.pyc,,
curl_cffi/__pycache__/utils.cpython-314.pyc,,
curl_cffi/__version__.py,sha256=FdOv9cpHIUGkFkcWA4O9gte0sun1QgJI69rIgzUkswo,413
curl_cffi/_asyncio_selector.py,sha256=dxKOC6B8mlRu3WYi0trSq0L-FsWV6l_pg9TP35OpDI4,13043
curl_cffi/_wrapper.abi3.so,sha256=4sMTX_Q2WMouO96xfxc3BZjZxnMZnLjZV8nF_FCU_zE,12691712
curl_cffi/aio.py,sha256=oTiffUFDNfxxSHmCVAsjX0CIOs4IuBQ6mhm4WuY5KZs,11925
curl_cffi/cli/__init__.py,sha256=y-XQAfYkBDN3ejfVex1aKy5bcqsPUglAvm-i177wM5I,7290
curl_cffi/cli/__pycache__/__init__.cpython-314.pyc,,
curl_cffi/cli/__pycache__/doctor.cpython-314.pyc,,
curl_cffi/cli/__pycache__/output.cpython-314.pyc,,
curl_cffi/cli/__pycache__/parse.cpython-314.pyc,,
curl_cffi/cli/__pycache__/request.cpython-314.pyc,,
curl_cffi/cli/__pycache__/run.cpython-314.pyc,,
curl_cffi/cli/doctor.py,sha256=4wfyWF44JLxDtoH9YCDdmxrJ-1cWbNwSXcMc9Aopd1c,416
curl_cffi/cli/output.py,sha256=YzWbYLJ2zowR6G9mJxeTytcPrnSk2WQVwfmv8V404X4,6709
curl_cffi/cli/parse.py,sha256=OzqGEZPqOrH2nq14UKnaXwKAblAw6V867tDEp9XSLdo,2549
curl_cffi/cli/request.py,sha256=MJskNMJBIR8oq_fvrPvsi61Wy-bR4-aC8QQJb1YcqRg,3522
curl_cffi/cli/run.py,sha256=WYaPbX9h85DZQNkDbUUyvp3bryaAuNOxnjU6GpenigQ,7554
curl_cffi/const.py,sha256=mF3H1kHsqj-dfd7GWHMHyuB2bZ3QZd61tC1iCZgEjyo,18523
curl_cffi/curl.py,sha256=woBPw1OQk4FH7neNETuj_GwqcQa1jCjd1tA0ZxPSTA8,26928
curl_cffi/py.typed,sha256=dcrsqJrcYfTX-ckLFJMTaj6mD8aDe2u0tkQG-ZYxnEg,26
curl_cffi/requests/__init__.py,sha256=3ZO7mC7gNJZydze0VQLEYpEc9dMlf1uRbFS-fxKSQPs,6148
curl_cffi/requests/__pycache__/__init__.cpython-314.pyc,,
curl_cffi/requests/__pycache__/cookies.cpython-314.pyc,,
curl_cffi/requests/__pycache__/errors.cpython-314.pyc,,
curl_cffi/requests/__pycache__/exceptions.cpython-314.pyc,,
curl_cffi/requests/__pycache__/headers.cpython-314.pyc,,
curl_cffi/requests/__pycache__/impersonate.cpython-314.pyc,,
curl_cffi/requests/__pycache__/models.cpython-314.pyc,,
curl_cffi/requests/__pycache__/session.cpython-314.pyc,,
curl_cffi/requests/__pycache__/utils.cpython-314.pyc,,
curl_cffi/requests/__pycache__/websockets.cpython-314.pyc,,
curl_cffi/requests/cookies.py,sha256=QDEuhtsSjh6iNAKmp5TnGyyAe8wdDJCADCHY_GWCeCc,11867
curl_cffi/requests/errors.py,sha256=R6N5lmOTdRukThkNGUihDAQRu8HSh27M8E3zfUJJX74,250
curl_cffi/requests/exceptions.py,sha256=ViyLx3XHii_s7kjrO3GhVOVXhq2_UsYfAQl8MPwDnEM,6187
curl_cffi/requests/headers.py,sha256=Q1jrRdJ2YMLOcl5W3WBaKZAdLbPGPPERJ6MYzos3YXk,11535
curl_cffi/requests/impersonate.py,sha256=dKRpbPTqLCABrCmSKmgXyhA1zmrv0DMuSuqQyhn5-FU,13389
curl_cffi/requests/models.py,sha256=SaN9QUYyljUDFDQnUrYZRl9KiUe25nb2c2ca-dfq3Nw,11487
curl_cffi/requests/session.py,sha256=LkfPvAr8BIVzB_K91xwh0wIPRW26mi2VJd1cEYorIho,58871
curl_cffi/requests/utils.py,sha256=zMKaWoXcAPFNBv6FglE3FSAPNuxYr_leUcWKnhfYecw,26618
curl_cffi/requests/websockets.py,sha256=RJVNqCDrlLWzQ12Ym9M5_T0SW4EmoqKUYsXXTaQmBRQ,71685
curl_cffi/utils.py,sha256=gRVzO-vhjf596V6kr_SjwHlwJfDIwTrPbRLJvvNlUNE,307
@@ -0,0 +1,6 @@
Wheel-Version: 1.0
Generator: setuptools (82.0.1)
Root-Is-Purelib: false
Generator: delocate 0.13.0
Tag: cp310-abi3-macosx_10_9_universal2
@@ -0,0 +1 @@
{"archive_info": {"hash": "sha256=bf985a468ffb52bdcdfa1dac713555144c7711521428cd9267578a208c8f45ab", "hashes": {"sha256": "bf985a468ffb52bdcdfa1dac713555144c7711521428cd9267578a208c8f45ab"}}, "url": "file:///Users/runner/work/yt-dlp/yt-dlp/build/universal2/curl_cffi-0.15.0-cp310-abi3-macosx_10_9_universal2.whl"}
@@ -0,0 +1,2 @@
[console_scripts]
curl-cffi = curl_cffi.cli:main
@@ -0,0 +1,23 @@
MIT License
Copyright (c) 2018 multippt
Copyright (c) 2022 curl_cffi developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More