Recode is a login-free video-to-GIF conversion app with an asynchronous processing pipeline.
You upload a video in the web UI, the backend enqueues a job in RabbitMQ, a worker converts the video with FFmpeg, and the UI polls until the GIF is ready to download.
- Drag-and-drop video upload (
react-dropzone) - Upload state UX (
idle->uploading->processing->done) - Animated UI transitions with Framer Motion
- Async job queue using RabbitMQ (
video_processingqueue) - Background media processing worker with
fluent-ffmpeg - Polling-based processing status endpoint
- Direct download endpoint for completed GIF files
- Shared local storage for uploaded and processed files (
/uploads) - Durable RabbitMQ messages and explicit ack/reject handling in worker
- Next.js 16 (App Router)
- React 19 + TypeScript
- Tailwind CSS 4
react-dropzonefor file intakemotion+lucide-reactfor UI animation and iconsamqplibfor RabbitMQ publishing
- Bun runtime + TypeScript
amqplibfor consuming queue messagesfluent-ffmpegfor video conversion
- RabbitMQ 3 management image via Docker Compose
- Local filesystem storage for media files
recode/
├─ docker-compose.yml # RabbitMQ service
├─ uploads/ # Uploaded videos + generated GIFs
├─ web/ # Next.js frontend + API routes
│ ├─ app/page.tsx # Drag/drop UI + polling logic
│ └─ app/api/
│ ├─ upload/route.ts # Saves upload + enqueues job
│ ├─ status/route.ts # Checks processed file existence
│ └─ download/route.ts # Serves generated GIF as attachment
└─ worker/
└─ src/index.ts # RabbitMQ consumer + FFmpeg conversion
- User drops a video in the UI (
web/app/page.tsx). - Frontend posts multipart form data to
POST /api/upload. - API route saves file to
../uploadsand enqueues job metadata tovideo_processing. - Worker consumes the job, runs FFmpeg, and writes:
processed-<original-upload-name>.gif
- Frontend polls
GET /api/status?fileName=<upload-name>every 2 seconds. - When the output exists, API returns a download URL.
- User downloads through
GET /api/download?file=<processed-name>.
Accepts multipart form data:
video(required): video filetitle(optional): currently passed through in responsedescription(optional): currently passed through in response
Behavior:
- Saves file into
uploads/using a timestamp-prefixed name - Publishes conversion job to RabbitMQ queue
video_processing - Returns JSON including
fileNameused for status checks
Behavior:
- Checks whether
uploads/processed-<fileName>.gifexists - Returns:
{ "status": "processing" }when not ready{ "status": "done", "downloadUrl": "/api/download?file=..." }when ready
Behavior:
- Reads requested file from
uploads/ - Returns attachment response with
Content-Type: image/gif
- Bun (recommended for this repo)
- Docker + Docker Compose
- FFmpeg installed on your machine and available in
PATH
From repo root:
docker compose up -dRabbitMQ services:
- AMQP:
localhost:5672 - Management UI:
http://localhost:15672(guest / guest)
cd web && bun install
cd ../worker && bun installIn one terminal:
cd worker
bun run src/index.tsIn another terminal:
cd web
bun run devOpen http://localhost:3000.
- Current RabbitMQ connection strings are hardcoded to
amqp://localhost:5672. - File storage is local disk only (
uploads/); no object storage integration yet. - Status tracking is file-existence based; no DB/state store currently used.
- Queue and output naming conventions are fixed in code.
- No authentication or authorization.
- No upload size/type validation beyond client-side accepted MIME group.
- No cleanup policy for old uploads/outputs.
- No retry/backoff strategy beyond queue reject behavior.
- No progress percentages (only processing complete vs not complete).
- Some scaffolding files remain placeholders (
web/lib/redis.ts,web/lib/rabbitmq.ts, emptyweb/Dockerfile).
- Move broker URL, queue name, and paths to environment variables
- Add file validation and max size enforcement
- Add signed/expiring download links and basic abuse controls
- Add persistent job state (Redis/Postgres) for richer statuses
- Add output options (fps, duration, resolution, crop)
- Add automatic cleanup/retention jobs
- Containerize worker + web for one-command full stack startup
No license file is currently defined in this repository.