Skip to content

New tool: PBS slug resolver — Media Manager slug → pbswisconsin.org URL (design doc) #21

Description

@mriechers

Idea

Port the "Jump to PBSWI slug" Alfred workflow (alfred-setup#1, #2) to a browser tool: paste a slug copied from the Media Manager backend (or any portal/pbs.org/station URL), get the canonical pbswisconsin.org/watch/{show}/{slug}/ URL with copy/open buttons — plus a searchable browser of every show the station carries. Useful from any machine (work laptop, phone) without Alfred.

What the Alfred build established (all verified 2026-07)

  • Asset slugs end in an auto-generated 6-char suffix (racine-zoo-ho3yhq) — detectable by shape: ^[a-z0-9]+(?:-[a-z0-9]+)*-[a-z0-9]{6}$.
  • video.pbswisconsin.org/video/{slug}/ resolves any published asset with no show knowledge (200 = valid, 404 = unpublished/expired) and its HTML names the show. The station's own /watch/ pages do NOT validate server-side.
  • Full show catalog (~2,690) enumerable from videosearch.php?let=A..Z plus the local-show slug lists embedded in /shows-a-z/ (the A-Z index omits some local shows — inside-wisconsin-politics proved it).
  • Station watch URL: https://pbswisconsin.org/watch/{show-slug}/{asset-slug}/.

The browser constraint (tested 2026-07-03)

None of the endpoints send Access-Control-Allow-Origin (checked with an Origin: https://tools.bymarkriechers.com header against the portal, wpt-cove/css/videosearch.php, and the MM API base). Cross-origin fetches from the tool will be blocked, so the Alfred workflow's live resolution/validation cannot run client-side. Design works around it; no proxies (violates the repo's privacy-first/no-server principles).

Architecture — v1 (fully static)

Follows the existing build-suggested-tools.yml precedent: CI does the fetching, the browser stays offline.

.github/workflows/build-pbs-catalog.yml — scheduled (weekly cron + workflow_dispatch), runs a zero-dep Node script that:

  1. Sweeps videosearch.php?let=A..Z → slug + title pairs.
  2. Scrapes /shows-a-z/ embedded poster_shows lists (title-cased from slug when the sweep lacks it).
  3. Writes pbs-slug/catalog.json ({generated, shows: [{slug, title}]}, ~100 KB) and commits if changed.

pbs-slug/ tool (vanilla HTML/CSS/JS, shared/ styles, dark mode, a11y per repo principles):

  • One input, auto-detects intent:
    • Complete asset slug or pasted URL → normalize (accept portal / pbs.org / station URL forms) → emit portal URL (always constructible, needs no show) + station URL when the show is resolvable: slug-prefix match against the catalog (MM bakes the show prefix into most station-produced asset slugs). Each result: copy button + open-in-new-tab (opening doubles as manual validation — the tool says so honestly: "can't verify from the browser; portal 404 = unpublished/expired").
    • Show name → instant client-side token search over catalog.json → /watch/{slug}/ links. Same all-tokens-covered ranking logic as the Alfred version.
  • Show catalog freshness shown from generated timestamp; ?slug= / ?q= query params for shareable links (matches og-image's ?url= pattern).

Landing page: add tool tile + README section, per repo structure.

v2 (optional live layer, later)

The wpt-cove plugin is station-controlled — if an Access-Control-Allow-Origin: * header were added to videosearch.php (read-only, public data, no credentials), the tool could add live show search parity with Alfred. Portal-side validation would still be blocked (pbs.org infrastructure, not ours) short of the Media Manager API — which needs a key and therefore a server, so it stays out of scope for this repo (the pending MM API access request in pbswi is the right home for that).

Non-goals

  • CORS proxies or any server-side component (repo principles).
  • Replacing the Alfred workflow (it keeps live validation; this is the anywhere version).

Open questions

  • Tool naming/placement: pbs-slug/? It's station-specific on an otherwise general-purpose public site — fine, or prefer unlisted (no landing tile)?
  • Catalog cadence: weekly cron enough? (Alfred uses 7-day TTL; live fallback covers gaps there, which v1 here won't have.)
  • Ship the initial catalog.json in the first PR or let the Action generate it on first run?

🤖 Generated with Claude Code

https://claude.ai/code/session_012EXrV9taMGFN2iDa317caX

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions