Metadata-Version: 2.4
Name: utube-shorts
Version: 0.1.0
Summary: AI-powered YouTube Shorts generator — script, TTS, visuals, assemble, upload
Author-email: Viet Dinh <dinhquocvietpro@gmail.com>
Requires-Python: >=3.12
Requires-Dist: anthropic>=0.109.2
Requires-Dist: elevenlabs>=2.53.0
Requires-Dist: google-api-python-client>=2.197.0
Requires-Dist: google-auth-httplib2>=0.4.0
Requires-Dist: google-auth-oauthlib>=1.4.0
Requires-Dist: httpx>=0.28.1
Requires-Dist: moviepy>=2.2.1
Requires-Dist: mutagen>=1.47.0
Requires-Dist: openai>=1.0.0
Requires-Dist: pillow>=11.3.0
Requires-Dist: pydantic>=2
Requires-Dist: pytest-asyncio>=1.4.0
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: requests>=2.34.2
Description-Content-Type: text/markdown

# utube

AI-powered YouTube Shorts generator. Give it a topic — it writes the script,
synthesizes narration, fetches stock visuals, assembles the video, and uploads
it to YouTube. Supports Vietnamese-language content via VBee TTS.

![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue)
![License: MIT](https://img.shields.io/badge/license-MIT-green)

## How it works

```
topic → script (LLM) → assets (TTS + visuals) → assemble → upload
```

| Step     | What happens                                     | Providers                    |
|----------|--------------------------------------------------|------------------------------|
| script   | LLM generates title, scenes, narration, tags     | Anthropic, OpenAI-compatible |
| assets   | TTS audio + stock visual fetched per scene       | OpenAI TTS, ElevenLabs, VBee |
| assemble | MoviePy builds the final MP4 + thumbnail         | —                            |
| upload   | Uploads to YouTube with title, description, tags | YouTube Data API v3          |

Each step is independently resumable — a failed or interrupted job can be
continued from where it left off.

## Examples

Videos generated with this tool:

- [YouTube Short #1](https://www.youtube.com/shorts/blu_iI4bHY4)
- [YouTube Short #2](https://www.youtube.com/shorts/Mkitm0neHWs)
- [YouTube Short #3](https://www.youtube.com/shorts/FbG8fyBLKKw)

## Requirements

- Python 3.12+
- [uv](https://docs.astral.sh/uv/) — dependency manager
- FFmpeg — required by MoviePy for video encoding

## Installation

```bash
git clone https://github.com/your-org/utube.git
cd utube
uv sync
```

## Configuration

```bash
cp .env.example .env
# Edit .env with your API keys
```

### Minimum required keys

| Variable          | Description                               |
|-------------------|-------------------------------------------|
| `LLM_PROVIDER`    | `anthropic` or `openai` (default: openai) |
| `ANTHROPIC_API_KEY` | Required if `LLM_PROVIDER=anthropic`    |
| `OPENAI_API_KEY`  | Required if `LLM_PROVIDER=openai`         |
| `TTS_PROVIDER`    | `openai`, `elevenlabs`, or `vbee`         |
| `PEXELS_API_KEY`  | Stock video/photo visuals (free tier works) |

See `.env.example` for the full variable reference.

## Usage

### Run end-to-end

```bash
uv run utube run --niche "5 mind-blowing facts about black holes"
```

Runs all four steps and uploads as **private** by default.

### Common flags

| Flag               | Description                                        |
|--------------------|----------------------------------------------------|
| `--visibility`     | `private` (default), `unlisted`, or `public`       |
| `--public`         | Shorthand for `--visibility public`                |
| `--no-auto`        | Stop after script — review before continuing       |
| `--audio-speed X`  | Narration speed multiplier (e.g. `1.2` for faster) |
| `--caption`        | Overlay on-screen text captions on each scene      |

### Resume or restart a job

```bash
uv run utube continue <job_id>                   # advance one step
uv run utube continue <job_id> --from assets     # restart from assets step
uv run utube status  <job_id>                    # inspect current state
```

Restart targets: `script`, `assets`, `assemble`, `upload`.

### YouTube auth (first time)

```bash
uv run utube auth     # opens browser, caches token
uv run utube whoami   # verify the connected channel
```

Place your Google OAuth client secret at `secrets/client_secret.json` before
running `auth`. See the [YouTube Data API docs](https://developers.google.com/youtube/v3/getting-started)
for how to create OAuth credentials.

### Job files

Each run creates a directory under `./jobs/<job_id>/` containing all
intermediate files: script JSON, per-scene MP3s, visuals, final MP4, and
thumbnail.

## Vietnamese content with VBee

[VBee](https://vbee.vn) is a Vietnamese AI TTS platform with high-quality
voices. Set it as your TTS provider to generate Vietnamese-language Shorts.

```env
TTS_PROVIDER=vbee
VBEE_API_TOKEN=your_token
VBEE_APP_ID=your_app_id
VBEE_VOICE_CODE=hn_female_ngochuyen_full_48k-fhg   # default
VBEE_WEBHOOK_URL=https://your-server.com/vbee/callback
VBEE_SPEED=1.0
```

VBee uses an async batch API — the tool submits the synthesis job and polls
the webhook URL for the result. `VBEE_WEBHOOK_URL` must be a publicly
reachable HTTPS endpoint that VBee can POST the audio back to.

## Extending

utube uses a provider registry pattern. Adding a new TTS, visuals, or LLM
provider requires only a new file — no edits to existing pipeline code.

### Example: add a TTS provider

```python
# src/utube/providers/tts/mytts.py
from utube.providers.registry import register_tts
from utube.providers.base import TTSProvider

@register_tts("mytts")
class MyTTS:
    async def synthesize(self, text: str, voice: str) -> bytes:
        ...  # return raw audio bytes
```

Then set `TTS_PROVIDER=mytts` in `.env`. The same pattern applies to:

- **LLM / script providers** — implement `ScriptProvider`, register with `@register_script`
- **Visuals providers** — implement `VisualProvider`, register with `@register_visual`

See `src/utube/providers/base.py` for the Protocol definitions.

## Development

```bash
uv run pytest                  # run all tests
uv run ruff check src tests    # lint
uv run mypy src                # type-check
```

Tests never hit the network — all HTTP and external clients are mocked.
New provider implementations should follow the same pattern.

## Contributing

Pull requests are welcome. For significant changes, open an issue first to
discuss the approach.

## License

MIT
