# Project Overview

**ABCC Media Server** is a self-hosted playout system for the Arabic Bible
Christian Church. It runs on a single Linux VM at `media.abcc.org` and delivers:

- A 24/7 HLS live stream driven by a weekly schedule
- A Roku channel with VOD playlists
- An admin dashboard for monitoring download status and schedule

## Entry Points

### Public URLs (consumed by clients)

| URL | Consumer | Description |
|-----|----------|-------------|
| `https://media.abcc.org/live/stream.m3u8` | Roku app, test.html, any HLS player | Live HLS stream |
| `https://media.abcc.org/roku/feeds/primary-feed.json` | Roku Direct Publisher, MainLoaderTask.brs | VOD channel feed |
| `https://media.abcc.org/roku/now-playing.json` | Roku app (NowPlayingTask.brs), test.html | Current block & video info |

### Admin Pages

| URL | Description |
|-----|-------------|
| `/admin/status.php` | Playlist download progress, packages, missing files |
| `/admin/schedule.php` | Full schedule viewer with active block highlighted |
| `/admin/daily-plan.php` | 30-hour plan viewer with live editor |
| `/admin/test.html` | Live stream + VOD test player |
| `/admin/showRoku.php` | Roku feed viewer |
| `/admin/uploadCookies.php` | Upload `cookies.txt` for yt-dlp; test YouTube API key |

### Server-Side Entry Points

| Command / Trigger | Entry Point | Purpose |
|-------------------|-------------|---------|
| `systemctl start abcc-live` | `scripts/setup.sh` | Live playout engine |
| cron `*/5 * * * *` | `scripts/update_now_playing.sh` | Writes `roku/now-playing.json` |
| cron `0 2 * * *` | `scripts/run.sh` | Sync playlists, download videos, regenerate plan |

---

## Directory Structure

```
/var/www/html/media/
├── config.php              ★ Global constants — all paths and URLs defined here
│
├── data/                   ★ Central data & config files
│   ├── playlists.json      Playlist definitions (WP category or YouTube playlist ID)
│   ├── schedule.json       Playout schedule (defaults + date overrides)
│   ├── packages.json       Content packages referenced by schedule
│   ├── daily-plan.json     Pre-computed 30-hour playout plan (regenerated by cron)
│   ├── yt_key.txt          YouTube Data API key (git-ignored)
│   └── cookies.txt         yt-dlp browser cookies (git-ignored)
│
├── admin/                  Admin dashboard (PHP)
│   ├── Schedule.php        Schedule data class (used by web + CLI)
│   ├── Playlist.php        Playlist data class
│   ├── VideoLibrary.php    Static utilities: video duration, title, path lookup
│   ├── DailyPlan.php       Daily plan loader with binary-search current-entry
│   ├── status.php          Playlist & download status dashboard
│   ├── schedule.php        Full schedule viewer + editor
│   ├── daily-plan.php      30-hour plan viewer + live editor
│   ├── showRoku.php        Roku feed viewer
│   └── uploadCookies.php   Cookie upload + YouTube API key tester
│
├── scripts/                All CLI scripts (VOD sync + live stream)
│   ├── run.sh              Master entry point (cron 2 AM); archives logs, purges >30 days
│   ├── Process.php         Main sync engine — fetches lists, downloads videos
│   ├── getFromWP.php       Fetches video metadata from WordPress REST API
│   ├── getPlaylist.sh      Fetches YouTube playlist IDs via Data API (atomic list.txt write)
│   ├── getVideo.sh         Downloads a single video: mp4 / jpg / json sidecar
│   ├── checkFile.sh        Moves tmp download into videos/, converts to mp4 if needed
│   ├── genFeed.php         Generates Roku JSON feed
│   ├── generate_daily_plan.php  Builds data/daily-plan.json
│   ├── encode_videos.sh    Encodes MP4s to HLS segments under live/hls/
│   ├── update_now_playing.sh    Writes roku/now-playing.json (cron every 5 min)
│   ├── gen_banners.py      Generates playlist + per-video banner images
│   ├── normalize_lists.php Upgrades list.txt files to 3-column format
│   ├── validate_plan.php   Validates daily plan vs now-playing
│   └── setup.sh            Installs dependencies; sets www-data group permissions on data/ logs/
│
├── videos/                 Downloaded MP4 files (git-ignored)
│   └── {playlist-id}/
│       ├── list.txt            Tab-separated: date \t videoId \t title (oldest first)
│       ├── {videoId}.mp4
│       ├── {videoId}.jpg       Thumbnail
│       ├── {videoId}.json      Metadata sidecar (duration, title, upload_date)
│       └── banner.png          Playlist banner (generated by gen_banners.py)
│
├── live/
│   ├── stream.php          HLS stream endpoint (logs to logs/stream.log)
│   └── hls/                Per-video HLS segment cache
│
├── logs/                   Runtime logs (www-data group write required)
│   ├── run.log             Latest sync run output
│   ├── run-YYYY-MM-DD.log  Archived daily sync logs (kept 30 days)
│   ├── stream.log          HLS stream: video changes + 5-min heartbeats
│   └── error.log           Download errors from getVideo.sh
│
└── roku/                   Roku feed (served publicly)
    ├── feeds/primary-feed.json   Roku Direct Publisher feed
    └── now-playing.json          Current block/video info (updated by cron)
```

## Key Data Files

| File | Purpose |
|------|---------|
| `data/playlists.json` | Defines all playlists: WP category or YouTube playlist ID |
| `data/schedule.json` | Playout schedule: `defaults` (every-day, Sunday) + `dates` overrides |
| `data/packages.json` | Curated video packages used by the schedule |
| `data/daily-plan.json` | Pre-computed 30-hour playout plan (regenerated nightly) |
| `data/yt_key.txt` | YouTube Data API key (git-ignored) |
| `data/cookies.txt` | yt-dlp auth cookies (git-ignored) |
| `roku/now-playing.json` | Real-time block + video info (public URL) |
| `roku/feeds/primary-feed.json` | Roku feed (public URL) |

## Services

| Service | Command | Purpose |
|---------|---------|---------|
| `abcc-live.service` | `systemctl status abcc-live` | Runs playout engine (setup.sh / FFmpeg) |
| cron | `crontab -l` | Runs `run.sh` (sync) and `update_now_playing.sh` |

## Class Design

Shared logic lives in `admin/` classes, usable from both web pages and CLI scripts:

| Class | File | Purpose |
|-------|------|---------|
| `Schedule` | `admin/Schedule.php` | Load schedule, packages, resolve current block |
| `Playlist` | `admin/Playlist.php` | Load playlist list.txt entries |
| `VideoLibrary` | `admin/VideoLibrary.php` | Video disk utilities (duration, title, segment path) |
| `DailyPlan` | `admin/DailyPlan.php` | Load daily plan, binary-search current entry |

All classes auto-load `config.php` if not already included.
