-- change again:

A Schdule Entry (for a given date/day) is made of a block (named package)
  - start time
  - named package
  - repeat flag: meaning all series episode are repeated 

A Package is made of
  current entries
  - Keyword:  recent-sunday, recent-youth
  - Video reference a particular exiting video from an existing playlist
  - Playlist
  -- Series
  -- Random 

Filler is by default over entry other than first


Schedule are two type of entries
1.  Schedule start at a particular time
2.  Filler, typically after #1 and finishes when next entry starts

Schedule Entry can be:
- Keyword:  recent-sunday, recent-youth
- Video reference a particular exiting video from an existing playlist
- Playlist
-- Series, or Series Repet
-- Random 


# playlists.json

Replaces the old `playLists.txt` + per-folder `pl.id` files.
Lives at: `data/playlists.json`

Each playlist entry has an `id` (folder name under `videos/`), a display `title`, a sort `order`,
and a `source` — either a YouTube playlist or a WordPress query.

## Configured playlists

Refreshed nightly at 2 AM UTC by `scripts/run.sh` → `Process.php`.

| id | Title | Source | Details | Max |
|----|-------|--------|---------|-----|
| `sunday` | Sunday Services | WordPress | Category 6 on abcc.org | 12 |
| `youth` | Youth Ministry | WordPress | Category 47 on abcc.org | 10 |
| `guests` | Guest Speakers | WordPress | Category 18 on abcc.org | 15 |
| `Esther` | Bible Study: Esther | YouTube | `PLWUuT8dTSTRBOFF9IG4WEPa8aS5MrXXBx` | all |
| `Easter` | Easter | YouTube | `PLWUuT8dTSTRBNUMSQ_DSwzE-hahkmJfrD` | all |
| `Ralph-Hymns` | Arabic Hymns | YouTube | `PLXM3vZCccKrLsTvOzVHbQbhpPX0GzeWOA` | 10 |
| `BT-new-Hymns` | Better Life new Hymns | YouTube | `PLMncR0UTSkZvPEv6h4iYYT98QDfDUIEN7` | 10 |
| `Dew-Drops` | Dew Drops | YouTube | `PLWUuT8dTSTRDM6xfHrmjhTW5ZBViKgLgO` | 10 |
| `bible` | Bible Readings | manual | Files placed manually in `videos/bible/` | — |
| `bumpers` | Short Bumpers | manual | Files placed manually in `videos/bumpers/` | — |

**WP playlists** — `getFromWP.php` fetches posts from `abcc.org/wp-json/wp/v2/posts`, extracts YouTube video IDs from post HTML, and writes `list.txt`. Videos are then downloaded by `getVideo.sh`.

**YouTube playlists** — `getPlaylist.sh` calls the YouTube Data API v3 and writes `list.txt`. Missing videos are downloaded by `getVideo.sh` via yt-dlp.

**manual playlists** — not synced; files are added/removed by hand and not touched by `Process.php`.

## Source types

### YouTube playlist
```json
{
  "type": "youtube",
  "playlistId": "PLWUuT8dTSTRBrmn6nSnud4VPavH3ZB7Wd"
}
```

### WordPress query
```json
{
  "type": "WP",
  "category": "6",
  "max": "10"
}
```

`category` is the WordPress category ID (integer as string). `max` is the
maximum number of posts to fetch. Video IDs are extracted from post HTML
by `vod/scripts/getFromWP.php`.

## Per-playlist folder  (`videos/{id}/`)
- `list.txt` — tab-separated lines: `date \t videoId \t title`, newest last

---

# schedule.json

## Priority (highest → lowest)
1. **Date** — specific calendar date (e.g. `2026-03-08`)
2. **Day of week** — e.g. `Sunday`, `Monday`
3. **Default** — fallback for any day not matched above

---

## Entry types

1. **Scheduled** — `"start": "HH:MM"`; begins playing at that exact time
2. **Filler** — `"start": "after"`; plays after the previous entry ends, until the next scheduled block begins

---

## Content reference

### Keyword
Shorthand for a well-known dynamic source. No extra fields.

```json
{ "type": "recent-sunday" }
{ "type": "recent-youth" }
```

| Keyword         | Resolves to                                              |
|-----------------|----------------------------------------------------------|
| `recent-sunday` | Last line of `videos/sunday/list.txt` (newest broadcast) |
| `recent-youth`  | Last line of `videos/youth/list.txt`                     |

### Video
A specific video from an existing playlist.

```json
{ "type": "video", "id": "dQw4w9WgXcQ", "playlist": "sunday" }
```

### Playlist
A playlist played back in a chosen mode.

```json
{ "type": "playlist", "id": "PKG-MORNING",    "mode": "random" }
{ "type": "playlist", "id": "PL_BIBLE_STUDY", "mode": "series" }
{ "type": "playlist", "id": "PL_BIBLE_STUDY", "mode": "series-repeat" }
```

| Mode            | Description                                                          |
|-----------------|----------------------------------------------------------------------|
| `random`        | Shuffles all items on each run                                       |
| `series`        | Plays next unplayed episode; advances index in `series-state.json`  |
| `series-repeat` | Replays the most recent episode; does not advance the index          |

---

## Example blocks

Scheduled entry:
```json
{ "start": "12:00", "media": { "type": "recent-sunday" } }
```

Filler entry:
```json
{ "start": "after", "media": { "type": "playlist", "id": "PKG-MORNING", "mode": "random" } }
```

A typical day's block list (filler wraps around scheduled entries):
```json
[
  { "start": "after",  "media": { "type": "playlist", "id": "PKG-MORNING", "mode": "random" } },
  { "start": "12:00",  "media": { "type": "recent-sunday" } },
  { "start": "after",  "media": { "type": "playlist", "id": "Ralph-Hymns", "mode": "random" } },
  { "start": "19:00",  "media": { "type": "playlist", "id": "Esther", "mode": "series" } },
  { "start": "after",  "media": { "type": "playlist", "id": "PKG-EVENING", "mode": "random" } }
]
```

---

## Resolution rules

### `recent-sunday` / `recent-youth`
- Reads `videos/{folder}/list.txt`
- Picks the **last line** (newest entry = most recent broadcast)

### `package`
- Reads `live/packages/{id}.json`
- Shuffles all items randomly on each run

### `series` / `series-repeat`
- State tracked per-playlist in `live/series-state.json`:
```json
{
  "PL_BIBLE_STUDY": {
    "nextIndex": 4,
    "lastVideoId": "abc123",
    "firstPlayed": "2026-03-01"
  }
}
```
- `series` plays the video at `nextIndex`, then increments it
- `series-repeat` plays `lastVideoId` without advancing the index

---

## Example — Sunday

```
@12:00  recent-sunday
        fill → package: PKG-WORSHIP-A

@15:00  recent-sunday
        fill → package: PKG-WORSHIP-A
```

## Example — Monday

```
@19:00  series: PL_BIBLE_STUDY
        fill → package: PKG-MORNING
```

---

# series-state.json

Tracks progress through each series playlist.

```json
{
  "PL_BIBLE_STUDY": {
    "nextIndex": 4,
    "lastVideoId": "abc123",
    "firstPlayed": "2026-03-01"
  }
}
```

| Field         | Description                                          |
|---------------|------------------------------------------------------|
| `nextIndex`   | Index of the next episode to play in `list.txt`      |
| `lastVideoId` | Video ID of the most recently played episode         |
| `firstPlayed` | Date the series was first started                    |

---

# now-playing.json  (runtime, not committed)

Written by `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-08T12:05:00Z"
}
```
