Openlier is an open-source AI YouTube thumbnail generator built with Next.js. It supports prompt-based generation, optional style references from YouTube links, local-browser cameo references, credit-based usage, and Stripe checkout.
- Next.js 16 (App Router) + React 19 + TypeScript
- Better Auth (GitHub OAuth)
- PostgreSQL (
pg) - Stripe (checkout + webhook)
- Google Gemini via server-side API key (prompt safety + image generation)
- AWS S3 (generated image storage)
- Zustand + Tailwind CSS
- Node.js 20+
- pnpm
- PostgreSQL database
- GitHub OAuth app
- Stripe account
- Google AI Studio server API key + YouTube Data API key
- AWS S3 bucket and IAM credentials
pnpm installCopy .env.example to .env.local and fill in the values you need:
cp .env.example .env.localMinimum local variables:
NEXT_PUBLIC_APP_URL=http://localhost:3000
BETTER_AUTH_URL=http://localhost:3000
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/DB_NAME
BETTER_AUTH_SECRET=replace-me-with-a-long-random-string
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=Keep the rest if you want the full product flow locally:
- Stripe for credit checkout
- Google AI Studio on the server + YouTube API for generation/reference enrichment
- S3 for storing generated images
- Cameo face references are stored only in the browser's
localStorage - Cameo images are never written to PostgreSQL or S3
- Cameo images are sent only inside the active
POST /api/generaterequest when the user uses#me - If the user switches browsers or devices, they need to scan their cameo again
Set GENERATE_IMAGES=false if you want to avoid real image generation while wiring the app locally.
The repo now ships with an idempotent local database bootstrap:
pnpm db:setupThis creates:
- Better Auth tables:
"user",session,account,verification - App tables:
thumbnail_session,thumbnail_generation,credit_purchase,konami_redemption
pnpm devOpen http://localhost:3000 and sign in with GitHub. Local auth still requires a GitHub OAuth app configured for your local callback URL.
pnpm dev- Start development serverpnpm build- Build production bundlepnpm start- Start production serverpnpm lint- Run ESLintpnpm db:setup- Create/update the local PostgreSQL schema
POST /api/generate- Validate/enrich prompt and generate thumbnailGET /api/sessions- List user sessionsPOST /api/sessions- Create sessionGET /api/sessions/:id- Get generations for a sessionDELETE /api/sessions/:id- Delete sessionGET /api/images/:id- Resolve signed image URL / blob streamPOST /api/stripe/checkout- Create Stripe checkout sessionPOST /api/stripe/confirm- Confirm checkout resultPOST /api/stripe/webhook- Stripe webhook handlerGET /api/youtube/channel- Fetch channel-based style referencesGET /api/youtube/video- Fetch video metadata/thumbnailPOST /api/konami- One-time bonus creditsGET/POST /api/auth/[...all]- Better Auth endpoints
- User signs in with GitHub.
- User creates a session.
- User submits prompt (+ optional references).
- If the prompt uses
#me, the browser attaches the locally stored cameo image to that single request. - API deducts 1 credit and runs Gemini safety/enrichment.
- If enabled, image is generated and uploaded to S3.
- Generation metadata is stored in PostgreSQL.
- Set all environment variables in your hosting platform.
- Provision PostgreSQL and run
pnpm db:setupbefore first request. - Expose a public HTTPS URL for
POST /api/stripe/webhookand configure it in Stripe. - Build and run:
pnpm build
pnpm start401 Unauthorized: verify session/auth cookies and GitHub OAuth config.Error generating image: verify the server-sideGOOGLE_AI_STUDIO_API_KEYandGENERATE_IMAGES=true.- Stripe webhook errors: verify
STRIPE_WEBHOOK_SECRETand raw-body signature handling. - YouTube lookup failures: verify
YOUTUBE_API_KEYand quota. - Missing image previews: verify S3 credentials, bucket name, and region.
#medoes not work: re-scan the cameo in the same browser; it is stored only locally and is not shared across devices.- DB relation errors: run
pnpm db:setupand confirmDATABASE_URLpoints to the expected database.