# VOD Sync Flow

How playlists are fetched and videos downloaded to disk.

```mermaid
flowchart TD

    %% ── Data Sources ─────────────────────────────────────────────────────
    WP[(WordPress\nREST API)]
    YT[(YouTube\nAPI / yt-dlp)]

    %% ── Config ───────────────────────────────────────────────────────────
    PL[("data/\nplaylists.json")]

    %% ── Sync Layer ───────────────────────────────────────────────────────
    subgraph SYNC ["Sync  (cron: run.sh)"]
        direction TB

        PROC["Process.php\n─────────────\nreads playlists.json\nroutes by source type"]

        subgraph WP_PATH ["WP source"]
            GETWP["getFromWP.php\n──────────────\nfetch posts via REST API\nextract YouTube IDs from HTML"]
        end

        subgraph YT_PATH ["youtube source"]
            GETPL["getPlaylist.sh\n──────────────\nfetch video IDs\nvia YouTube Data API"]
        end

        LIST["videos/id/list.txt\ndate · videoId · title\nnewest last"]

        SYNC_VIDEOS["syncList()\n──────────\ncheck disk for each ID\ndownload missing files"]
        GETV["getVideo.sh\n──────────\nyt-dlp → .mp4\nyt-dlp → .json sidecar\nyt-dlp → .jpg thumbnail"]
    end

    %% ── Feed Generation ──────────────────────────────────────────────────
    subgraph FEED ["Feed (genFeed.php)"]
        GENFEED["genFeed.php\n──────────────────────\nreads list.txt per playlist\nbuilds Roku-format JSON"]
        FEEDOUT[("roku/feeds/\nprimary-feed.json")]
    end

    %% ── Output on disk ───────────────────────────────────────────────────
    DISK[("videos/id/\nvideoId.mp4\nvideoId.json\nvideoId.jpg")]

    %% ── Consumers ────────────────────────────────────────────────────────
    ROKU["Roku App\nMainLoaderTask.brs"]
    STREAM["Live Stream\nstart_live_stream.sh\n(FFmpeg reads .mp4)"]
    ADMIN["admin/status.php\n(download progress)"]

    %% ── Edges ────────────────────────────────────────────────────────────
    PL --> PROC
    PROC -->|type: WP| GETWP
    PROC -->|type: youtube| GETPL
    WP --> GETWP
    YT --> GETPL

    GETWP --> LIST
    GETPL --> LIST

    LIST --> SYNC_VIDEOS
    SYNC_VIDEOS -->|missing IDs| GETV
    YT --> GETV
    GETV --> DISK

    LIST --> GENFEED
    DISK --> GENFEED
    GENFEED --> FEEDOUT

    FEEDOUT --> ROKU
    DISK --> STREAM
    LIST --> ADMIN
    DISK --> ADMIN
```

## Steps in order

1. **`cron` triggers `scripts/run.sh`** daily (default: 2 am UTC)
2. **`run.sh`** calls `Process.php`, `genFeed.php`, `generate_daily_plan.php`, then `encode_videos.sh`
3. **`Process.php`** reads `data/playlists.json`
   - For each **WP** playlist → `getFromWP.php` fetches posts from `abcc.org` REST API, extracts YouTube IDs from post HTML, writes `list.txt`
   - For each **youtube** playlist → `getPlaylist.sh` fetches video IDs via YouTube Data API, writes `list.txt`
4. **`syncList()`** in `Process.php` compares `list.txt` to disk:
   - All three files present → OK (skip)
   - No files present → full download via `getVideo.sh`
   - Partial (e.g. mp4 missing) → repair only the missing file with `getVideo.sh --mp4` / `--jpg` / `--json`
   - On disk but not in list.txt → remove stale files (**only if the remote fetch succeeded** — skipped on API failure to avoid deleting valid videos)
5. **`getVideo.sh`** runs `yt-dlp` to download `.mp4`, `.json` sidecar, and `.jpg` thumbnail into `videos/{playlist-id}/`
6. **`genFeed.php`** reads each `list.txt`, builds the Roku Direct Publisher JSON, writes `roku/feeds/primary-feed.json`

## Outputs consumed by

| Output | Consumer |
|--------|----------|
| `videos/*/list.txt` | `start_live_stream.sh` (recent-sunday/youth resolution) |
| `videos/*/*.mp4` | FFmpeg (live stream playout) |
| `roku/feeds/primary-feed.json` | Roku app (`MainLoaderTask.brs`), `showRoku.php` |
| `videos/*/*.json` | `update_now_playing.sh` (video duration + title) |
