# Live Stream — System Flow

```mermaid
flowchart TD

    %% ── Data Sources ─────────────────────────────────────────────────────
    WP[(WordPress\nREST API)]
    YT[(YouTube\nAPI / yt-dlp)]

    %% ── Sync Layer ───────────────────────────────────────────────────────
    subgraph SYNC ["Sync  (run.sh → Process.php)"]
        direction TB
        PL[data/playlists.json\nWP category / YT playlist]
        GETFROMWP[getFromWP.php\nextract YT IDs from WP posts]
        GETPLAYLIST[getPlaylist.sh\nfetch YT playlist order]
        LISTTXT["videos/id/list.txt · YT video IDs, oldest→newest"]
        GETVIDEO[getVideo.sh / yt-dlp\ndownload .mp4 + .json sidecar]
        VIDEOSDIR[(videos/\n*.mp4  *.json  *.jpg)]
    end

    WP -->|posts + metadata| GETFROMWP
    YT -->|playlist order| GETPLAYLIST
    PL -->|type:WP| GETFROMWP
    PL -->|type:youtube| GETPLAYLIST
    GETFROMWP --> LISTTXT
    GETPLAYLIST --> LISTTXT
    LISTTXT --> GETVIDEO
    YT -->|download| GETVIDEO
    GETVIDEO --> VIDEOSDIR

    %% ── Required Videos Check ────────────────────────────────────────────
    subgraph CHECK ["extract_required_videos.sh"]
        REQLIST[requiredVideos.txt\nmissing IDs]
    end

    LISTTXT --> CHECK
    PKG[(data/packages/*.json)] --> CHECK
    VIDEOSDIR -->|already on disk?| CHECK
    CHECK --> GETVIDEO

    %% ── Schedule ─────────────────────────────────────────────────────────
    subgraph SCHED ["data/schedule.json"]
        direction LR
        S_DATE[dates:\nspecific date]
        S_DOW[defaults:\nday of week]
        S_DEF[defaults:\nevery-day]
        S_DATE -->|priority 1| RESOLVE
        S_DOW  -->|priority 2| RESOLVE
        S_DEF  -->|priority 3| RESOLVE
        RESOLVE{active block}
    end

    %% ── Playout Engine ───────────────────────────────────────────────────
    subgraph PLAYOUT ["start_live_stream.sh  (systemd: abcc-live)"]
        direction TB
        GETIDS[get_video_ids\nresolve media type]
        ELAPSED[elapsed_since_block\ncalculate seek position]
        CONCAT[build concat list\nseek into current video]
        FFMPEG[FFmpeg\nHLS encode]
        M3U8[(live/stream.m3u8\n+ seg*.ts)]
    end

    RESOLVE --> GETIDS
    LISTTXT -->|recent-sunday\nrecent-youth| GETIDS
    PKG -->|package type| GETIDS
    VIDEOSDIR -->|find_video| GETIDS
    GETIDS --> ELAPSED
    ELAPSED --> CONCAT
    CONCAT --> FFMPEG
    FFMPEG --> M3U8

    %% ── Now Playing ──────────────────────────────────────────────────────
    subgraph NP ["update_now_playing.sh  (cron: */5 * * * *)"]
        NPJSON[(roku/now-playing.json\nblock · current · next)]
    end

    RESOLVE --> NP
    LISTTXT -->|recent video title| NP
    VIDEOSDIR -->|duration from .json| NP
    PKG -->|package title| NP
    NP --> NPJSON

    %% ── Consumers ────────────────────────────────────────────────────────
    subgraph CLIENTS ["Clients"]
        TESTPAGE[admin/test.html\nUTC clock · now/next · player]
        ROKU[Roku App\nnow-playing + feed]
        BROWSER[Browser / HLS player]
    end

    M3U8 --> TESTPAGE
    M3U8 --> ROKU
    M3U8 --> BROWSER
    NPJSON --> TESTPAGE
    NPJSON --> ROKU

    %% ── Roku Feed ────────────────────────────────────────────────────────
    GENFEED[genFeed.php] --> FEED[(roku/feeds/\nprimary-feed.json)]
    VIDEOSDIR --> GENFEED
    FEED --> ROKU
    FEED --> TESTPAGE
```

## Key files

| File | Role |
|------|------|
| `data/playlists.json` | Defines all playlists — WP category or YT playlist ID |
| `data/schedule.json` | Defines what plays when (date > day-of-week > default) |
| `data/packages/*.json` | Pre-built video lists for fill / package blocks |
| `videos/{id}/list.txt` | Ordered YT video IDs for each playlist |
| `videos/{id}/*.mp4` | Downloaded video files |
| `live/stream.m3u8` | Live HLS manifest (written by FFmpeg, no EXT-X-ENDLIST) |
| `roku/now-playing.json` | Current/next block+video info, refreshed every 5 min |

## Media type resolution

```
schedule block
  ├── recent-sunday  →  last line of videos/sunday/list.txt
  ├── recent-youth   →  last line of videos/youth/list.txt
  ├── package        →  data/packages/{id}.json  (shuffled)
  └── video          →  specific video ID
       └── fill      →  appended if time remains before next block
```
