# Fansifter Video Clipper

A toolkit for turning music videos into short-form vertical marketing clips (9:16, TikTok/Reels ready). Two components live in this repository:

| Folder | What it is |
|---|---|
| [`lib/`](lib/README.md) | Pure Python processing library — the engine |
| [`demo-app/`](demo-app/README.md) | Full-stack web application — a UI wrapper around the library |

---

## `lib/` — the Python library

`fansifter_clipper` is a standalone Python package that does the actual video work:

- **Gemini AI analysis** — uploads a downsampled copy of the video to Gemini Flash and gets back ranked segment timestamps
- **Scene-equilibrium reframing** — splits each segment by scene cuts (PySceneDetect), computes a stable crop position per scene via MediaPipe face/pose detection, and applies it frame-by-frame with OpenCV
- **Cut-to-music mode** — a second pipeline that assembles a beat-synced 14-18 s highlight reel, aligning visual peaks to percussive audio onsets
- **Downloader utilities** — `GoogleDriveDownloader` for remote sources

The library is designed to be driven step-by-step from an external orchestrator (e.g. a web backend): `analyze()` returns segments the UI can show; `reframe_and_render()` takes the user-confirmed segments and produces the final clips.

See [`lib/README.md`](lib/README.md) for installation, full API reference, CLI usage, and configuration options.

---

## `demo-app/` — the web application

A project-management UI built on top of the library:

- **Backend**: FastAPI + SQLModel + PostgreSQL, Celery workers (Redis broker)
- **Frontend**: React + TypeScript, TanStack Query, shadcn/ui
- **Infrastructure**: `docker-compose.yml` spins up PostgreSQL + Redis locally; workers can run natively or in Docker

The app models each video as a **Project** that advances through a state machine (`uploading → analyzing → analysis_complete → processing → completed`). Phase 1 (Gemini analysis) and Phase 2 (clip generation) each run as a Celery task so the UI stays responsive. A mock mode skips the Gemini call and generates random test segments — useful for demos and cropping tests without API quota.

A second section, **Artist Socials**, manages a library of TikTok-style videos served from a local folder tree. Videos are auto-discovered on first browse, qualified by Gemini (checking for clean frames with no on-screen text and sufficient body visibility), and surfaced as a ready-to-clip source alongside file upload and Google Drive.

See [`demo-app/README.md`](demo-app/README.md) for setup instructions, environment variables, Docker vs native modes, and troubleshooting.

---

## Repository layout

```
fansifter-video-clipper/
├── lib/                    # Python library (fansifter_clipper package)
│   ├── src/fansifter_clipper/
│   ├── cli.py              # CLI entry point
│   └── pyproject.toml
└── demo-app/               # Web application
    ├── backend/            # FastAPI app + Celery tasks
    │   └── app/
    ├── frontend/           # React/TypeScript SPA
    │   └── src/
    ├── docker-compose.yml  # PostgreSQL + Redis for local dev
    ├── compose.yml         # Full-stack Docker services
    └── pyproject.toml      # uv workspace root (links backend → lib as editable dep)
```

The `demo-app/` is a **uv workspace**: `demo-app/pyproject.toml` declares `lib/` as an editable path dependency via `[tool.uv.sources]`, so any change to the library source is immediately visible to the backend without reinstalling.

---

## Quick start (local, no Docker)

```bash
# 1. Start infrastructure
cd demo-app && docker-compose up -d   # PostgreSQL on :5433, Redis on :6379

# 2. Backend + migrations
cd backend
uv sync
uv run alembic upgrade head
uv run uvicorn app.main:app --reload --port 8000

# 3. Celery worker (separate terminal)
cd demo-app/backend
uv run celery -A app.core.celery_app worker --loglevel=info --concurrency=2

# 4. Frontend (separate terminal)
cd demo-app/frontend
npm install && npm run dev   # http://localhost:5173
```

Requires: Python 3.12, Node 18+, FFmpeg (`brew install ffmpeg`), a Gemini API key in `demo-app/.env`.