A single Next.js App Router project with API route handlers, authentication, profiles, HLS playback, and an admin CMS for uploads.
https://streamly.sahilkhadtare.com
- Node.js 20+
- Docker (for Postgres and optional MinIO)
- FFmpeg installed locally (
ffmpeg -version)
- Next.js App Router + TypeScript (strict)
- Prisma + PostgreSQL
- NextAuth (Credentials provider)
- TailwindCSS + custom UI primitives
- Zustand for client state
- Zod validation
- HLS playback via hls.js with MP4 fallback
Copy .env.example to .env and adjust:
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/streaming"
NEXTAUTH_SECRET="replace-me"
NEXTAUTH_URL="http://localhost:3000"
MEDIA_STORAGE="local"
LOCAL_MEDIA_DIR="./storage"
S3_ENDPOINT=""
S3_ACCESS_KEY=""
S3_SECRET_KEY=""
S3_BUCKET=""
S3_REGION="us-east-1"
- Start Postgres (and optional MinIO):
docker compose up -d db minio
- Install deps:
npm install
- (Optional) Download demo media (seed no longer generates dummy assets):
npm run demo:videos
- Run migrations and seed:
npm run db:migrate npm run db:seed
- Start the app:
npm run dev
docker compose up --buildThe compose stack includes MinIO for S3-compatible storage at http://localhost:9001 (user/pass: minioadmin).
- Admin:
[email protected]/Admin@12345 - Demo user:
[email protected]/User@12345
- Sign in as admin.
- Create a movie or series under
/admin. - For movies: open the title page and upload an MP4 (and optional poster/backdrop/VTT).
- For series: create a season + episode, then upload the episode MP4.
- Media jobs will show
PROCESSINGuntil HLS and thumbnail generation completes.
- Download curated sample MP4s into local storage:
This also extracts poster/backdrop JPGs from the videos. If you're using S3/MinIO, set
npm run demo:videos
DEMO_UPLOAD_TO_S3=trueand the S3 env vars so uploads go to the bucket. - Run (or re-run) the seed to attach them:
npm run db:seed
- Local (default): files stored under
LOCAL_MEDIA_DIRand served via/api/media/*. - S3/MinIO: set
MEDIA_STORAGE=s3and fill S3 env vars. Ensure the bucket exists (createmediain MinIO) and is publicly readable for direct playback URLs.- If your app runs in Docker and MinIO is only reachable on the Docker network, set
S3_PUBLIC_ENDPOINTto a host-accessible URL (e.g.http://localhost:9000) so browsers can load media.
- If your app runs in Docker and MinIO is only reachable on the Docker network, set
npm run dev
npm run build
npm run start
npm run db:migrate
npm run db:seed- Playback uses HLS when available; MP4 fallback is automatic.
- If you are running inside Docker, the container installs FFmpeg for processing.