Align self-host docs with payment-free OSS Docker image.

This commit is contained in:
Atakan Doğan Özban
2026-08-03 07:07:12 +02:00
parent 6bf2bffc55
commit 605487db0f
10 changed files with 102 additions and 70 deletions
+7 -5
View File
@@ -1,6 +1,8 @@
# Songs2VID # Songs2VID (hosted / SaaS checkout)
Create YouTube videos from an image and audio files. Create YouTube videos from an image and audio files. This tree is the **hosted SaaS** codebase (billing, credits, marketing landing).
For the **payment-free self-hosted OSS** product (no Stripe), use Gitea branch `main` / image [`atakanozban/songs2vid:latest`](https://hub.docker.com/r/atakanozban/songs2vid) and the docs at [docs.songs2vid.com](https://docs.songs2vid.com). Self-host install guides in `website/docs/` describe that OSS path.
## Stack ## Stack
@@ -11,14 +13,14 @@ Create YouTube videos from an image and audio files.
- FFmpeg for video encoding - FFmpeg for video encoding
- YouTube Data API v3 - YouTube Data API v3
## Editions ## Editions (this SaaS tree)
| Edition | How | Limits | | Edition | How | Limits |
|---------|-----|--------| |---------|-----|--------|
| **Hosted** (default) | Leave `S2VID_EDITION` unset | Free / Pro quotas and API gates | | **Hosted** (default) | Leave `S2VID_EDITION` unset | Free / Pro quotas and API gates |
| **Self-hosted / OSS** | `S2VID_EDITION=selfhosted` | No video quota, no API rate caps; playlists + API unlocked | | **Self-hosted flag** | `S2VID_EDITION=selfhosted` | No video quota, no API rate caps; playlists + API unlocked |
Docker Compose sets `S2VID_EDITION=selfhosted` automatically. Prefer the published OSS image for new self-host installs. Docker Compose in this tree still sets `S2VID_EDITION=selfhosted` when you run it locally.
## Quick start (Docker) ## Quick start (Docker)
+1 -1
View File
@@ -409,7 +409,7 @@ YouTube upload limits (channel daily caps, etc.) are enforced by Google, not Son
|--------|------| |--------|------|
| `400` | Validation error (bad file type, invalid layout, missing fields, bad JSON) | | `400` | Validation error (bad file type, invalid layout, missing fields, bad JSON) |
| `401` | Missing or invalid API key | | `401` | Missing or invalid API key |
| `403` | YouTube not connected, or edition/plan does not allow API features | | `403` | YouTube not connected, or the request is not allowed for this account |
| `404` | Job not found | | `404` | Job not found |
| `429` | API rate limit exceeded — body includes `retryAfterSeconds`; header `Retry-After` is set | | `429` | API rate limit exceeded — body includes `retryAfterSeconds`; header `Retry-After` is set |
+4 -5
View File
@@ -4,9 +4,9 @@ sidebar_position: 1
# API overview # API overview
Programmatic uploads and batch jobs for self-hosted Songs2VID. Generate your API key under **Dashboard → Settings → API access**. Programmatic uploads and batch jobs for self-hosted Songs2VID. Generate your API key under **Dashboard → Settings → API key**.
Keys start with `s2yt_live_` and are shown once at creation. Keys start with `s2yt_live_` and are shown once at creation. The OSS / Docker image always allows API use — there is no plan or credit gate.
## Authentication ## Authentication
@@ -18,14 +18,13 @@ Authorization: Bearer s2yt_live_your_key_here
Requirements: Requirements:
- `S2VID_EDITION=selfhosted` (Compose sets this by default)
- YouTube channel connected (sign in with Google OAuth that includes YouTube scopes) - YouTube channel connected (sign in with Google OAuth that includes YouTube scopes)
OAuth setup: [Getting started](../getting-started.md) and Googles [OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server). YouTube scopes/API: [YouTube Data API Overview](https://developers.google.com/youtube/v3/getting-started). OAuth setup: [Getting started](../getting-started.md) and Googles [OAuth 2.0 for Web Server Applications](https://developers.google.com/identity/protocols/oauth2/web-server). YouTube scopes/API: [YouTube Data API Overview](https://developers.google.com/youtube/v3/getting-started).
## Rate limits ## Rate limits
Self-hosted editions use a very high per-account ceiling (effectively unlimited for normal automation). You will rarely see `429`. Self-hosted OSS uses a very high per-account ceiling (effectively unlimited for normal automation). You will rarely see `429`.
If a limit is hit, the response is **429** with `retryAfterSeconds` and a `Retry-After` header. See [Endpoints — HTTP errors](./endpoints.md#http-errors). If a limit is hit, the response is **429** with `retryAfterSeconds` and a `Retry-After` header. See [Endpoints — HTTP errors](./endpoints.md#http-errors).
@@ -36,7 +35,7 @@ If a limit is hit, the response is **429** with `retryAfterSeconds` and a `Retry
1. Upload each file with `POST /api/v1/upload` 1. Upload each file with `POST /api/v1/upload`
2. Create the job with `POST /api/v1/jobs` (JSON paths) 2. Create the job with `POST /api/v1/jobs` (JSON paths)
This avoids huge multipart bodies. Self-hosted max batch size is **100** tracks per job. This avoids huge multipart bodies. Max batch size is **100** tracks per job.
### One-shot batch: small packs only ### One-shot batch: small packs only
+18 -9
View File
@@ -6,13 +6,14 @@ sidebar_position: 4
Self-hosting in production means running the **web app** and the **worker** against shared Postgres, Redis, and upload storage, with a public HTTPS URL for OAuth. Self-hosting in production means running the **web app** and the **worker** against shared Postgres, Redis, and upload storage, with a public HTTPS URL for OAuth.
How you package that (bare metal, systemd, Kubernetes, Docker, a PaaS) is up to you. The Compose files in this repo are **optional examples**, not a required stack. How you package that (bare metal, systemd, Kubernetes, Docker, a PaaS) is up to you. The Compose files in the [OSS repo](https://git.atakanozban.com/Songs2VID/songs2vid) are **optional examples**, not a required stack.
Published image: [`atakanozban/songs2vid:latest`](https://hub.docker.com/r/atakanozban/songs2vid).
## What you must configure ## What you must configure
| Requirement | Notes | | Requirement | Notes |
|-------------|--------| |-------------|--------|
| `S2VID_EDITION=selfhosted` | Unlimited allowance, API, and Pro layout features. Root Compose injects this when you use that example. |
| `NEXTAUTH_URL` | Exact public origin users open (e.g. `https://songs2vid.example.com`), no trailing slash | | `NEXTAUTH_URL` | Exact public origin users open (e.g. `https://songs2vid.example.com`), no trailing slash |
| `NEXTAUTH_SECRET` | Strong random secret | | `NEXTAUTH_SECRET` | Strong random secret |
| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | OAuth Web client from Google Cloud | | `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | OAuth Web client from Google Cloud |
@@ -21,6 +22,8 @@ How you package that (bare metal, systemd, Kubernetes, Docker, a PaaS) is up to
| Worker process | Same `DATABASE_URL`, `REDIS_URL`, and `UPLOAD_DIR` as the web app | | Worker process | Same `DATABASE_URL`, `REDIS_URL`, and `UPLOAD_DIR` as the web app |
| Persistent uploads | Shared volume or disk for both web and worker | | Persistent uploads | Shared volume or disk for both web and worker |
Stripe, billing, credits, and pricing env vars are **not** used by the OSS self-hosted image.
Env reference: [Environment variables](./environment.md). Local setup: [Getting started](./getting-started.md). Env reference: [Environment variables](./environment.md). Local setup: [Getting started](./getting-started.md).
### Google OAuth (required) ### Google OAuth (required)
@@ -38,9 +41,9 @@ Users sign in with Google; they do not need their own Cloud credentials.
### After go-live ### After go-live
1. Open `NEXTAUTH_URL` and sign in 1. Open `NEXTAUTH_URL` and sign in (you land on the dashboard)
2. Confirm the YouTube channel connects 2. Confirm the YouTube channel connects under **Settings → YouTube**
3. Generate an API key under **Dashboard → Settings → API access** if you automate uploads 3. Generate an API key under **Settings → API key** if you automate uploads
4. Run a small test job (dashboard or [API](./api/overview.md)) 4. Run a small test job (dashboard or [API](./api/overview.md))
### Common issues ### Common issues
@@ -54,13 +57,19 @@ Users sign in with Google; they do not need their own Cloud credentials.
Put any reverse proxy you like in front (Caddy, nginx, Traefik, cloud load balancer) and terminate TLS there so `NEXTAUTH_URL` is HTTPS. Put any reverse proxy you like in front (Caddy, nginx, Traefik, cloud load balancer) and terminate TLS there so `NEXTAUTH_URL` is HTTPS.
## Optional examples in this repo ## Optional examples
These are starting points only. Adapt or ignore them. These are starting points only. Adapt or ignore them.
### Root `docker-compose.yml` ### Docker Hub + Compose
Builds web + worker + Postgres + Redis with `S2VID_EDITION=selfhosted`. Useful for a quick all-in-one box. App port defaults to `${S2VID_PORT:-3000}`. Pull the published image:
```bash
docker pull atakanozban/songs2vid:latest
```
The repo root `docker-compose.yml` builds web + worker + Postgres + Redis. Useful for a quick all-in-one box. App port defaults to `${S2VID_PORT:-3000}`.
```bash ```bash
docker compose up -d --build docker compose up -d --build
@@ -70,7 +79,7 @@ Compose reference: [Docker Compose docs](https://docs.docker.com/compose/).
### `deploy/songs2vid/` (Caddy sample) ### `deploy/songs2vid/` (Caddy sample)
Sample layout under `deploy/songs2vid/`: Compose services plus a [Caddyfile](https://caddyserver.com/docs/caddyfile) that reverse-proxies the app, optionally serves a static docs build, and optionally puts Prisma Studio behind basic auth. If present in your checkout, sample layout under `deploy/songs2vid/`: Compose services plus a [Caddyfile](https://caddyserver.com/docs/caddyfile) that reverse-proxies the app, optionally serves a static docs build, and optionally puts Prisma Studio behind basic auth.
Only relevant if you choose Caddy. Useful links: Only relevant if you choose Caddy. Useful links:
+6 -5
View File
@@ -13,6 +13,8 @@ Two files exist on purpose — they are not duplicates you both fill with secret
Workflow: copy once (`cp .env.example .env`), then edit **only** `.env`. Leave `.env.example` as the shared checklist. Workflow: copy once (`cp .env.example .env`), then edit **only** `.env`. Leave `.env.example` as the shared checklist.
The official OSS / Docker image is always self-hosted and payment-free. **Do not set Stripe, billing, or credit-related variables** for self-host — they are unused.
## Required for local development ## Required for local development
| Variable | Purpose | | Variable | Purpose |
@@ -32,18 +34,17 @@ Create OAuth credentials in [Google Cloud Console](https://console.cloud.google.
|----------|---------| |----------|---------|
| `TOKEN_ENCRYPTION_KEY` | Encrypts YouTube tokens at rest; falls back to `NEXTAUTH_SECRET` if unset | | `TOKEN_ENCRYPTION_KEY` | Encrypts YouTube tokens at rest; falls back to `NEXTAUTH_SECRET` if unset |
| `UPLOAD_DIR` | Upload storage path; defaults to `./uploads` (Compose uses `/app/uploads`) | | `UPLOAD_DIR` | Upload storage path; defaults to `./uploads` (Compose uses `/app/uploads`) |
| `FFMPEG_PATH` | Override bundled `ffmpeg-static` binary | | `FFMPEG_PATH` | Override FFmpeg binary (image defaults to system `ffmpeg`) |
| `S2VID_EDITION` | Set to `selfhosted` for unlimited video allowance, API access, and all layout features |
| `S2VID_PORT` | Host port for the optional root `docker-compose.yml` example (default `3000`) | | `S2VID_PORT` | Host port for the optional root `docker-compose.yml` example (default `3000`) |
| `NEXT_PUBLIC_GITEA_URL` | Footer / open-source link | | `NEXT_PUBLIC_GITEA_URL` | Footer / open-source link |
| `NEXT_PUBLIC_GITEA_ISSUES_URL` | Bug report link | | `NEXT_PUBLIC_GITEA_ISSUES_URL` | Bug report link |
| `NEXT_PUBLIC_DOCKER_HUB_URL` | Docker image link | | `NEXT_PUBLIC_DOCKER_HUB_URL` | Docker image link |
| `NEXT_PUBLIC_DOCS_URL` | Docusaurus docs site. Omit locally to use `http://localhost:3001` when `NEXTAUTH_URL` is localhost; production default `https://docs.songs2vid.com` | | `NEXT_PUBLIC_DOCS_URL` | Docs site URL (production default `https://docs.songs2vid.com`) |
| `ADMIN_API_KEY` | Optional Bearer token for internal admin HTTP routes. **Not required** for normal self-hosted operation | | `ADMIN_API_KEY` | Optional Bearer token for internal admin HTTP routes. **Not required** for normal self-hosted operation |
## Notes ## Notes
- User API keys are generated in Dashboard → Settings (hashed at rest). They are not env vars. - User API keys are generated in Dashboard → Settings → API key (hashed at rest). They are not env vars.
- Self-hosted deployments should set `S2VID_EDITION=selfhosted` (the optional root Compose example does this for you). - Full entitlements (layouts, API, playlists, unlimited allowance) are always on in the OSS image — there is no edition flag or paywall to enable.
- In production, `NEXTAUTH_URL` must match the public HTTPS URL users open in the browser, and the same origin must be listed as an OAuth redirect URI (`…/api/auth/callback/google`). See [Production notes](./deploy.md). - In production, `NEXTAUTH_URL` must match the public HTTPS URL users open in the browser, and the same origin must be listed as an OAuth redirect URI (`…/api/auth/callback/google`). See [Production notes](./deploy.md).
- Never commit `.env` or put production secrets in `.env.example`. - Never commit `.env` or put production secrets in `.env.example`.
+55 -37
View File
@@ -4,42 +4,61 @@ sidebar_position: 2
# Getting started # Getting started
Run Songs2VID locally for development or self-hosting. Run Songs2VID locally for development or self-hosting. The OSS edition is payment-free and always has full entitlements (no Stripe, credits, or plans).
## 1. Environment file Source: [Gitea — Songs2VID/songs2vid](https://git.atakanozban.com/Songs2VID/songs2vid) (`main`).
Image: [`atakanozban/songs2vid:latest`](https://hub.docker.com/r/atakanozban/songs2vid).
Copy the template, then edit **only** `.env` with your real values: ## Fastest path: Docker Compose
1. Copy the template, then edit **only** `.env`:
```bash ```bash
cp .env.example .env cp .env.example .env
``` ```
See [Environment variables](./environment.md) for required vs optional keys. Set `NEXTAUTH_SECRET`, `GOOGLE_CLIENT_ID`, and `GOOGLE_CLIENT_SECRET`. See [Environment variables](./environment.md).
## 2. PostgreSQL and Redis 2. Configure Google OAuth (below), then start the full stack:
For local app development (infra only):
```bash
docker compose -f docker-compose.dev.yml up -d
```
Or run the full stack (web + worker + DB) with the self-hosted edition — an optional Compose example:
```bash ```bash
docker compose up -d --build docker compose up -d --build
``` ```
Compose is not required; any Postgres + Redis that match your `.env` works. See [Docker Compose](https://docs.docker.com/compose/) if you use the examples above. Or pull the published image:
## 3. Install and migrate ```bash
docker pull atakanozban/songs2vid:latest
```
Open [http://localhost:3000](http://localhost:3000), sign in with Google, and use the dashboard.
Compose is not required; any Postgres + Redis that match your `.env` works. See [Docker Compose](https://docs.docker.com/compose/).
## Local development (app + worker)
### 1. Environment file
```bash
cp .env.example .env
```
### 2. PostgreSQL and Redis
```bash
docker compose -f docker-compose.dev.yml up -d
```
### 3. Install and migrate
```bash ```bash
npm install npm install
npm run db:push npm run db:migrate
``` ```
## 4. Google OAuth (`npm run db:push` is an alternative if you prefer schema push without migrations.)
### 4. Google OAuth
In [Google Cloud Console](https://console.cloud.google.com/) (server-side only — end users never enter credentials): In [Google Cloud Console](https://console.cloud.google.com/) (server-side only — end users never enter credentials):
@@ -52,21 +71,13 @@ In [Google Cloud Console](https://console.cloud.google.com/) (server-side only
Also set `NEXTAUTH_URL` to the same origin users open in the browser. Also set `NEXTAUTH_URL` to the same origin users open in the browser.
## 5. FFmpeg and fonts ### 5. FFmpeg and fonts
The worker needs FFmpeg. The `ffmpeg-static` npm package is used by default. Set `FFMPEG_PATH` only if you want a system binary instead. The worker needs FFmpeg. The Docker image includes system FFmpeg; locally, `ffmpeg-static` is used by default. Set `FFMPEG_PATH` only if you want a system binary instead.
For curated watermark fonts (Inter, Montserrat, etc.), ensure files exist under `assets/fonts`: For curated watermark fonts (Inter, Montserrat, etc.), ensure files exist under `assets/fonts` (see `assets/fonts/README.md` in the repo). Custom `.ttf` / `.otf` uploads work without that step. See [Video editing](./video-editing.md).
```bash ### 6. Start app and worker
node scripts/fetch-watermark-fonts.mjs
```
Custom `.ttf` / `.otf` uploads work without this step. See [Video editing](./video-editing.md).
## 6. Start app, worker, and docs
One command for everything:
```bash ```bash
npm run dev:all npm run dev:all
@@ -76,32 +87,39 @@ npm run dev:all
|---------|------------| |---------|------------|
| Next.js app | [http://localhost:3000](http://localhost:3000) | | Next.js app | [http://localhost:3000](http://localhost:3000) |
| BullMQ worker | Encodes videos and uploads to YouTube | | BullMQ worker | Encodes videos and uploads to YouTube |
| Docusaurus docs | [http://localhost:3001](http://localhost:3001) |
Or run them separately: Or run them separately:
```bash ```bash
npm run dev npm run dev
npm run worker npm run worker
npm run docs:dev
``` ```
## Authentication This docs site (Docusaurus) is maintained separately and published at [docs.songs2vid.com](https://docs.songs2vid.com).
Users sign in with Google via OAuth 2.0. The app connects their YouTube channel automatically — end users do not need Google Cloud credentials or API keys. ## Authentication and settings
Users sign in with Google via OAuth 2.0. The app connects their YouTube channel automatically — end users do not need Google Cloud credentials.
After sign-in you go straight to the dashboard. **Settings** includes:
- Account
- YouTube connection
- API key
There is no billing, pricing, or credit UI in the self-hosted OSS build.
## Production ## Production
For public HTTPS, OAuth redirect URIs, and worker checklist, see [Production notes](./deploy.md). Repo Compose/Caddy files there are optional examples only. For public HTTPS, OAuth redirect URIs, and worker checklist, see [Production notes](./deploy.md).
## Useful scripts ## Useful scripts
| Script | Purpose | | Script | Purpose |
|--------|---------| |--------|---------|
| `npm run dev:all` | App (3000) + worker + docs (3001) together | | `npm run dev:all` | App (3000) + worker together |
| `npm run dev` | Next.js dev server only | | `npm run dev` | Next.js dev server only |
| `npm run worker` | Background job processor only | | `npm run worker` | Background job processor only |
| `npm run docs:dev` | Documentation site only (port 3001) | | `npm run db:migrate` | Apply Prisma migrations |
| `npm run docs:build` | Static docs build (for Caddy / nginx) |
| `npm run db:push` | Push Prisma schema to the database | | `npm run db:push` | Push Prisma schema to the database |
| `npm run build` | Production build | | `npm run build` | Production build |
+8 -5
View File
@@ -5,9 +5,11 @@ slug: /intro
# Introduction # Introduction
**Songs2VID** turns a cover image and one or more audio files into YouTube-ready videos, then uploads them to your channel. **Songs2VID** turns a cover image and one or more audio files into YouTube-ready videos, then uploads them to your channel (FFmpeg encoding + BullMQ jobs).
This documentation is for **self-hosted / open-source** deployments (`S2VID_EDITION=selfhosted`). This documentation is for the **self-hosted / open-source** edition. That build is payment-free: no Stripe, no plans, no credits, and no paywall. Every deployment has full layout, API, and playlist entitlements.
Hosted cloud at [songs2vid.com](https://songs2vid.com) is a separate SaaS product and is not what these self-host guides describe.
## What you can do ## What you can do
@@ -24,15 +26,16 @@ See [Video editing](./video-editing.md) for composition controls in the dashboar
## Self-host ## Self-host
Follow [Getting started](./getting-started.md). Set `S2VID_EDITION=selfhosted` for unlimited video allowance, API access, and all layout features (the optional root Compose example sets this for you). Follow [Getting started](./getting-started.md). The recommended path is Docker with image
[`atakanozban/songs2vid:latest`](https://hub.docker.com/r/atakanozban/songs2vid) or a local Compose build from the [Gitea OSS repo](https://git.atakanozban.com/Songs2VID/songs2vid).
For local development, `npm run dev:all` starts the app (port 3000), worker, and this docs site (port 3001). After sign-in you land on the dashboard. Settings are limited to **account**, **YouTube**, and **API key** — there is no billing or pricing UI.
Going to a public URL? See [Production notes](./deploy.md) (OAuth redirect, worker, HTTPS). Docker/Caddy samples in the repo are optional. Going to a public URL? See [Production notes](./deploy.md) (OAuth redirect, worker, HTTPS). Docker/Caddy samples in the repo are optional.
## REST API ## REST API
Programmatic uploads and job creation. Generate an API key under **Dashboard → Settings → API access**. Start with [API overview](./api/overview.md). Programmatic uploads and job creation. Generate an API key under **Dashboard → Settings → API key**. Start with [API overview](./api/overview.md).
## Stack ## Stack
+1 -1
View File
@@ -37,7 +37,7 @@ YouTube metadata and on-video layout text are separate fields:
| `artist` | **Artist** | Artist line under the song title on art-track layouts | Max **80** characters | | `artist` | **Artist** | Artist line under the song title on art-track layouts | Max **80** characters |
- On the dashboard, video title is always editable. Song title and artist control the Layout Studio preview and the encoded frame. - On the dashboard, video title is always editable. Song title and artist control the Layout Studio preview and the encoded frame.
- If **video title** is left empty, Songs2VID falls back to ``${artist} - ${songTitle}`` (or whichever of those is present). Self-hosted editions always have this unlocked. - If **video title** is left empty, Songs2VID falls back to ``${artist} - ${songTitle}`` (or whichever of those is present). Self-hosted OSS always has art-track fields and layouts unlocked.
- ID3 tags (when readable) typically prefill song title / artist and a combined video title such as `Artist - Song`. - ID3 tags (when readable) typically prefill song title / artist and a combined video title such as `Artist - Song`.
Classic letterbox mode does not burn song title or artist into the frame; they still matter for the YouTube title fallback when video title is omitted. Classic letterbox mode does not burn song title or artist into the frame; they still matter for the YouTube title fallback when video title is omitted.
+1 -1
View File
@@ -4,7 +4,7 @@ import type * as Preset from '@docusaurus/preset-classic';
const config: Config = { const config: Config = {
title: 'Songs2VID', title: 'Songs2VID',
tagline: 'Image + audio to YouTube', tagline: 'Self-host image + audio to YouTube (payment-free OSS)',
favicon: 'img/favicon.png', favicon: 'img/favicon.png',
future: { future: {
+1 -1
View File
@@ -30,7 +30,7 @@ export default function Home(): ReactNode {
return ( return (
<Layout <Layout
title="Documentation" title="Documentation"
description="Songs2VID docs — self-host setup, video editing, and REST API."> description="Songs2VID docs — payment-free self-host setup, video editing, and REST API.">
<HomepageHeader /> <HomepageHeader />
<main> <main>
<section className="container margin-vert--xl"> <section className="container margin-vert--xl">