# Thank You for Your Time

> Music videos, one moment at a time.


A free, open-source (MIT) passion project: a quieter way to consume music videos.

Each article embeds the **official** music video and pairs it with tour notes — color, camera, gaze, status cues — like a museum guide, with the occasional dry booth aside. The through-line is the **evolution of music videos through the rise and fall of MTV**, told as a short sequence of eras and trends (not an encyclopedia).

Working title is easy to rename: change `SITE_NAME` in `js/config.js`.

## Features

- Static site: plain HTML, CSS, and JS. No build step.
- Mobile-first layout tuned for phones and iPad Safari.
- Home page with hero, **Today’s drop**, seven-era timeline, and archive grid.
- Era filter + dedicated era pages.
- Article pages with YouTube privacy-enhanced embeds (`youtube-nocookie.com`).
- Data-driven articles with `publishDate` gating so future drops can be pre-staged.
- Daily drop target: **6:00 PM America/Los_Angeles**.

## Adding an article

1. Create `articles/<slug>.json` (see schema below).
2. Add a summary entry to `articles/manifest.json` (id, slug, title, artist, year, director, era, youtubeId, publishDate, embedBlocked).
3. Use an **official** YouTube ID (artist/label/VEVO). Verify with:

```bash
curl -s "https://www.youtube.com/oembed?format=json&url=https://www.youtube.com/watch?v=VIDEO_ID"
```

If a video refuses embedding, set `"embedBlocked": true`. The template will show a **Watch on YouTube** fallback.

4. Set `publishDate` to `YYYY-MM-DD`. The article stays hidden until that date at **18:00** in `America/Los_Angeles`.
5. Optional preview clock: set `DEMO_NOW_ISO` in `js/config.js`, or append `?sn_now=2026-11-05T18:05:00-08:00` while testing. Set `DEMO_NOW_ISO` to `null` for real time.

### JSON schema (article file)

```json
{
  "id": "slug",
  "slug": "slug",
  "title": "Song title",
  "artist": "Artist",
  "year": 1991,
  "director": "Name or omit",
  "era": "authenticity",
  "youtubeId": "xxxxxxxxxxx",
  "publishDate": "2026-11-05",
  "embedBlocked": false,
  "beforePlay": "Context before watching…",
  "tourNotes": [{ "cue": "Opening shot", "note": "…" }],
  "signsAndCodes": {
    "color": "…",
    "styling": "…",
    "camera": "…",
    "typography": "…",
    "gaze": "…",
    "statusPower": "…"
  },
  "whyItMattered": "…",
  "boothCommentary": ["One-liner", "Another"],
  "furtherWatching": ["Artist – Title (year)"]
}
```

Valid `era` ids are defined in `js/config.js`: `launch`, `color-barrier`, `authenticity`, `auteur`, `trl`, `viral`, `tiktok`.

## Local preview

```bash
cd mtv-ocean
python3 -m http.server 8765
```

Open `http://127.0.0.1:8765/`.

## Free hosting

Any static host works:

- **GitHub Pages** — push this folder (or `/docs`) and enable Pages.
- **Cloudflare Pages** — connect the repo or upload the folder; output directory is the site root.

No build command. Publish the files as-is.



## Wishing Well

A sitewide coin toss: **one person, one wish**, no currency. The UI is a count only — optional wish text is never collected or stored.

### How deduping works

- **Server:** salted SHA-256 of the visitor IP (`WELL_SALT|ip`). Raw IPs are never stored — only the hash.
- **Client:** a `localStorage` flag so returning browsers show the wished state immediately.
- **Shared IPs:** households, workplaces, schools, and VPNs that share one public IP count as **one wish**. That is intentional and acceptable for this tiny passion-project counter.

### Local preview (static + API)

```bash
cd mtv-ocean
WELL_SALT='choose-a-long-random-string' python3 server/well_server.py
# serves the site and /api/well on http://127.0.0.1:8777
```

Data file: `data/well.json` (hashes + daily counts). Reset by writing `{ "total": 0, "days": {}, "visitors": [] }`.

### Cloudflare Worker (free tier)

The production-shaped API lives in `worker/`:

1. Install Wrangler and log in: `npm i -g wrangler && wrangler login`
2. `cd worker && npm i`
3. Create KV: `wrangler kv namespace create WELL` (and a preview namespace if you want)
4. Paste the namespace ids into `wrangler.toml`
5. Set the salt: `wrangler secret put WELL_SALT`
6. Update `ALLOWED_ORIGINS` in `wrangler.toml` to your GitHub/Cloudflare Pages origin
7. `wrangler deploy`
8. Point the static site at the Worker by setting `API_BASE` in `js/config.js` to the Worker URL (or keep `""` and route `/api/*` on the same domain via Pages Functions / a route)

Endpoints:

- `GET /api/well` → `{ total, series: [{ date, cumulative }], wished }`
- `POST /api/well` → records a wish if new; same shape plus `already`


## Disclaimer

Independent, non-commercial passion project. Not affiliated with MTV, Paramount, any artist, or any label. Videos remain the property of their owners. Commentary is opinion and criticism.

## License

MIT — see [LICENSE](./LICENSE).