Metadata-Version: 2.4
Name: zefoy-client
Version: 0.1.1
Summary: Python client for zefoy.com — JSON-only API (login, services, send views/hearts/...)
Author: zefoy-client contributors
License: MIT
Project-URL: Homepage, https://github.com/deno4908/zefoy_lib
Project-URL: Repository, https://github.com/deno4908/zefoy_lib
Project-URL: Issues, https://github.com/deno4908/zefoy_lib/issues
Keywords: zefoy,tiktok,automation,api,client
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cloudscraper>=1.2.71
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: Pillow>=10.0.0
Requires-Dist: numpy>=1.24.0
Requires-Dist: ddddocr>=1.4.11
Requires-Dist: pycryptodome>=3.19.0
Requires-Dist: brotli>=1.1.0
Requires-Dist: requests>=2.31.0
Provides-Extra: ocr
Requires-Dist: pytesseract>=0.3.10; extra == "ocr"
Provides-Extra: socks
Requires-Dist: PySocks>=1.7.1; extra == "socks"
Requires-Dist: requests[socks]>=2.31.0; extra == "socks"
Provides-Extra: dev
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# zefoy-client

Python client library for [zefoy.com](https://zefoy.com).

- **JSON-only API** — every public method returns a `dict` (ready for `json.dumps`)
- No stdout noise from the library
- Captcha via **ddddocr** (optional manual captcha)
- Auto cooldown wait (IP-based server timer)
- Services: views, hearts, favorites, shares, followers, …

> **Disclaimer:** Unofficial. Use at your own risk. Respect site terms and local laws. For educational / automation research purposes.

---

## Install

### PyPI

```bash
pip install zefoy-client
```

Optional extras:

```bash
pip install "zefoy-client[socks]"   # SOCKS4/5 proxy
pip install "zefoy-client[ocr]"     # pytesseract helper
pip install "zefoy-client[socks,ocr]"
```

### GitHub

Repo: [https://github.com/deno4908/zefoy_lib](https://github.com/deno4908/zefoy_lib)

```bash
# latest main
pip install git+https://github.com/deno4908/zefoy_lib.git

# specific branch / tag
pip install git+https://github.com/deno4908/zefoy_lib.git@main
pip install git+https://github.com/deno4908/zefoy_lib.git@v0.1.0
```

Clone rồi cài editable (dev):

```bash
git clone https://github.com/deno4908/zefoy_lib.git
cd zefoy_lib
pip install -e .
# pip install -e ".[socks,ocr]"
```

### From local folder

```bash
cd zefoy-client
pip install -e .
```

### Build / publish wheel

```bash
pip install build twine
python -m build
twine check dist/*
# twine upload dist/*
```

---

## Quick start

```python
import json
from zefoy import Zefoy

bot = Zefoy(
    use_ocr=True,       # solve captcha with ddddocr
    auto_wait=True,     # sleep on server cooldown
    # proxy="http://user:pass@host:port",
)

print(json.dumps(bot.login(), ensure_ascii=False, indent=2))
print(json.dumps(bot.services(), ensure_ascii=False, indent=2))

url = "https://www.tiktok.com/@user/video/1234567890"
print(json.dumps(bot.send_views(url), ensure_ascii=False, indent=2))
```

### Proxy

`proxy` áp dụng cho **toàn session** (login + captcha + services + send).  
Hỗ trợ URL string hoặc dict kiểu `requests`.

| Loại | Ví dụ |
|------|--------|
| HTTP | `http://host:8080` |
| HTTP + auth | `http://user:pass@host:8080` |
| HTTPS proxy | `https://user:pass@host:8443` |
| SOCKS5 | `socks5://user:pass@host:1080` |
| SOCKS5h (DNS qua proxy) | `socks5h://user:pass@host:1080` |
| SOCKS4 | `socks4://host:1080` |

```bash
# SOCKS cần thêm dependency
pip install -e ".[socks]"
# hoặc: pip install PySocks requests[socks]
```

```python
from zefoy import Zefoy
import json

# 1) HTTP proxy (string — gán cả http & https)
bot = Zefoy(proxy="http://1.2.3.4:8080")

# 2) HTTP có user/pass
bot = Zefoy(proxy="http://myuser:mypass@1.2.3.4:8080")

# 3) SOCKS5
bot = Zefoy(proxy="socks5://user:pass@1.2.3.4:1080")

# 4) SOCKS5 + resolve DNS trên proxy
bot = Zefoy(proxy="socks5h://user:pass@1.2.3.4:1080")

# 5) Dict tách http / https (giống requests)
bot = Zefoy(proxy={
    "http": "http://user:pass@1.2.3.4:8080",
    "https": "http://user:pass@1.2.3.4:8080",
})

# 6) Dùng với send
url = "https://www.tiktok.com/@user/video/123"
print(json.dumps(bot.login(), ensure_ascii=False, indent=2))
print(json.dumps(bot.send_views(url), ensure_ascii=False, indent=2))
print(json.dumps(bot.send_hearts(url), ensure_ascii=False, indent=2))
```

CLI:

```bash
zefoy --proxy "http://user:pass@host:8080" send views "https://www.tiktok.com/@u/video/123"
zefoy --proxy "socks5h://user:pass@host:1080" send hearts "https://..."
```

> Proxy đổi IP → tránh / giảm cooldown theo IP của Zefoy. Proxy chết sẽ làm `login`/`send` trả `ok: false`.

### Manual captcha

```python
bot = Zefoy(use_ocr=False)
img = bot.get_captcha_image("captcha.png")  # open image yourself
print(bot.login(captcha_text="flower"))
```

### Custom captcha solver

```python
def my_solver(image):
    # image: PIL.Image
    return "answer"

bot = Zefoy(captcha_solver=my_solver)
bot.login()
```

---

## API

### `Zefoy(...)`

| Arg | Type | Default | Description |
|-----|------|---------|-------------|
| `use_ocr` | `bool` | `True` | Auto-solve captcha |
| `auto_wait` | `bool` | `True` | Wait on IP cooldown |
| `max_cooldown_retries` | `int` | `5` | Max wait/retry loops |
| `proxy` | `str` \| `dict` | `None` | Proxy URL hoặc dict `requests` (HTTP/HTTPS/SOCKS) |
| `captcha_solver` | `callable` | `None` | `f(PIL.Image) -> str` |
| `user_agent` | `str` | Chrome 131 | Must stay consistent per session |
| `on_event` | `callable` | `None` | Optional debug hook `f(dict)` |

### Methods (all return `dict`)

| Method | Description |
|--------|-------------|
| `login(captcha_text=None, max_tries=5)` | Captcha + session |
| `submit_captcha(text)` | Submit captcha only |
| `services()` / `get_services()` | List available services |
| `send(service, url)` | Search + send order |
| `send_views(url)` | Shortcut |
| `send_hearts(url)` | Shortcut |
| `send_favorites(url)` | Shortcut |
| `send_shares(url)` | Shortcut |
| `send_followers(url)` | Shortcut |
| `Zefoy.to_json(data)` | `json.dumps` helper |

`service` name examples: `"views"`, `"t-views"`, `"hearts"`, `"favorites"`, …

---

## Response shape

Every call looks like:

```json
{
  "ok": true,
  "...": "..."
}
```

### `login()` success

```json
{
  "ok": true,
  "status": "logged_in",
  "captcha": "flower",
  "attempts": []
}
```

### `services()` success

```json
{
  "ok": true,
  "count": 8,
  "services": [
    {
      "name": "t-views",
      "disabled": false,
      "action": "https://zefoy.com/c2VuZC9mb2xeb3dlcnNfdGlrdG9V"
    }
  ]
}
```

### `send_views()` success

```json
{
  "ok": true,
  "status": "sent",
  "service": "t-views",
  "target": "https://www.tiktok.com/@u/video/123",
  "video_id": "123",
  "zefoy_amount": 1000,
  "zefoy_amount_label": "1000 views",
  "wait_seconds": 552,
  "summary": "sent 1000 views | next_wait 552s"
}
```

> **Note:** `zefoy_amount` is decided by Zefoy, not by the caller.

### Error

```json
{
  "ok": false,
  "error": "cooldown",
  "wait_seconds": 91,
  "message": "Please wait 91 seconds before trying again."
}
```

Common `error` codes: `login_failed`, `captcha_rejected`, `cooldown`, `service_not_found`, `no_send_form`, `send_failed`, `max_retries`.

---

## CLI

After install:

```bash
zefoy login
zefoy services
zefoy send views "https://www.tiktok.com/@u/video/123"
```

Or:

```bash
python -m zefoy send views "https://..."
```

---

## Flow (internal)

1. **Login** — fetch captcha image → OCR/manual → POST `captchalogin` + encrypted fingerprint  
2. **Search** — `POST /{base64_action}` with `HASH=full_tiktok_url`  
3. **Send** — `POST` same endpoint with `HASH=video_id`  
4. Response body is `reverse + base64` (same as site JS)

Server cooldown is **IP-based**, not local-session-based. New process on same IP still waits.

---

## Project layout

```text
zefoy-client/
├── pyproject.toml
├── README.md
├── LICENSE
├── MANIFEST.in
├── examples/
│   └── basic.py
└── src/
    └── zefoy/
        ├── __init__.py
        ├── __main__.py
        └── client.py
```

---

## Publish to PyPI

```bash
python -m build
twine check dist/*
twine upload dist/*
```

Users install with:

```bash
pip install zefoy-client
# or from GitHub:
pip install git+https://github.com/deno4908/zefoy_lib.git
```

---

## License

MIT
