# MeTube
A YouTube-style video platform: accounts, uploads, a browsable catalogue, likes,
threaded comments, and channel subscriptions.
It runs on **Node's standard library alone** — no npm dependencies. The HTTP
server, router, session auth, multipart upload parser and range-request media
server are all hand-rolled, and the database is Node 22's built-in
`node:sqlite`. The front end is a vanilla ES-module SPA with no build step.
## Running it
```bash
npm run seed # creates the database and renders sample videos with ffmpeg
npm start # http://localhost:3000
```
`npm run dev` restarts on file changes. `npm run reset` wipes the database and
all media, then re-seeds from scratch.
Requirements: **Node 22.5+** (for `node:sqlite`) and **ffmpeg/ffprobe** on your
PATH — used to probe durations and cut thumbnails on upload, and to generate the
sample clips.
### Demo accounts
The seed builds six channels and five viewers. Sign in as any of them with the
password `password123`:
| Channel | About |
| --- | --- |
| `pixelforge` | Generative art and shader breakdowns |
| `quietkitchen` | Slow cooking, sharp knives |
| `northbound` | Long walks in cold places |
| `lowlatency` | Competitive play and frame data |
| `roomtone` | Home recording on a budget |
| `thedailyloop` | A five-minute news digest |
Viewer accounts: `marta`, `dev_haruki`, `clara_b`, `sam.reads`, `tuesday`.
## What it does
**Accounts** — sign up, sign in, sign out. Passwords are hashed with scrypt
(16384/8/1) and compared in constant time; sessions are opaque 32-byte tokens in
an `HttpOnly`, `SameSite=Lax` cookie, expiring after 30 days.
**Browse** — a paginated home grid, category filters, search across titles,
descriptions and channel names, a trending sort, and a subscriptions feed.
Hovering a card cross-fades the still into the real video, muted, while an amber
hairline sweeps the frame and the duration badge counts down.
**Watch** — an HTML5 player served over HTTP range requests, so seeking works
against the file on disk. Views are counted once playback actually starts and
recorded to your history. Likes and dislikes render as a two-sided meter with a
ratio bar underneath.
**Comments** — post, reply one level deep, like, and delete. A video's owner can
remove any comment on it; everyone can remove their own. Comments from the
channel that published the video are badged `CREATOR`. Sort by top or newest.
**Subscriptions** — subscribe from a watch page or a channel page; your
subscriptions appear in the sidebar with video counts and drive the feed.
**Upload** — drag-and-drop or browse, with a real progress bar (XHR) and a
streaming server-side parser that writes straight to disk rather than buffering
the file in memory. Duration is probed and a thumbnail is cut with ffmpeg. Limit
512 MB; MP4, WebM, MOV and OGG.
**Your channel** — edit your display name, bio and avatar colour; edit or delete
your videos (deleting removes the media files too).
**Library** — history (with a clear button), liked videos, and watch later.
Plus: light and dark themes, keyboard focus styles throughout, `/` to focus
search, `prefers-reduced-motion` respected (hover previews are disabled), and a
layout that works down to a phone.
## Layout
```
server/
index.js HTTP server, routing, static + media serving
routes.js every API endpoint
model.js queries and JSON shaping
db.js schema and connection
auth.js password hashing, sessions, cookies
multipart.js streaming multipart/form-data parser
static.js file serving with Range support
http.js request/response helpers
public/
index.html app shell
css/app.css design tokens and components
js/ router, store, API client, DOM helpers, views
scripts/
seed.js demo data
seeddata.js channels, videos, comments
videoclips.js ffmpeg recipes for the sample clips
data/ SQLite database and uploaded media (gitignored)
```
## Design
The interface borrows the vocabulary of an editing suite rather than a social
app: deep slate panels, a single phosphor-amber accent, and every number —
durations, view counts, timestamps, subscriber totals — set in tabular monospace
like timecode. Type is Bricolage Grotesque for display, Public Sans for body,
JetBrains Mono for figures.
## Notes and limits
- Sessions live in SQLite; expired rows are ignored on lookup but not swept.
- Uploads are stored as-is — there is no transcoding, so playback depends on the
browser supporting the uploaded codec.
- Everything is served over HTTP for local use. Behind TLS you would want the
`Secure` flag on the session cookie.
- There is no rate limiting, moderation or email verification.
## The sample videos
The clips are generated, not downloaded: each is an ffmpeg render of a
generative source — Mandelbrot drifts, Conway's life, rule-110 automata,
Sierpinski carpets, gradient fields — graded and captioned, with a tone bed for
audio. Recipes live in `scripts/videoclips.js`, and each clip's variant picks
different coordinates, seeds and palettes so no two look alike.