# Server Endpoints & Storage Layout

HTTP interface served by the ABCC Media Server (`media.abcc.org`).

## Public Endpoints

Consumed by Roku devices, the Roku app, and external clients.

| Method | Path | Consumer | Description |
|--------|------|----------|-------------|
| `GET` | `/live/stream.m3u8` | Roku app, HLS players | Live HLS stream manifest |
| `GET` | `/roku/feeds/primary-feed.json` | Roku Direct Publisher, `MainLoaderTask.brs` | VOD channel feed |
| `GET` | `/roku/now-playing.json` | `NowPlayingTask.brs`, `test.html` | Current block & video |
| `GET` | `/videos/{playlist}/{id}.mp4` | `start_live_stream.sh` (FFmpeg) | MP4 source files |

## Admin Endpoints

| Path | Description |
|------|-------------|
| `/admin/status.php` | Playlist download progress, packages, missing files |
| `/admin/schedule.php` | Full schedule viewer with active block highlighted |
| `/admin/test.html` | Live stream + VOD test player |
| `/admin/showRoku.php` | Roku feed viewer |
| `/admin/uploadCookies.php` | Upload `cookies.txt` for yt-dlp |

## Data Files

The server is a static file host — there is no REST API layer. All data is
read from files on disk by the admin PHP pages and shell scripts.

### Actual storage layout

```
/var/www/html/media/
├── data/
│   ├── playlists.json        Playlist definitions
│   ├── schedule.json         Playout schedule (all days in one file)
│   └── packages.json         All content packages in one file
│
├── live/
│   └── stream.m3u8           Live HLS manifest (written by FFmpeg)
│
├── videos/
│   └── {playlist-id}/
│       ├── list.txt           date \t videoId \t title
│       ├── {videoId}.mp4
│       └── {videoId}.json     duration, title, thumbnailUrl
│
└── roku/
    ├── feeds/primary-feed.json
    └── now-playing.json
```

### `schedule.json` structure

Single file at `data/schedule.json` with three sections:

```json
{
  "defaults": {
    "every-day": { "blocks": [...] },
    "Sunday":    { "blocks": [...] }
  },
  "dates": {
    "2026-03-15": { "blocks": [...] }
  }
}
```

Priority: `dates` → `Sunday` → `every-day`.
See `schedule.md` for block format details.

### Package file structure (`data/packages.json`)

```json
{
  "packages": {
    "PKG-MORNING": {
      "entries": [
        { "type": "playlist", "id": "sunday", "mode": "series", "count": 1 },
        { "type": "playlist", "id": "bumpers", "mode": "random" }
      ]
    }
  }
}
```

First entry = **primary** (plays once). Remaining entries = **fillers** (loop to fill remaining block time).

### `now-playing.json` structure

Written by `live/scripts/update_now_playing.sh` every 5 minutes:

```json
{
  "block":   { "title": "...", "contentId": "...", "start": "12:00", "end": "15:00" },
  "current": { "title": "...", "videoId": "...", "duration": 3600, "endsAt": "13:00" },
  "next": {
    "video": { "title": "...", "videoId": "..." },
    "block": { "title": "...", "contentId": "...", "start": "15:00" }
  },
  "updatedAt": "2026-03-09T12:05:00Z"
}
```

---
*Updated March 2026.*
