# Admin Guide

Day-to-day operations and maintenance for the ABCC Media Server.

---

## Daily Workflow

```bash
# Full sync: fetch playlists, download videos, regenerate plan + feed
bash /var/www/html/media/scripts/run.sh

# Or trigger individual steps manually:
php  /var/www/html/media/scripts/Process.php           # sync + download
php  /var/www/html/media/scripts/genFeed.php           # rebuild Roku feed
php  /var/www/html/media/scripts/generate_daily_plan.php  # rebuild daily plan
bash /var/www/html/media/scripts/encode_videos.sh      # encode HLS segments
```

## Admin UI Pages

All pages are at `https://media.abcc.org/admin/`.

### Status (`status.php`)

The main dashboard. Shows at a glance:

- **Playlists** — each playlist, its source (WP or YouTube), how many videos are in `list.txt`, how many MP4s are downloaded, and how many are missing.
- **Packages** — each package with download progress.
- **Missing Files** — all video IDs not yet on disk, with YouTube links to open them directly.

Use this page to know what needs downloading before a broadcast.

### Daily Plan (`daily-plan.php`)

Full 30-hour schedule viewer and live editor. Shows:

- **Now Playing** — current video with progress bar, HLS stream health check.
- **Full Schedule** — 5-level hierarchy: ① Schedule Day → ② Schedule Entry → ③ Package → ④ Package Entry → ⑤ Video.
  - `↺ filler loop` divider marks where Phase 1 (primary + one full rotation) ends and the filler-only loop begins.
  - `▶` highlights the currently playing entry.

**Collapsible rows** — click a ② Schedule Entry or ③ Package row to collapse/expand its children.

**✎ Edit Day** (on every ① row) — opens a modal with the full day schedule: drag-to-reorder blocks, change start times, swap packages, toggle Repeat. Saves `schedule.json` and regenerates the daily plan on Save.

**✎ Edit Package Entries** (on every ③ row) — inline editor for that package's entries: add/remove/reorder Primary and Filler entries, change type, playlist ID, mode (random / series / recent), and count. Save regenerates the plan.

### Schedule (`schedule.php`)

Shows the full `data/schedule.json`:

- All default groups (every-day, Sunday) and all date overrides, newest first.
- Today's active group is highlighted green with a **TODAY** badge.
- The currently-playing block has a **▶ NOW** pill.
- **✎ Edit** opens the day editor modal.

### Test Player (`test.html`)

- Plays the live stream (`/live/stream.m3u8`) via hls.js with live-edge seeking.
- Shows current UTC time, now-playing title, and end time.
- Can switch to any VOD playlist from the Roku feed to test individual MP4s.

### Roku Feed (`showRoku.php`)

Renders `roku/feeds/primary-feed.json` in a readable format. Verify after a sync run.

### Cookie Upload (`uploadCookies.php`)

Upload a `cookies.txt` (Netscape format) to authenticate yt-dlp for age-restricted or members-only videos. Also tests the YouTube Data API key.

Recommended extension: **Get cookies.txt LOCALLY** (Chrome / Firefox).

---

## Routine Maintenance

### 1. Sync playlists and download missing videos

Runs automatically via cron at 2 am. To trigger manually:

```bash
bash /var/www/html/media/scripts/run.sh
```

This:
1. Reads `data/playlists.json`
2. For each WP playlist: fetches post metadata from `abcc.org` REST API, extracts YouTube IDs
3. For each YouTube playlist: fetches video IDs via YouTube Data API
4. Downloads any missing `.mp4`, `.jpg`, and `.json` sidecar files into `videos/{playlist-id}/`
5. Repairs partial downloads (only fetches whichever file is missing)
6. Removes stale files (on disk but no longer in `list.txt`)
7. Regenerates `roku/feeds/primary-feed.json`

Log: `logs/run.log`

### 2. Check what videos are missing

Open `admin/status.php` in the browser — it lists all missing video IDs with direct YouTube links.

### 3. Update cookies (when downloads start failing)

If yt-dlp starts failing with authentication errors, your cookies have expired.
Re-export from your browser and upload via `/admin/uploadCookies.php`.

### 4. Monitor the live stream

```bash
sudo systemctl status abcc-live
```

To restart:

```bash
sudo systemctl restart abcc-live
```

Check stream health by opening `/admin/test.html` and confirming the player loads.

### 5. Update now-playing

Runs automatically via cron every 5 minutes. To trigger manually:

```bash
bash /var/www/html/media/scripts/update_now_playing.sh
```

Writes `roku/now-playing.json`. Visible in the Roku app and `test.html`.

### 6. Normalize list.txt files

If any list.txt files are in the old 1-column format (bare video IDs), upgrade them:

```bash
php /var/www/html/media/scripts/normalize_lists.php --dry-run  # preview
php /var/www/html/media/scripts/normalize_lists.php            # apply
```

---

## Schedule Management

Preferred: use the **✎ Edit Day** button on `daily-plan.php` or **✎ Edit** on `schedule.php`.

All schedule data lives in `data/schedule.json`:

```json
{
  "defaults": {
    "Sunday":    { "blocks": [ { "start": "00:00", "package": "Sunday-1" }, ... ] },
    "every-day": { "blocks": [ ... ] }
  },
  "dates": {
    "2026-04-20": { "notes": "Easter", "blocks": [ ... ] }
  }
}
```

Each block: `{ "start": "HH:MM", "package": "Package-Name", "repeat": true }`.
`repeat` is optional — replays the same series episode instead of advancing.

Priority order: date-specific > day-of-week default > every-day fallback.

### Add a new package

Use **+ New Package** on `schedule.php`, or add directly to `data/packages.json`:

```json
"packages": {
  "My-Package": {
    "entries": [
      { "type": "playlist", "id": "my-playlist", "mode": "series", "count": 1 },
      { "type": "playlist", "id": "bumpers",     "mode": "random" }
    ]
  }
}
```

First entry = **primary** (plays once). Remaining entries = **fillers** (loop to fill remaining block time).

---

## Playlist Management

All playlist definitions are in `data/playlists.json`.

### Add a YouTube playlist

```json
{
  "id": "new-playlist",
  "order": 8,
  "title": "New Series",
  "source": {
    "type": "youtube",
    "playlistId": "PLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  }
}
```

After adding, run `bash scripts/run.sh` to populate `videos/new-playlist/list.txt` and download videos.

### WordPress-sourced playlist

```json
{
  "id": "sunday",
  "order": 1,
  "title": "Sunday Services",
  "source": {
    "type": "WP",
    "category": "6",
    "max": "10"
  }
}
```

`category` is the WordPress category ID. `max` is the number of most-recent posts to fetch.
YouTube IDs are extracted from post HTML by `scripts/getFromWP.php`.

---

## Key File Locations

| File | How to edit | Effect |
|------|-------------|--------|
| `data/schedule.json` | Admin UI or text editor | Live within minutes (next FFmpeg loop) |
| `data/playlists.json` | Text editor | After next `run.sh` |
| `data/packages.json` | Admin UI or text editor | Live within minutes |
| `data/yt_key.txt` | Replace file (or upload via admin UI) | Immediate |
| `data/cookies.txt` | Upload via `/admin/uploadCookies.php` | Immediate |

---

## Logs

| Log | Location | Contents |
|-----|----------|---------|
| VOD sync | `logs/run.log` | Output of `Process.php`, `genFeed.php`, `generate_daily_plan.php` |
| Archived sync | `logs/run-YYYY-MM-DD.log` | Daily copies kept 30 days |
| HLS stream | `logs/stream.log` | Video changes (`[NEW]`) and 5-min heartbeats (`[OK]`) |
| Download errors | `logs/error.log` | Errors from `getVideo.sh` (yt-dlp failures, API errors) |
| Live stream | `journalctl -u abcc-live` | FFmpeg + playout engine output |

> **Permissions note:** `logs/` must be group-writable by `www-data`. If log writes silently fail, run:
> ```bash
> sudo chgrp www-data /var/www/html/media/logs
> sudo chmod g+w /var/www/html/media/logs
> ```
> The same applies to any file in `data/` written by the admin UI (cookies, schedule, packages).
