diff --git a/.gitignore b/.gitignore index 8ac896e..c000ddc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,18 +27,5 @@ Thumbs.db # Direnv .direnv/ -# Source audio (large WAVs from concert tape transfers) -content/audio/*.wav - -# Built audio (regenerate from content/audio/ via `make audio`) -web/static/audio/*.opus - -# Built images (regenerate from content/images/ via `make images`) -web/static/images/*.webp - -# Nix build outputs -result -result-* - # Build artifacts from content pipeline content/build/ diff --git a/Makefile b/Makefile index 3366425..6ce7e03 100644 --- a/Makefile +++ b/Makefile @@ -2,46 +2,10 @@ SHELL := /usr/bin/env bash .PHONY: help help: - @echo "make build — build server + frontend locally (sanity check)" - @echo "make check — type-check + go vet" - @echo "make audio-pull — copy source WAVs from Dropbox into content/audio/" - @echo "make audio — transcode each side WAV → Opus" - @echo "make images — convert content/images/*.jpg → WebP" - @echo "make artists — regenerate artists.json from audio.yaml" - @echo "make content — artists + images + audio" - @echo "make deploy-assets — rsync web/static/{audio,images}/ to sprade for production" + @echo "make build — build server + frontend locally (sanity check)" + @echo "make check — type-check + go vet" @echo "make tag V=patch|minor|major — bump version tag and push" - @echo "make prefetch — print sha256 + npmDepsHash + vendorHash for the homelab module" - -.PHONY: audio-pull -audio-pull: - bin/pull-audio - -.PHONY: audio -audio: - bin/build-audio - -.PHONY: images -images: - bin/build-images - -.PHONY: artists -artists: - bin/build-artists - -.PHONY: content -content: artists images audio - -.PHONY: deploy-assets -deploy-assets: - @if [ ! -d web/static/audio ] || [ -z "$$(ls web/static/audio 2>/dev/null)" ]; then \ - echo "error: web/static/audio is empty. Run \`make audio\` first." >&2; exit 1; \ - fi - @if [ ! -d web/static/images ] || [ -z "$$(ls web/static/images 2>/dev/null)" ]; then \ - echo "error: web/static/images is empty. Run \`make images\` first." >&2; exit 1; \ - fi - rsync -av --delete --progress web/static/audio/ deploy@sprade:/var/lib/docent/audio/ - rsync -av --delete --progress web/static/images/ deploy@sprade:/var/lib/docent/images/ + @echo "make prefetch — print sha256 + npmDepsHash + vendorHash for the homelab module" .PHONY: build build: diff --git a/bin/build-artists b/bin/build-artists deleted file mode 100755 index 587d59d..0000000 --- a/bin/build-artists +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -MANIFEST="${MANIFEST:-$REPO_ROOT/content/audio.yaml}" -OUT="${OUT:-$REPO_ROOT/web/src/lib/artists.json}" - -for tool in yq jq; do - if ! command -v "$tool" >/dev/null; then - echo "error: $tool not in PATH (try: nix develop)" >&2 - exit 1 - fi -done - -yq -o=json '.' "$MANIFEST" | jq ' - def render_artist: - . as $a | - { - id: $a.id, - name: $a.name, - slug: $a.slug, - description: ($a.description // "" | rtrimstr("\n")), - images: [ - ($a.images // []) | to_entries[] | - ("/images/" + $a.slug + "-" + ((.key + 1) | tostring) + ".webp") - ], - shows: [ - $a.shows[] | . as $s | { - caption: $s.caption, - slug: $s.slug, - sides: [ - $s.sides[] | { - id: .id, - label: .label, - audio: ("/audio/" + $a.slug + "-" + $s.slug + "-" + .id + ".opus") - } - ] - } - ] - }; - - { - exhibit: .exhibit, - artists: [ .artists[] | render_artist ] - } -' > "$OUT.tmp" - -mv "$OUT.tmp" "$OUT" -echo "wrote $OUT ($(jq '.artists | length' "$OUT") artists)" diff --git a/bin/build-audio b/bin/build-audio deleted file mode 100755 index 6022153..0000000 --- a/bin/build-audio +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env bash -# Sides are encoded individually — no concatenation. Idempotent: a side is -# skipped if its output is newer than its source. -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -MANIFEST="${MANIFEST:-$REPO_ROOT/content/audio.yaml}" -RAW_DIR="${RAW_DIR:-$REPO_ROOT/content/audio}" -OUT_DIR="${OUT_DIR:-$REPO_ROOT/web/static/audio}" - -for tool in yq ffmpeg; do - if ! command -v "$tool" >/dev/null; then - echo "error: $tool not in PATH (try: nix develop)" >&2 - exit 1 - fi -done - -if [[ ! -f "$MANIFEST" ]]; then - echo "error: manifest not found: $MANIFEST" >&2 - exit 1 -fi - -mkdir -p "$OUT_DIR" - -DEFAULT_BITRATE=$(yq -r '.defaults.bitrate // "64k"' "$MANIFEST") -DEFAULT_CHANNELS=$(yq -r '.defaults.channels // "2"' "$MANIFEST") -DEFAULT_RATE=$(yq -r '.defaults.sample_rate // "48000"' "$MANIFEST") - -encoded=0 -skipped=0 -missing=0 -failed=0 - -NUM_ARTISTS=$(yq '.artists | length' "$MANIFEST") - -for ((a=0; a src_mt )); then - printf ' %-50s up to date\n' "$OUT_NAME" - skipped=$((skipped + 1)) - continue - fi - fi - - printf ' %-50s encoding ...\n' "$OUT_NAME" - - if ffmpeg \ - -i "$SRC_PATH" \ - -c:a libopus -b:a "$BITRATE" -ac "$CHANNELS" -ar "$RATE" \ - -application audio -vbr on -compression_level 10 \ - -y "$OUT_PATH" \ - -hide_banner -loglevel warning -nostdin &2 - failed=$((failed + 1)) - fi - done - done -done - -printf '\n%d encoded · %d up-to-date · %d missing sources · %d failed\n' \ - "$encoded" "$skipped" "$missing" "$failed" - -if (( failed > 0 )); then - exit 1 -fi diff --git a/bin/build-images b/bin/build-images deleted file mode 100755 index be42374..0000000 --- a/bin/build-images +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" -MANIFEST="${MANIFEST:-$REPO_ROOT/content/audio.yaml}" -SRC_DIR="${SRC_DIR:-$REPO_ROOT/content/images}" -OUT_DIR="${OUT_DIR:-$REPO_ROOT/web/static/images}" -MAX_SIZE="${MAX_SIZE:-1200}" -QUALITY="${QUALITY:-80}" - -for tool in yq magick; do - if ! command -v "$tool" >/dev/null; then - echo "error: $tool not in PATH (try: nix develop)" >&2 - exit 1 - fi -done - -mkdir -p "$OUT_DIR" - -encoded=0 -skipped=0 -missing=0 -failed=0 - -NUM_ARTISTS=$(yq '.artists | length' "$MANIFEST") - -for ((a=0; a src_mt )); then - printf ' %-45s up to date\n' "$OUT_NAME" - skipped=$((skipped + 1)) - continue - fi - fi - - printf ' %-45s converting ...\n' "$OUT_NAME" - - if magick "$SRC_PATH" \ - -auto-orient \ - -strip \ - -resize "${MAX_SIZE}x${MAX_SIZE}>" \ - -quality "$QUALITY" \ - "$OUT_PATH"; then - size=$(du -h "$OUT_PATH" | cut -f1) - printf ' %-45s done (%s)\n' "$OUT_NAME" "$size" - encoded=$((encoded + 1)) - else - printf ' %-45s FAILED\n' "$OUT_NAME" >&2 - failed=$((failed + 1)) - fi - done -done - -printf '\n%d converted · %d up-to-date · %d missing sources · %d failed\n' \ - "$encoded" "$skipped" "$missing" "$failed" - -if (( failed > 0 )); then - exit 1 -fi diff --git a/bin/pull-audio b/bin/pull-audio deleted file mode 100755 index 87c398c..0000000 --- a/bin/pull-audio +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# Copy concert WAV files from the curator's Dropbox folder into content/audio/, -# stripping the ` Brianna` suffix that the source files carry. -# Idempotent: skips files that already exist at the destination. -set -euo pipefail - -SRC_DIR="${SRC_DIR:-$HOME/Dropbox/File requests/Mill Run Audio}" -DEST_DIR="${DEST_DIR:-$(cd "$(dirname "$0")/.." && pwd)/content/audio}" - -if [[ ! -d "$SRC_DIR" ]]; then - echo "error: source directory not found: $SRC_DIR" >&2 - exit 1 -fi - -mkdir -p "$DEST_DIR" - -count=0 -copied=0 -skipped=0 - -shopt -s nullglob -for src in "$SRC_DIR"/*.wav; do - count=$((count + 1)) - name=$(basename "$src") - # Strip trailing " Brianna.wav" → ".wav" - dest_name="${name% Brianna.wav}.wav" - dest="$DEST_DIR/$dest_name" - - if [[ -f "$dest" ]] && [[ $(stat -c %s "$src") -eq $(stat -c %s "$dest") ]]; then - skipped=$((skipped + 1)) - continue - fi - - printf ' [%2d] %s\n' "$count" "$dest_name" - cp -- "$src" "$dest" - copied=$((copied + 1)) -done - -printf '\n%d total · %d copied · %d skipped (already present)\n' "$count" "$copied" "$skipped" diff --git a/branding.png b/branding.png deleted file mode 100644 index afb0fd3..0000000 Binary files a/branding.png and /dev/null differ diff --git a/content/audio.yaml b/content/audio.yaml deleted file mode 100644 index 20df964..0000000 --- a/content/audio.yaml +++ /dev/null @@ -1,899 +0,0 @@ -# Source of truth for the exhibit's audio collection. -# -# The Mill Run Playhouse-Theatre stop in the larger exhibit holds recordings -# from concerts at the venue, digitized side-by-side from cassette tapes. -# The data model here is artist → shows → sides. Each `side` produces one -# Opus file; sides are not concatenated. -# -# Filename convention (auto-derived): -# web/static/audio/--.opus -# -# Pipeline: -# bin/pull-audio — copy WAVs from Dropbox to content/audio/ -# bin/build-audio — encode each side as its own opus -# bin/build-images — convert content/images/*.jpg → web/static/images/*.webp -# bin/build-stops — regenerate web/src/lib/stops.json from this file - -defaults: - bitrate: 64k - channels: 2 - sample_rate: 48000 - -exhibit: - title: "Mill Run Theatre" - description: | - Listen to performances from the Mill Run - Select from the artists below - -artists: - - id: 1 - name: "Al Martino" - slug: al-martino - description: | - American singer of Italian descent best known for the ballad "Here - in My Heart" and the perennial "Spanish Eyes." Martino also played - the singer Johnny Fontane in The Godfather and its sequel. - images: - - "AL MARTINO001_74.jpg" - shows: - - caption: "1974" - slug: "1974" - sides: - - id: a - label: "Side A" - source: "Al Martino - 1974 (Side A) (No Side B).wav" - - - id: 2 - name: "Caterina Valente" - slug: caterina-valente - description: | - Italo-French entertainer who recorded in over a dozen languages across - a career spanning the 1950s through the 1980s. A jazz-trained singer, - she was a fixture of European and American television variety shows. - images: [] - shows: - - caption: "Aug 1976" - slug: "1976-aug" - sides: - - id: a - label: "Side A" - source: "Caterina Valente - August 1976 (2nd Show Sunday) (Side A) (No Side B).wav" - - - id: 3 - name: "Dionne Warwick" - slug: dionne-warwicke - description: | - American singer who became the definitive voice of the Burt Bacharach - and Hal David songbook in the 1960s: "Walk On By," "Anyone Who Had a - Heart," and "Do You Know the Way to San Jose." From 1971 to 1975 she - performed under the alternate spelling "Warwicke." - images: - - "Dionne Warwick 1974 from Don Leavitt.jpg" - shows: - - caption: "1974" - slug: "1974" - sides: - - id: a - label: "Side A" - source: "Dionne Warwicke - 1974 (Side A).wav" - - id: b - label: "Side B" - source: "Dionne Warwicke - 1974 (Side B).wav" - - - id: 4 - name: "Don Ho" - slug: don-ho - description: | - Hawaiian musician and entertainer whose 1966 single "Tiny Bubbles" - became his lifelong signature. He performed nightly in Waikiki for - decades and toured the mainland into the 2000s. - images: - - "Don Ho 001 1980.jpg" - shows: - - caption: "Jun 26, 1977 — 1st show" - slug: "1977-jun-1" - sides: - - id: a - label: "Side A" - source: "Don Ho - June 26th 1977 (Tape 1) (Side A).wav" - - id: b - label: "Side B" - source: "Don Ho - June 26th 1977 (Tape 1) (Side B).wav" - - caption: "Jun 26, 1977 — 2nd show" - slug: "1977-jun-2" - sides: - - id: a - label: "Side A" - source: "Don Ho - June 26th 1977 (Tape 2) (Side A).wav" - - id: b - label: "Side B" - source: "Don Ho - June 26th 1977 (Tape 2) (Side B).wav" - - - id: 5 - name: "Don Rickles" - slug: don-rickles - description: | - American stand-up comedian known for insult comedy aimed affectionately - at celebrities and audience members alike. A regular on television - variety and talk shows from the 1960s onward. - images: - - "Don Rickles 002 1975.jpg" - shows: - - caption: "May 25, 1975" - slug: "1975-may" - sides: - - id: a - label: "Side A" - source: "Don Rickles - May 25th 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Don Rickles - May 25th 1975 (Side B).wav" - - - id: 6 - name: "Eddy Arnold" - slug: eddy-arnold - description: | - Tennessee-born country singer who placed more than 145 songs on the - country charts across five decades. Hits include "Make the World Go - Away" and "Cattle Call." - images: - - "Eddy Arnold 001 1975.jpg" - shows: - - caption: "1975" - slug: "1975" - sides: - - id: a - label: "Side A" - source: "Eddy Arnold - 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Eddy Arnold - 1975 (Side B).wav" - - caption: "Nov 1977" - slug: "1977-nov" - sides: - - id: a - label: "Side A" - source: "Eddy Arnold - November 1977 (Side A).wav" - - id: b - label: "Side B" - source: "Eddy Arnold - November 1977 (Side B).wav" - - - id: 7 - name: "Engelbert Humperdinck" - slug: engelbert-humperdinck - description: | - British pop singer whose 1967 single "Release Me" famously kept the - Beatles' "Strawberry Fields Forever" from reaching number one in the - UK. His stage name was borrowed from a 19th-century German opera - composer. - images: - - "Engelbert Humperdinck 003 1975.jpg" - shows: - - caption: "Oct 1975" - slug: "1975-oct" - sides: - - id: a - label: "Side A" - source: "Engelebert Humperdinck - October 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Engelebert Humperdinck - October 1975 (Side B).wav" - - - id: 8 - name: "Frankie Laine" - slug: frankie-laine - description: | - American crooner whose hits include "That's My Desire," "Mule Train," - "Jezebel," and the theme from the television series Rawhide. - images: - - "Frankie Laine 002 1975.jpg" - shows: - - caption: "Sep 1975" - slug: "1975-sep" - sides: - - id: a - label: "Side A" - source: "Frankie Laine - September 1975 (2nd Show Sunday) (Side A).wav" - - id: b - label: "Side B" - source: "Frankie Laine - September 1975 (2nd Show Sunday) (Side B).wav" - - - id: 9 - name: "Gladys Knight & the Pips" - slug: gladys-knight - description: | - American soul and funk group fronted by Gladys Knight with her brother - and two cousins as the Pips. Hits include "Midnight Train to Georgia," - "I Heard It Through the Grapevine," and "Neither One of Us." - images: - - "Gladys Knight and the Pips 001 1975.jpg" - - "Gladys Knight & the Pips 001 1975.jpg" - shows: - - caption: "Aug 1977 — 1st show" - slug: "1977-aug-1st" - sides: - - id: a - label: "Side A" - source: "Gladys Knight - August 1977 (1st Show Saturday) (Side A).wav" - - id: b - label: "Side B" - source: "Gladys Knight - August 1977 (1st Show Saturday) (Side B).wav" - - caption: "Aug 1977 — 2nd show" - slug: "1977-aug-2nd" - sides: - - id: a - label: "Side A" - source: "Gladys Knight - August 1977 (2nd Show Saturday) (Side A).wav" - - id: b - label: "Side B" - source: "Gladys Knight - August 1977 (2nd Show Saturday) (Side B).wav" - - caption: "Oct 1975 — 1st show" - slug: "1975-oct-fri" - sides: - - id: a - label: "Side A" - source: "Gladys Knight - October 1975 (2nd Show Friday) (Side A).wav" - - id: b - label: "Side B" - source: "Gladys Knight - October 1975 (2nd Show Friday) (Side B).wav" - - caption: "Oct 1975 — 2nd show" - slug: "1975-oct-sat" - sides: - - id: a - label: "Side A" - source: "Gladys Knight - October 1975 (2nd Show Saturday) (Side A).wav" - - id: b - label: "Side B" - source: "Gladys Knight - October 1975 (2nd Show Saturday) (Side B).wav" - - - id: 10 - name: "Glen Campbell & Jud Strunk" - slug: glen-campbell-jud-strunk - description: | - Country-pop superstar Glen Campbell ("Wichita Lineman," "Rhinestone - Cowboy") shared this bill with Jud Strunk, a Maine native who reached - the U.S. Top 20 in 1973 with the novelty hit "Daisy a Day." - images: - - "Glenn Campbell 006 1973.jpg" - shows: - - caption: "Dec 1973" - slug: "1973-dec" - sides: - - id: a - label: "Side A" - source: "Glen Campbell_Jud Strunk - December 1973 (Side A).wav" - - id: b - label: "Side B" - source: "Glen Campbell_Jud Strunk - December 1973 (Side B).wav" - - - id: 11 - name: "Glenn Yarbrough & The Limeliters" - slug: glenn-yarbrough-limeliters - description: | - Folk singer who rose to fame with the Limeliters, one of the leading - acts of the early-1960s folk revival, before launching a successful - solo career. He occasionally rejoined the group for reunion tours. - images: [] - shows: - - caption: "Oct 1977" - slug: "1977-oct" - sides: - - id: a - label: "Side A" - source: "Glenn Yarbrough & Limeliters - October 1977 (Side A).wav" - - id: b - label: "Side B" - source: "Glenn Yarbrough & Limeliters - October 1977 (Side B).wav" - - - id: 12 - name: "Harry Belafonte" - slug: harry-belafonte - description: | - American singer, actor, and civil rights activist who brought Caribbean - music to mainstream audiences with "Day-O (The Banana Boat Song)" and - "Jump in the Line." His 1956 album Calypso was the first by a solo - artist to sell a million copies in the United States. - images: [] - shows: - - caption: "May 1976" - slug: "1976-may" - sides: - - id: a - label: "Act I — Side A" - source: "Harry Belafonte - May 1976 (1st Half) (Act I) (Side A).wav" - - id: b - label: "Act I — Side B" - source: "Harry Belafonte - May 1976 (1st Half) (Act I) (Side B).wav" - - - id: 13 - name: "Helen Reddy" - slug: helen-reddy - description: | - Australian-American singer best known for "I Am Woman," an anthem - that became a touchstone of second-wave feminism. Other hits include - "Delta Dawn" and "Angie Baby." - images: - - "HelenReddy001_74.jpg" - shows: - - caption: "1974" - slug: "1974" - sides: - - id: a - label: "Side A" - source: "Helen Reddy - 1974 (Side A).wav" - - id: b - label: "Side B" - source: "Helen Reddy - 1974 (Side B).wav" - - - id: 14 - name: "Florence Henderson & Jim Nabors" - slug: henderson-nabors - description: | - Florence Henderson (Carol Brady of The Brady Bunch) shared this bill - with Jim Nabors (Gomer Pyle of The Andy Griffith Show). Both had - concert-singing careers alongside their television roles and were - regulars on variety programs. - images: - - "Florence Henderson 009 1975.jpg" - - "Jim Nabors 002 1975.jpg" - shows: - - caption: "Jul 1975" - slug: "1975-jul" - sides: - - id: a - label: "Side A" - source: "Henderson & Nabors - July 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Henderson & Nabors - July 1975 (Side B).wav" - - - id: 15 - name: "The Hues Corporation & The 5th Dimension" - slug: hues-corp-5th-dimension - description: | - The Hues Corporation, who topped the charts in 1974 with "Rock the - Boat," shared this bill with The 5th Dimension, the late-1960s - sunshine-pop group behind "Up, Up and Away" and the medley - "Aquarius/Let the Sunshine In," drawn from the musical Hair. - images: - - "The 5th DimentionFD001_74.jpg" - shows: - - caption: "1974" - slug: "1974" - sides: - - id: a - label: "Side A" - source: "Hues Corp; 5th Dimension - 1974 (Side A).wav" - - id: b - label: "Side B" - source: "Hues Corp; 5th Dimension - 1974 (Side B).wav" - - - id: 16 - name: "John Davidson" - slug: john-davidson - description: | - American singer, actor, and television host with a clean-cut style. - A frequent variety-show guest in the 1960s and '70s, he later hosted - That's Incredible! and Hollywood Squares. - images: - - "JohnDavidson002_74 HQ.jpg" - shows: - - caption: "1974" - slug: "1974" - sides: - - id: a - label: "Side A" - source: "John Davidson - 1974 (Side A).wav" - - id: b - label: "Side B" - source: "John Davidson - 1974 (Side B).wav" - - - id: 17 - name: "Johnny Mathis" - slug: johnny-mathis - description: | - American singer whose smooth tenor on songs like "Chances Are," - "Misty," and "It's Not for Me to Say" made him one of the best-selling - recording artists of the twentieth century. - images: - - "Johnny Mathis 004 1975.jpg" - shows: - - caption: "Aug 1975 — 1st show" - slug: "1975-aug-sun-1st" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1975 (1st Show Sunday) (Side A).wav" - - id: b - label: "Side B" - source: "Johnny Mathis - August 1975 (1st Show Sunday) (Side B).wav" - - caption: "Aug 1975 — 2nd show" - slug: "1975-aug-1st" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1975 (1st) (Side A).wav" - - id: b - label: "Side B" - source: "Johnny Mathis - August 1975 (1st) (Side B).wav" - - caption: "Aug 1975 — 3rd show" - slug: "1975-aug-2nd-half" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1975 (2nd Half) (Side A) (No Side B).wav" - - caption: "Aug 1975 — 4th show" - slug: "1975-aug-3rd" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1975 (3rd) (Side A) (No Side B).wav" - - caption: "Aug 1976 — 1st show" - slug: "1976-aug-1" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1976 (Side A) 1-13-2021 (tape with stickers on box).wav" - - id: b - label: "Side B" - source: "Johnny Mathis - August 1976 (Side B) 1-13-2021 (tape with stickers on box).wav" - - caption: "Aug 1976 — 2nd show" - slug: "1976-aug-2" - sides: - - id: a - label: "Side A" - source: "Johnny Mathis - August 1976 (Side A) 7-30-2021.wav" - - id: b - label: "Side B" - source: "Johnny Mathis - August 1976 (Side B) 7-30-2021.wav" - - - id: 18 - name: "Kate Smith" - slug: kate-smith - description: | - American singer with a 50-year career and a deep contralto voice, - famous for her 1939 recording of Irving Berlin's "God Bless America." - She hosted radio and television variety programs through the 1950s - and '60s. - images: - - "Kate Smith 006 1975.jpg" - shows: - - caption: "Nov 1975" - slug: "1975-nov" - sides: - - id: a - label: "Side A" - source: "Kate Smith - November 1975 (1st Show) (Side A).wav" - - id: b - label: "Side B" - source: "Kate Smith - November 1975 (1st Show) (Side B).wav" - - - id: 19 - name: "Lainie Kazan" - slug: lainie-kazan - description: | - American singer and actress with a powerful belt and Broadway roots. - As Barbra Streisand's understudy in Funny Girl, she famously stepped - in for one performance in 1964. She later became a fixture in supper - clubs and film comedies. - images: [] - shows: - - caption: "Aug 1975 — 1st show" - slug: "1975-aug-1" - sides: - - id: a - label: "Side A" - source: "Lainie Kazan - August 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Lainie Kazan - August 1975 (Side B).wav" - - caption: "Aug 1975 — 2nd show" - slug: "1975-aug-2" - sides: - - id: a - label: "Side A" - source: "Lainie Kazan - August 1975 (Tape 2) (Side A).wav" - - id: b - label: "Side B" - source: "Lainie Kazan - August 1975 (Tape 2) (Side B).wav" - - - id: 20 - name: "The Love Machine" - slug: love-machine - description: | - International all-female funk and soul group active in the 1970s. - The seven-member ensemble, which included songwriter Sandra Sully, - toured Europe, Asia, and Africa and recorded for labels including - Buddah, Arista, and Motown. - images: [] - shows: - - caption: "Oct 1976" - slug: "1976-oct" - sides: - - id: a - label: "Side A" - source: "Love Machine - October 1976 (Side A).wav" - - - id: 21 - name: "Tony Martin & Cyd Charisse" - slug: martin-charisse - description: | - Husband-and-wife stage act. Tony Martin sang and Cyd Charisse danced; - both were veterans of Hollywood musicals, and they toured together - through the 1970s. - images: [] - shows: - - caption: "Aug 1975" - slug: "1975-aug" - sides: - - id: a - label: "Side A" - source: "Martin;Charisse - August 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Martin;Charisse - August 1975 (Side B).wav" - - - id: 22 - name: "The Mills Brothers" - slug: mills-brothers - description: | - American close-harmony vocal quartet from Piqua, Ohio, active from - the 1920s through the 1980s. Best known for "Paper Doll" (1943), - "Glow Worm," and "You Always Hurt the One You Love." - images: - - "Mills Brothers 003 1975.jpg" - shows: - - caption: "Sep 1975" - slug: "1975-sep" - sides: - - id: a - label: "Side A" - source: "Mills Brothers - September 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Mills Brothers - September 1975 (Side B).wav" - - - id: 23 - name: "Mitzi Gaynor" - slug: mitzi-gaynor - description: | - American actress, singer, and dancer who starred in the 1958 film of - South Pacific opposite Rossano Brazzi. Her touring revues throughout - the 1970s showcased her dance numbers and comic timing. - images: - - "Mitzi Gaynor 007 1976.jpg" - shows: - - caption: "Oct 2, 1977" - slug: "1977-oct" - sides: - - id: i-a - label: "Act I — Side A" - source: "Mitzi Gaynor - October 2nd 1977 (Act I) (Side A).wav" - - id: i-b - label: "Act I — Side B" - source: "Mitzi Gaynor - October 2nd 1977 (Act I) (Side B).wav" - - id: ii-a - label: "Act II — Side A" - source: "Mitzi Gaynor - October 2nd 1977 (Act II) (Side A) (No Side B).wav" - - - id: 24 - name: "Robert Goulet" - slug: robert-goulet - description: | - Canadian-American baritone who originated the role of Lancelot in - Lerner and Loewe's Camelot on Broadway in 1960. A long career on - television, in film, and on the Las Vegas circuit followed. - images: - - "Robert Goulet crop 008 1976.jpg" - shows: - - caption: "Jun 1975 — with Foster Brooks" - slug: "1975-jun" - sides: - - id: a - label: "Side A" - source: "Robert Goulet_Foster Brooks - June 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Robert Goulet_Foster Brooks - June 1975 (Side B).wav" - - caption: "Oct 1976" - slug: "1976-oct" - sides: - - id: a - label: "Side A" - source: "Robert Goulet - October 1976 (Side A).wav" - - id: b - label: "Side B" - source: "Robert Goulet - October 1976 (Side B).wav" - - - id: 25 - name: "Roy Clark" - slug: roy-clark - description: | - American country musician and comedian, longtime co-host of the - syndicated television show Hee Haw. A virtuoso multi-instrumentalist - and a Country Music Hall of Fame inductee. - images: - - "Roy Clark 009 crop1976.jpg" - shows: - - caption: "Apr 1976" - slug: "1976-apr" - sides: - - id: a - label: "Side A" - source: "Roy Clark - April 1976 (Side A).wav" - - id: b - label: "Side B" - source: "Roy Clark - April 1976 (Side B).wav" - - - id: 26 - name: "Sammy Davis Jr." - slug: sammy-davis-jr - description: | - American singer, dancer, actor, and member of the Rat Pack, whose - career spanned more than six decades across Broadway, film, and - television. His signature hit was "The Candy Man." - images: - - "Sammy Davis Jr. 002 1975.jpg" - - "Sammy Davis Jr. 003 1976.jpg" - shows: - - caption: "1975" - slug: "1975" - sides: - - id: a - label: "Side A" - source: "Sammy Davis - 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Sammy Davis - 1975 (Side B).wav" - - caption: "Nov 1976" - slug: "1976-nov" - sides: - - id: a - label: "Side A" - source: "Sammy Davis Jr - November 1976 (Side A).wav" - - id: b - label: "Side B" - source: "Sammy Davis Jr - November 1976 (Side B).wav" - - - id: 27 - name: "Sandler & Young" - slug: sandler-young - description: | - Singing duo Tony Sandler (Belgian) and Ralph Young (American), known - for their multilingual repertoire and tight harmony. A staple of - supper-club and television variety bookings from the late 1960s - onward. - images: - - "Sandler & Young 010 1975.jpg" - shows: - - caption: "Dec 1975 — 1st show" - slug: "1975-dec-mill-run" - sides: - - id: a - label: "Side A" - source: "Sandler_Young - December 1975 ('Mill Run' Label) (Side A).wav" - - id: b - label: "Side B" - source: "Sandler_Young - December 1975 ('Mill Run' Label) (Side B).wav" - - caption: "Dec 1975 — 2nd show" - slug: "1975-dec" - sides: - - id: a - label: "Side A" - source: "Sandler_Young - December 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Sandler_Young - December 1975 (Side B).wav" - - - id: 28 - name: "Shirley Bassey" - slug: shirley-bassey - description: | - Welsh singer with a powerful contralto, internationally known for the - three James Bond film theme songs she recorded: "Goldfinger" (1964), - "Diamonds Are Forever" (1971), and "Moonraker" (1979). - images: - - "Shirley Bassey 011 1976.jpg" - shows: - - caption: "Sep 1976" - slug: "1976-sep" - sides: - - id: a - label: "Side A" - source: "Shirley Bassey - September 1976 (Side A).wav" - - id: b - label: "Side B" - source: "Shirley Bassey - September 1976 (Side B).wav" - - - id: 29 - name: "Steve Lawrence & Eydie Gormé" - slug: steve-lawrence-eydie-gorme - description: | - American husband-and-wife singing duo who met as Steve Allen's Tonight - Show regulars in the 1950s and remained inseparable performers until - Eydie's death in 2013. Each maintained a successful solo career - alongside the duo work. - images: - - "Steve Lawrence_EydieGorme001_73.jpg" - shows: - - caption: "Aug 1977 — 1st show" - slug: "1977-aug-1" - sides: - - id: a - label: "Side A" - source: "Steve & Eydie - August 1977 (Side A).wav" - - id: b - label: "Side B" - source: "Steve & Eydie - August 1977 (Side B).wav" - - caption: "Aug 1977 — 2nd show" - slug: "1977-aug-2" - sides: - - id: a - label: "Side A" - source: "Steve Lawrence & Eydie Gorme - August 1977 (1st Show Sunday) (Side A).wav" - - id: b - label: "Side B" - source: "Steve Lawrence & Eydie Gorme - August 1977 (1st Show Sunday) (Side B).wav" - - - id: 30 - name: "The Dells" - slug: the-dells - description: | - Chicago R&B vocal group whose career stretched from the 1950s - ("Oh What a Night") through the 1990s ("Stay in My Corner"). One of - the longest-lived doo-wop and soul ensembles. - images: [] - shows: - - caption: "1975" - slug: "1975" - sides: - - id: a - label: "Side A" - source: "The Dells - 1975 (Side A).wav" - - id: b - label: "Side B" - source: "The Dells - 1975 (Side B).wav" - - - id: 31 - name: "The Irish Rovers" - slug: irish-rovers - description: | - Canadian-Irish folk group founded in Toronto in the 1960s, best known - for "The Unicorn" (1968) and "Wasn't That a Party" (1981). - images: [] - shows: - - caption: "Jul 1977 — 1st show" - slug: "1977-jul-16" - sides: - - id: a - label: "Side A" - source: "The Irish Rovers - July 16th, 1977 (1st Show) (Side A).wav" - - id: b - label: "Side B" - source: "The Irish Rovers - July 16th, 1977 (1st Show) (Side B).wav" - - caption: "Jul 1977 — 2nd show" - slug: "1977-jul-17" - sides: - - id: a - label: "Side A" - source: "The Irish Rovers - July 17th, 1977 (2nd Show) (Side A).wav" - - id: b - label: "Side B" - source: "The Irish Rovers - July 17th, 1977 (2nd Show) (Side B).wav" - - - id: 32 - name: "The Kingston Trio" - slug: kingston-trio - description: | - American folk group from San Francisco, one of the most popular acts - of the late 1950s and early '60s and a catalyst for the folk revival. - Hits include "Tom Dooley" and "Where Have All the Flowers Gone." - images: [] - shows: - - caption: "Oct 1977" - slug: "1977-oct" - sides: - - id: a - label: "Side A" - source: "The Kingston Trio - October 1977 (Side A).wav" - - id: b - label: "Side B" - source: "The Kingston Trio - October 1977 (Side B).wav" - - - id: 33 - name: "The Temptations & Honey Cone" - slug: temptations-honey-cone - description: | - Motown soul giants The Temptations ("My Girl," "Just My Imagination") - shared this bill with Honey Cone, the trio whose 1971 single - "Want Ads" topped the Billboard Hot 100. - images: - - "TheTemptations002_74.jpg" - shows: - - caption: "Dec 30, 1972" - slug: "1972-dec" - sides: - - id: a - label: "Side A" - source: "The Temptations_Honeycone - December 30th 1972 (Side A).wav" - - id: b - label: "Side B" - source: "The Temptations_Honeycone - December 30th 1972 (Side B).wav" - - - id: 34 - name: "Tom Jones" - slug: tom-jones - description: | - Welsh singer with a powerhouse baritone who broke through with "It's - Not Unusual" in 1965 and went on to build a decades-long Las Vegas - residency career. His variety show This Is Tom Jones aired from 1969 - to 1971. - images: - - "TomJones005_74.jpg" - - "Tom Jones redo 008 1976.jpg" - shows: - - caption: "1975" - slug: "1975" - sides: - - id: a - label: "Side A" - source: "Tom Jones - 1975 (1st Half) (1st Show Sat) (Side A) (No Side B).wav" - - caption: "Sep 1976" - slug: "1976-sep" - sides: - - id: a - label: "Side A" - source: "Tom Jones - September 1976 (Side A).wav" - - id: b - label: "Side B" - source: "Tom Jones - September 1976 (Side B).wav" - - - id: 35 - name: "Vic Damone" - slug: vic-damone - description: | - American singer whose smooth baritone made him a fixture on television - variety shows and a Las Vegas mainstay. Hits include "You're Breaking - My Heart" and "On the Street Where You Live." - images: - - "VicDamone001_74 HQ.jpg" - shows: - - caption: "Dec 1974" - slug: "1974-dec" - sides: - - id: a - label: "Side A" - source: "Vic Damone - December 1974 (Side A).wav" - - id: b - label: "Side B" - source: "Vic Damone - December 1974 (Side B).wav" - - - id: 36 - name: "Vikki Carr" - slug: vikki-carr - description: | - American singer of Mexican-American heritage who scored a pop hit with - "It Must Be Him" in 1967 before pivoting to a Spanish-language career - that earned her multiple Grammy and Latin Grammy awards. - images: - - "Vikki Carr 004 1976.jpg" - - "Vikki Carr 006 1975.jpg" - shows: - - caption: "1975" - slug: "1975" - sides: - - id: a - label: "Side A" - source: "Vikki Carr - 1975 (Side A).wav" - - id: b - label: "Side B" - source: "Vikki Carr - 1975 (Side B).wav" - - caption: "May 1975" - slug: "1975-may" - sides: - - id: a - label: "Side A" - source: "Vikki Carr - Sunday May 1975 (Second Half) (Red by WJT) (Side A).wav" - - id: b - label: "Side B" - source: "Vikki Carr - Sunday May 1975 (Second Half) (Red by WJT) (Side B).wav" diff --git a/content/images/AL MARTINO001_74.jpg b/content/images/AL MARTINO001_74.jpg deleted file mode 100644 index 6a812a2..0000000 Binary files a/content/images/AL MARTINO001_74.jpg and /dev/null differ diff --git a/content/images/Dionne Warwick 1974 from Don Leavitt.jpg b/content/images/Dionne Warwick 1974 from Don Leavitt.jpg deleted file mode 100644 index 558d2b1..0000000 Binary files a/content/images/Dionne Warwick 1974 from Don Leavitt.jpg and /dev/null differ diff --git a/content/images/Don Ho 001 1980.jpg b/content/images/Don Ho 001 1980.jpg deleted file mode 100644 index d91ab7b..0000000 Binary files a/content/images/Don Ho 001 1980.jpg and /dev/null differ diff --git a/content/images/Don Rickles 002 1975.jpg b/content/images/Don Rickles 002 1975.jpg deleted file mode 100644 index f53a81c..0000000 Binary files a/content/images/Don Rickles 002 1975.jpg and /dev/null differ diff --git a/content/images/Eddy Arnold 001 1975.jpg b/content/images/Eddy Arnold 001 1975.jpg deleted file mode 100644 index 30be557..0000000 Binary files a/content/images/Eddy Arnold 001 1975.jpg and /dev/null differ diff --git a/content/images/Engelbert Humperdinck 003 1975.jpg b/content/images/Engelbert Humperdinck 003 1975.jpg deleted file mode 100644 index d336e11..0000000 Binary files a/content/images/Engelbert Humperdinck 003 1975.jpg and /dev/null differ diff --git a/content/images/Florence Henderson 009 1975.jpg b/content/images/Florence Henderson 009 1975.jpg deleted file mode 100644 index 733dc8c..0000000 Binary files a/content/images/Florence Henderson 009 1975.jpg and /dev/null differ diff --git a/content/images/Frankie Laine 002 1975.jpg b/content/images/Frankie Laine 002 1975.jpg deleted file mode 100644 index 28e87a6..0000000 Binary files a/content/images/Frankie Laine 002 1975.jpg and /dev/null differ diff --git a/content/images/Gladys Knight & the Pips 001 1975.jpg b/content/images/Gladys Knight & the Pips 001 1975.jpg deleted file mode 100644 index 41c6890..0000000 Binary files a/content/images/Gladys Knight & the Pips 001 1975.jpg and /dev/null differ diff --git a/content/images/Gladys Knight and the Pips 001 1975.jpg b/content/images/Gladys Knight and the Pips 001 1975.jpg deleted file mode 100644 index 585f1bb..0000000 Binary files a/content/images/Gladys Knight and the Pips 001 1975.jpg and /dev/null differ diff --git a/content/images/Glenn Campbell 006 1973.jpg b/content/images/Glenn Campbell 006 1973.jpg deleted file mode 100644 index fb83e3f..0000000 Binary files a/content/images/Glenn Campbell 006 1973.jpg and /dev/null differ diff --git a/content/images/HelenReddy001_74.jpg b/content/images/HelenReddy001_74.jpg deleted file mode 100644 index f625039..0000000 Binary files a/content/images/HelenReddy001_74.jpg and /dev/null differ diff --git a/content/images/Jim Nabors 002 1975.jpg b/content/images/Jim Nabors 002 1975.jpg deleted file mode 100644 index a05e48d..0000000 Binary files a/content/images/Jim Nabors 002 1975.jpg and /dev/null differ diff --git a/content/images/JohnDavidson002_74 HQ.jpg b/content/images/JohnDavidson002_74 HQ.jpg deleted file mode 100644 index 293b599..0000000 Binary files a/content/images/JohnDavidson002_74 HQ.jpg and /dev/null differ diff --git a/content/images/Johnny Mathis 004 1975.jpg b/content/images/Johnny Mathis 004 1975.jpg deleted file mode 100644 index ee530ea..0000000 Binary files a/content/images/Johnny Mathis 004 1975.jpg and /dev/null differ diff --git a/content/images/Kate Smith 006 1975.jpg b/content/images/Kate Smith 006 1975.jpg deleted file mode 100644 index 68509ae..0000000 Binary files a/content/images/Kate Smith 006 1975.jpg and /dev/null differ diff --git a/content/images/Mills Brothers 003 1975.jpg b/content/images/Mills Brothers 003 1975.jpg deleted file mode 100644 index b1d1b69..0000000 Binary files a/content/images/Mills Brothers 003 1975.jpg and /dev/null differ diff --git a/content/images/Mitzi Gaynor 007 1976.jpg b/content/images/Mitzi Gaynor 007 1976.jpg deleted file mode 100644 index b61d41b..0000000 Binary files a/content/images/Mitzi Gaynor 007 1976.jpg and /dev/null differ diff --git a/content/images/Robert Goulet crop 008 1976.jpg b/content/images/Robert Goulet crop 008 1976.jpg deleted file mode 100644 index 17dfc6f..0000000 Binary files a/content/images/Robert Goulet crop 008 1976.jpg and /dev/null differ diff --git a/content/images/Roy Clark 009 crop1976.jpg b/content/images/Roy Clark 009 crop1976.jpg deleted file mode 100644 index 92b5cab..0000000 Binary files a/content/images/Roy Clark 009 crop1976.jpg and /dev/null differ diff --git a/content/images/Sammy Davis Jr. 002 1975.jpg b/content/images/Sammy Davis Jr. 002 1975.jpg deleted file mode 100644 index 64210bb..0000000 Binary files a/content/images/Sammy Davis Jr. 002 1975.jpg and /dev/null differ diff --git a/content/images/Sammy Davis Jr. 003 1976.jpg b/content/images/Sammy Davis Jr. 003 1976.jpg deleted file mode 100644 index 3939cc9..0000000 Binary files a/content/images/Sammy Davis Jr. 003 1976.jpg and /dev/null differ diff --git a/content/images/Sandler & Young 010 1975.jpg b/content/images/Sandler & Young 010 1975.jpg deleted file mode 100644 index 3b8b0ca..0000000 Binary files a/content/images/Sandler & Young 010 1975.jpg and /dev/null differ diff --git a/content/images/Shirley Bassey 011 1976.jpg b/content/images/Shirley Bassey 011 1976.jpg deleted file mode 100644 index f9da521..0000000 Binary files a/content/images/Shirley Bassey 011 1976.jpg and /dev/null differ diff --git a/content/images/Steve Lawrence_EydieGorme001_73.jpg b/content/images/Steve Lawrence_EydieGorme001_73.jpg deleted file mode 100644 index 596c928..0000000 Binary files a/content/images/Steve Lawrence_EydieGorme001_73.jpg and /dev/null differ diff --git a/content/images/The 5th DimentionFD001_74.jpg b/content/images/The 5th DimentionFD001_74.jpg deleted file mode 100644 index 53aade9..0000000 Binary files a/content/images/The 5th DimentionFD001_74.jpg and /dev/null differ diff --git a/content/images/TheTemptations002_74.jpg b/content/images/TheTemptations002_74.jpg deleted file mode 100644 index ed56f86..0000000 Binary files a/content/images/TheTemptations002_74.jpg and /dev/null differ diff --git a/content/images/Tom Jones redo 008 1976.jpg b/content/images/Tom Jones redo 008 1976.jpg deleted file mode 100644 index de353b7..0000000 Binary files a/content/images/Tom Jones redo 008 1976.jpg and /dev/null differ diff --git a/content/images/TomJones005_74.jpg b/content/images/TomJones005_74.jpg deleted file mode 100644 index 5e24858..0000000 Binary files a/content/images/TomJones005_74.jpg and /dev/null differ diff --git a/content/images/VicDamone001_74 HQ.jpg b/content/images/VicDamone001_74 HQ.jpg deleted file mode 100644 index 4d38b8f..0000000 Binary files a/content/images/VicDamone001_74 HQ.jpg and /dev/null differ diff --git a/content/images/Vikki Carr 004 1976.jpg b/content/images/Vikki Carr 004 1976.jpg deleted file mode 100644 index a6a94ab..0000000 Binary files a/content/images/Vikki Carr 004 1976.jpg and /dev/null differ diff --git a/content/images/Vikki Carr 006 1975.jpg b/content/images/Vikki Carr 006 1975.jpg deleted file mode 100644 index 790e64a..0000000 Binary files a/content/images/Vikki Carr 006 1975.jpg and /dev/null differ diff --git a/content/reference/reference-the_lettermen-mill_run.jpg b/content/reference/reference-the_lettermen-mill_run.jpg deleted file mode 100644 index 1e202be..0000000 Binary files a/content/reference/reference-the_lettermen-mill_run.jpg and /dev/null differ diff --git a/content/stops.yaml b/content/stops.yaml index 56ae8cc..136e373 100644 --- a/content/stops.yaml +++ b/content/stops.yaml @@ -1,324 +1,30 @@ # Source of truth for exhibit content. -# A build step generates web/src/lib/stops.json from this file (and -# transcodes content/audio/*.wav → web/static/audio/*.opus, similarly for images). +# A build step generates web/src/lib/stops.json from this file. # -# Each stop: -# id — integer, used in URLs and as the asset basename prefix -# title — performer(s) as printed on the exhibit -# audio — source filename in content/audio/ -# image — source filename in content/images/ -# caption — short line shown beneath the title (date / show info) +# Each stop has: +# id — integer, used in URLs and as the asset basename +# title — short label, shown in the grid and on the detail page +# audio — filename in content/audio/, transcoded to web/static/audio/ +# image — filename in content/images/, transcoded to web/static/images/ +# caption — short line shown beneath the title # description — longer text shown below the audio player (markdown allowed) exhibit: - title: "Mill Run Playhouse-Theatre" - subtitle: "" + title: "TBD" + subtitle: "TBD" stops: - id: 1 - title: "Al Martino" - audio: 01-al-martino.wav - image: 01-al-martino.png - caption: "1974" - description: "" + title: "Welcome" + audio: 01-welcome.wav + image: 01-welcome.png + caption: "An introduction to the exhibit." + description: | + Placeholder for the full description shown on the stop detail page. - id: 2 - title: "Caterina Valente" - audio: 02-caterina-valente.wav - image: 02-caterina-valente.png - caption: "Aug 1976" - description: "" - - - id: 3 - title: "Dionne Warwicke" - audio: 03-dionne-warwicke.wav - image: 03-dionne-warwicke.png - caption: "1974" - description: "" - - - id: 4 - title: "Don Ho" - audio: 04-don-ho.wav - image: 04-don-ho.png - caption: "Jun 26, 1977" - description: "" - - - id: 5 - title: "Don Rickles" - audio: 05-don-rickles.wav - image: 05-don-rickles.png - caption: "May 25, 1975" - description: "" - - - id: 6 - title: "Eddy Arnold" - audio: 06-eddy-arnold.wav - image: 06-eddy-arnold.png - caption: "1975" - description: "" - - - id: 7 - title: "Engelbert Humperdinck" - audio: 07-engelbert-humperdinck.wav - image: 07-engelbert-humperdinck.png - caption: "Oct 1975" - description: "" - - - id: 8 - title: "Frankie Laine" - audio: 08-frankie-laine.wav - image: 08-frankie-laine.png - caption: "Sun, Sep 1975 — 2nd show" - description: "" - - - id: 9 - title: "Gladys Knight" - audio: 09-gladys-knight-aug-1977.wav - image: 09-gladys-knight-aug-1977.png - caption: "Sat, Aug 1977 — 1st & 2nd show" - description: "" - - - id: 10 - title: "Gladys Knight" - audio: 10-gladys-knight-oct-1975-fri.wav - image: 10-gladys-knight-oct-1975-fri.png - caption: "Fri, Oct 1975 — 2nd show" - description: "" - - - id: 11 - title: "Gladys Knight" - audio: 11-gladys-knight-oct-1975-sat.wav - image: 11-gladys-knight-oct-1975-sat.png - caption: "Sat, Oct 1975 — 2nd show" - description: "" - - - id: 12 - title: "Glenn Campbell & Jud Strunk" - audio: 12-glenn-campbell-jud-strunk.wav - image: 12-glenn-campbell-jud-strunk.png - caption: "Dec 1973" - description: "" - - - id: 13 - title: "Glenn Yarbrough & The Limeliters" - audio: 13-glenn-yarbrough-limeliters.wav - image: 13-glenn-yarbrough-limeliters.png - caption: "Oct 1977" - description: "" - - - id: 14 - title: "Harry Belafonte" - audio: 14-harry-belafonte.wav - image: 14-harry-belafonte.png - caption: "May 1976" - description: "" - - - id: 15 - title: "Helen Reddy" - audio: 15-helen-reddy.wav - image: 15-helen-reddy.png - caption: "1974" - description: "" - - - id: 16 - title: "Henderson & Nabors" - audio: 16-henderson-nabors.wav - image: 16-henderson-nabors.png - caption: "Jul 1975" - description: "" - - - id: 17 - title: "Hues Corp & 5th Dimension" - audio: 17-hues-corp-5th-dimension.wav - image: 17-hues-corp-5th-dimension.png - caption: "1974" - description: "" - - - id: 18 - title: "John Davidson" - audio: 18-john-davidson.wav - image: 18-john-davidson.png - caption: "1974" - description: "" - - - id: 19 - title: "Johnny Mathis" - audio: 19-johnny-mathis-aug-1975.wav - image: 19-johnny-mathis-aug-1975.png - caption: "Sun, Aug 1975 — 1st show" - description: "" - - - id: 20 - title: "Johnny Mathis" - audio: 20-johnny-mathis-aug-1976.wav - image: 20-johnny-mathis-aug-1976.png - caption: "Aug 1976" - description: "" - - - id: 21 - title: "Kate Smith" - audio: 21-kate-smith.wav - image: 21-kate-smith.png - caption: "Nov 1975" - description: "" - - - id: 22 - title: "Lainie Kazan" - audio: 22-lainie-kazan.wav - image: 22-lainie-kazan.png - caption: "Aug 1975" - description: "" - - - id: 23 - title: "Love Machine" - audio: 23-love-machine.wav - image: 23-love-machine.png - caption: "Oct 1976" - description: "" - - - id: 24 - title: "Martin & Charisse" - audio: 24-martin-charisse.wav - image: 24-martin-charisse.png - caption: "Aug 1975" - description: "" - - - id: 25 - title: "Mill Bros" - audio: 25-mill-bros.wav - image: 25-mill-bros.png - caption: "Sep 1975" - description: "" - - - id: 26 - title: "Mitzi Gaynor" - audio: 26-mitzi-gaynor.wav - image: 26-mitzi-gaynor.png - caption: "Oct 2, 1977" - description: "" - - - id: 27 - title: "Robert Goulet" - audio: 27-robert-goulet.wav - image: 27-robert-goulet.png - caption: "Oct 1976" - description: "" - - - id: 28 - title: "Goulet & Foster Brooks" - audio: 28-goulet-foster-brooks.wav - image: 28-goulet-foster-brooks.png - caption: "Jun 1975" - description: "" - - - id: 29 - title: "Roy Clark" - audio: 29-roy-clark.wav - image: 29-roy-clark.png - caption: "Apr 1976" - description: "" - - - id: 30 - title: "Sammy Davis" - audio: 30-sammy-davis-1975.wav - image: 30-sammy-davis-1975.png - caption: "1975" - description: "" - - - id: 31 - title: "Sammy Davis Jr" - audio: 31-sammy-davis-jr-1976.wav - image: 31-sammy-davis-jr-1976.png - caption: "Nov 1976" - description: "" - - - id: 32 - title: "Sandler & Young" - audio: 32-sandler-young.wav - image: 32-sandler-young.png - caption: "Dec 1975" - description: "" - - - id: 33 - title: "Shirley Bassey" - audio: 33-shirley-bassey.wav - image: 33-shirley-bassey.png - caption: "Sep 1976" - description: "" - - - id: 34 - title: "Steve Lawrence & Eydie Gorme" - audio: 34-steve-lawrence-eydie-gorme.wav - image: 34-steve-lawrence-eydie-gorme.png - caption: "Aug 1977" - description: "" - - - id: 35 - title: "The Dells" - audio: 35-the-dells.wav - image: 35-the-dells.png - caption: "1975" - description: "" - - - id: 36 - title: "The Irish Rovers" - audio: 36-irish-rovers-jul16.wav - image: 36-irish-rovers-jul16.png - caption: "Jul 16, 1977 — 1st show" - description: "" - - - id: 37 - title: "The Irish Rovers" - audio: 37-irish-rovers-jul17.wav - image: 37-irish-rovers-jul17.png - caption: "Jul 17, 1977 — 2nd show" - description: "" - - - id: 38 - title: "The Kingston Trio" - audio: 38-kingston-trio.wav - image: 38-kingston-trio.png - caption: "Oct 1977" - description: "" - - - id: 39 - title: "The Temptations" - audio: 39-temptations.wav - image: 39-temptations.png - caption: "Dec 30, 1972" - description: "" - - - id: 40 - title: "Tom Jones" - audio: 40-tom-jones-1975.wav - image: 40-tom-jones-1975.png - caption: "Sat, 1975 — 1st show" - description: "" - - - id: 41 - title: "Tom Jones" - audio: 41-tom-jones-1976.wav - image: 41-tom-jones-1976.png - caption: "Sep 1976" - description: "" - - - id: 42 - title: "Vic Damone" - audio: 42-vic-damone.wav - image: 42-vic-damone.png - caption: "Dec 1974" - description: "" - - - id: 43 - title: "Vikki Carr" - audio: 43-vikki-carr-1975.wav - image: 43-vikki-carr-1975.png - caption: "1975" - description: "" - - - id: 44 - title: "Vikki Carr" - audio: 44-vikki-carr-may-1975.wav - image: 44-vikki-carr-may-1975.png - caption: "Sun, May 1975" + title: "Stop two placeholder" + audio: 02.wav + image: 02.png + caption: "" description: "" diff --git a/flake.nix b/flake.nix index 786a9d8..14060c1 100644 --- a/flake.nix +++ b/flake.nix @@ -21,7 +21,6 @@ ffmpeg imagemagick yq-go - jq ]; }; } diff --git a/server/main.go b/server/main.go index aebbc5d..d12c9e1 100644 --- a/server/main.go +++ b/server/main.go @@ -16,6 +16,7 @@ import ( type server struct { staticDir string password string + qrKey string secret []byte secure bool loginLimiter *rateLimiter @@ -25,13 +26,20 @@ func main() { addr := flag.String("addr", ":8181", "listen address") staticDir := flag.String("static", "../web/build", "static asset directory") insecure := flag.Bool("insecure", false, "drop Secure flag from cookie (dev only)") - strict := flag.Bool("strict", false, "production mode: refuse to start without DOCENT_COOKIE_SECRET") + strict := flag.Bool("strict", false, "production mode: refuse to start without DOCENT_COOKIE_SECRET and DOCENT_QR_KEY") flag.Parse() password := os.Getenv("DOCENT_PASSWORD") if password == "" { log.Fatal("DOCENT_PASSWORD must be set") } + qrKey := os.Getenv("DOCENT_QR_KEY") + if qrKey == "" { + if *strict { + log.Fatal("DOCENT_QR_KEY must be set in -strict mode") + } + log.Println("warning: DOCENT_QR_KEY not set; QR-code auto-login disabled") + } cookieSecret := os.Getenv("DOCENT_COOKIE_SECRET") if *strict && cookieSecret == "" { @@ -53,6 +61,7 @@ func main() { s := &server{ staticDir: abs, password: password, + qrKey: qrKey, secret: secret, secure: !*insecure, loginLimiter: newRateLimiter(8, time.Minute), @@ -60,6 +69,7 @@ func main() { mux := http.NewServeMux() mux.HandleFunc("POST /api/login", s.handleLogin) + mux.HandleFunc("POST /api/key", s.handleKey) mux.HandleFunc("POST /api/logout", s.handleLogout) mux.HandleFunc("GET /api/me", s.handleMe) mux.Handle("GET /audio/", s.requireAuth(http.HandlerFunc(s.serveStatic))) @@ -116,6 +126,26 @@ func (s *server) handleLogin(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } +func (s *server) handleKey(w http.ResponseWriter, r *http.Request) { + if !s.loginLimiter.allow(clientIP(r)) { + w.Header().Set("Retry-After", "60") + http.Error(w, "too many attempts", http.StatusTooManyRequests) + return + } + var body struct { + Key string `json:"key"` + } + err := json.NewDecoder(r.Body).Decode(&body) + // An empty qrKey means the QR auto-login is disabled — never accept any value. + if err != nil || s.qrKey == "" || !constantTimeEqualString(body.Key, s.qrKey) { + time.Sleep(250 * time.Millisecond) + http.Error(w, "unauthorized", http.StatusUnauthorized) + return + } + s.setSessionCookie(w) + w.WriteHeader(http.StatusNoContent) +} + func (s *server) handleLogout(w http.ResponseWriter, r *http.Request) { s.clearSessionCookie(w) w.WriteHeader(http.StatusNoContent) @@ -177,6 +207,7 @@ func (s *server) serveSPA(w http.ResponseWriter, r *http.Request) { return } + // Unknown path → SPA fallback. w.Header().Set("Cache-Control", "no-cache") http.ServeFile(w, r, filepath.Join(s.staticDir, "index.html")) } diff --git a/web/package-lock.json b/web/package-lock.json index ddd65f0..844eacd 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -7,14 +7,6 @@ "": { "name": "docent-web", "version": "0.0.1", - "dependencies": { - "@fontsource/bebas-neue": "^5.1.0", - "@fontsource/cantarell": "^5.1.0", - "@fontsource/cormorant-garamond": "^5.1.0", - "@fontsource/inspiration": "^5.1.0", - "@fontsource/oswald": "^5.1.0", - "@fontsource/playwrite-de-sas": "^5.1.0" - }, "devDependencies": { "@sveltejs/adapter-static": "^3.0.5", "@sveltejs/kit": "^2.7.0", @@ -416,60 +408,6 @@ "node": ">=12" } }, - "node_modules/@fontsource/bebas-neue": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/bebas-neue/-/bebas-neue-5.2.7.tgz", - "integrity": "sha512-DsmBrmq55d9BCU0mt4DT4RZDdH8vhWRKEUOfbuNB1EEjMuwbtFvM8N+3gIlkYSFbsb10P8Q19BV5OdpMu2h0fA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/cantarell": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/cantarell/-/cantarell-5.2.8.tgz", - "integrity": "sha512-MQKwrtpAmd5disYpoTcxliqQjzn/5msazpycrS57ppNNV8HKDP3RYpVTcEw8nYvWVoXwqSOkU2/RHmo3VqckkQ==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/cormorant-garamond": { - "version": "5.2.11", - "resolved": "https://registry.npmjs.org/@fontsource/cormorant-garamond/-/cormorant-garamond-5.2.11.tgz", - "integrity": "sha512-5JjpN023lhA5soijgVT0BdRGzmlijm402ppjccMd6h+vRE0mX2lJnE+41UPfnlidrkV9/rCo1mf58WZlHnB0CA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/inspiration": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/inspiration/-/inspiration-5.2.7.tgz", - "integrity": "sha512-Unh3kgWHn024288t5u8EiBgqR6i+PdHNCjrvPIhgCRS02XlgwoXQeWzUPCknWY/5WRsGJUsu3sJxo+0sMM7esQ==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/oswald": { - "version": "5.2.8", - "resolved": "https://registry.npmjs.org/@fontsource/oswald/-/oswald-5.2.8.tgz", - "integrity": "sha512-DFoPK1BqsFIQhVjs2xgO/oL9veF9oUJgFojEWIU+nazUrfqsBDtAMI4n9L9CZFX3kQNDLcCyzKx1xoEDvQT4WQ==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, - "node_modules/@fontsource/playwrite-de-sas": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@fontsource/playwrite-de-sas/-/playwrite-de-sas-5.2.7.tgz", - "integrity": "sha512-ELyLve5ZbiEm3Ra2itvO4wjlqrjS6G/6SYTh7K8Mdbi/Ib/PEjZcyCzZChfw0lCx62AJWk5HYvGeXqS6KVjPaA==", - "license": "OFL-1.1", - "funding": { - "url": "https://github.com/sponsors/ayuhito" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", diff --git a/web/package.json b/web/package.json index 2df743f..ecc0606 100644 --- a/web/package.json +++ b/web/package.json @@ -9,14 +9,6 @@ "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json" }, - "dependencies": { - "@fontsource/bebas-neue": "^5.1.0", - "@fontsource/cantarell": "^5.1.0", - "@fontsource/cormorant-garamond": "^5.1.0", - "@fontsource/inspiration": "^5.1.0", - "@fontsource/oswald": "^5.1.0", - "@fontsource/playwrite-de-sas": "^5.1.0" - }, "devDependencies": { "@sveltejs/adapter-static": "^3.0.5", "@sveltejs/kit": "^2.7.0", diff --git a/web/src/app.css b/web/src/app.css index 5fb17d1..4c58f6c 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -1,54 +1,16 @@ -@import '@fontsource/playwrite-de-sas/100.css'; -@import '@fontsource/cormorant-garamond/400.css'; -@import '@fontsource/cormorant-garamond/400-italic.css'; -@import '@fontsource/cormorant-garamond/600.css'; -@import '@fontsource/cantarell/400.css'; -@import '@fontsource/cantarell/700.css'; -@import '@fontsource/bebas-neue/400.css'; -@import '@fontsource/oswald/400.css'; -@import '@fontsource/oswald/500.css'; - -/* Inspiration is used only for the uppercase letters in script titles - * (matches the brand treatment where the leading caps are extra-flourished). - * The unicode-range restriction means the browser falls through to - * Playwrite DK Loopet for everything else automatically — no markup spans. - */ -@font-face { - font-family: 'Inspiration Caps'; - font-style: normal; - /* Inspiration is only published at weight 400; declare a wide range here - * so this face matches whatever weight the title-script class requests. */ - font-weight: 100 900; - font-display: swap; - src: - url('@fontsource/inspiration/files/inspiration-latin-400-normal.woff2') format('woff2'), - url('@fontsource/inspiration/files/inspiration-latin-400-normal.woff') format('woff'); - unicode-range: U+0041-005A; -} - :root { - /* Mill Run brand palette */ - --bg: #b9cfba; /* sage — main background */ - --bg-card: #ffffff; /* card / tile background on the sage page */ - --bg-callout: #4b6c64; /* deep teal — callout panels */ - --bg-paper: #f6ecd6; /* warm ivory — Stagebill program paper */ - --ink: #4b6c64; /* primary body text */ - --ink-on-callout: #b9cfba; /* text on dark teal callouts */ - --ink-mute: #6b8a82; /* secondary teal for de-emphasis */ - --ink-deep: #11281f; /* very dark green for high contrast on paper/light bg */ - --title: #c33b23; /* red-orange — titles, focus, errors (darkened from #e1442b) */ - --highlight: #f1b416; /* yellow — accents, scrub thumb, indicators */ - --rule: #9bb59c; /* darker sage — borders/dividers */ - --shadow: 0 1px 2px rgba(75, 108, 100, 0.12), 0 8px 24px rgba(75, 108, 100, 0.18); - + --bg: #faf7f2; + --bg-elev: #ffffff; + --ink: #2a2520; + --ink-mute: #6b6157; + --accent: #6e3a1f; + --rule: #e8e0d4; --radius: 14px; --radius-lg: 22px; + --shadow: 0 1px 2px rgba(42, 37, 32, 0.06), 0 8px 24px rgba(42, 37, 32, 0.08); --font-sans: ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; --font-serif: ui-serif, Georgia, 'Times New Roman', serif; - --font-script: 'Inspiration Caps', 'Playwrite DE SAS', cursive; - --font-marquee: 'Bebas Neue', 'Anton', 'Oswald', 'Arial Narrow', sans-serif; - --font-editorial: 'Cormorant Garamond', 'Iowan Old Style', Cambria, Georgia, serif; color-scheme: light; } @@ -79,18 +41,14 @@ body { } h1, h2, h3 { - font-weight: 600; - letter-spacing: -0.005em; - margin: 0; - color: var(--title); -} - -h2, h3 { font-family: var(--font-serif); + font-weight: 600; + letter-spacing: -0.01em; + margin: 0; } a { - color: var(--title); + color: var(--accent); text-decoration: none; } @@ -112,101 +70,3 @@ img { display: block; max-width: 100%; } - -/* Title-style headings (the script-font, brand-red ones). - * Apply via `.title-script` to any heading we want to render in the - * exhibit's primary script-and-red treatment. - */ -.title-script { - font-family: var(--font-script); - color: var(--title); - font-weight: 100; - line-height: 1.25; - letter-spacing: 0; - /* Playwrite has long ascenders/descenders; allow them to breathe. */ - padding: 0.1em 0.05em; -} - -/* Marquee letter-board: white sign with bold black changeable-letter text. - * Modeled on the actual Mill Run marquee from the 1970s. */ -.marquee-panel { - position: relative; - display: inline-block; - max-width: 100%; - color: #111111; - /* Scale side padding with viewport so phone screens aren't doubly cramped. */ - padding: clamp(1.5rem, 5vw, 2.5rem) clamp(1.25rem, 5vw, 3rem) clamp(1.75rem, 5vw, 2.75rem); - border-radius: 4px; - border: 1px solid rgba(0, 0, 0, 0.08); - background: #ffffff; - box-shadow: - 0 1px 0 rgba(0, 0, 0, 0.08) inset, - 0 6px 24px rgba(75, 108, 100, 0.18); - text-align: center; -} - -/* Bulb ring: a single stroked rect with `stroke-dasharray: 0 N` and round - * caps renders evenly-spaced circular dots that traverse the corners cleanly. */ -.marquee-panel .bulbs { - position: absolute; - inset: 0; - width: 100%; - height: 100%; - pointer-events: none; -} -.marquee-panel .bulbs rect { - x: 11px; - y: 11px; - width: calc(100% - 22px); - height: calc(100% - 22px); - rx: 3px; - fill: none; - stroke: var(--highlight); - stroke-width: 7; - /* pathLength is set on each rect in the template; dasharray "0 2" - * over a path of length N places N/2 evenly-spaced dots, so the first - * and last align exactly with no leftover corner gap. */ - stroke-dasharray: 0 2; - stroke-linecap: round; -} - -.title-marquee { - font-family: var(--font-marquee); - color: var(--title); - font-weight: 400; - line-height: 0.95; - letter-spacing: 0.04em; - text-transform: uppercase; - margin: 0; - text-align: center; -} - -.marquee-body { - font-family: var(--font-marquee); - color: #111111; - font-weight: 400; - font-size: clamp(0.95rem, 2.4vw, 1.25rem); - line-height: 1.15; - letter-spacing: 0.08em; - text-transform: uppercase; - margin: 0.4rem 0 0; - text-align: center; -} -.marquee-body + .marquee-body { - margin-top: 0.25rem; -} - -/* The yellow heading band that sits behind a script title. - * `max-width: 100%` keeps it inside narrow containers (login card on phones). - * `overflow-wrap: break-word` lets long titles wrap rather than overflow. - */ -.band { - display: inline-block; - max-width: 100%; - padding: 2rem 3.25rem 2.25rem; - background: var(--highlight); - border-radius: 2.5rem; - box-shadow: 0 1px 0 rgba(75, 108, 100, 0.08); - overflow-wrap: break-word; - hyphens: auto; -} diff --git a/web/src/app.html b/web/src/app.html index 42415c6..cdc6961 100644 --- a/web/src/app.html +++ b/web/src/app.html @@ -11,7 +11,7 @@ - Mill Run Theatre + Mill Run %sveltekit.head% diff --git a/web/src/lib/artists.json b/web/src/lib/artists.json deleted file mode 100644 index a460314..0000000 --- a/web/src/lib/artists.json +++ /dev/null @@ -1,1230 +0,0 @@ -{ - "exhibit": { - "title": "Mill Run Theatre", - "description": "Listen to performances from the Mill Run\nSelect from the artists below\n" - }, - "artists": [ - { - "id": 1, - "name": "Al Martino", - "slug": "al-martino", - "description": "American singer of Italian descent best known for the ballad \"Here\nin My Heart\" and the perennial \"Spanish Eyes.\" Martino also played\nthe singer Johnny Fontane in The Godfather and its sequel.", - "images": [ - "/images/al-martino-1.webp" - ], - "shows": [ - { - "caption": "1974", - "slug": "1974", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/al-martino-1974-a.opus" - } - ] - } - ] - }, - { - "id": 2, - "name": "Caterina Valente", - "slug": "caterina-valente", - "description": "Italo-French entertainer who recorded in over a dozen languages across\na career spanning the 1950s through the 1980s. A jazz-trained singer,\nshe was a fixture of European and American television variety shows.", - "images": [], - "shows": [ - { - "caption": "Aug 1976", - "slug": "1976-aug", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/caterina-valente-1976-aug-a.opus" - } - ] - } - ] - }, - { - "id": 3, - "name": "Dionne Warwick", - "slug": "dionne-warwicke", - "description": "American singer who became the definitive voice of the Burt Bacharach\nand Hal David songbook in the 1960s: \"Walk On By,\" \"Anyone Who Had a\nHeart,\" and \"Do You Know the Way to San Jose.\" From 1971 to 1975 she\nperformed under the alternate spelling \"Warwicke.\"", - "images": [ - "/images/dionne-warwicke-1.webp" - ], - "shows": [ - { - "caption": "1974", - "slug": "1974", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/dionne-warwicke-1974-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/dionne-warwicke-1974-b.opus" - } - ] - } - ] - }, - { - "id": 4, - "name": "Don Ho", - "slug": "don-ho", - "description": "Hawaiian musician and entertainer whose 1966 single \"Tiny Bubbles\"\nbecame his lifelong signature. He performed nightly in Waikiki for\ndecades and toured the mainland into the 2000s.", - "images": [ - "/images/don-ho-1.webp" - ], - "shows": [ - { - "caption": "Jun 26, 1977 — 1st show", - "slug": "1977-jun-1", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/don-ho-1977-jun-1-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/don-ho-1977-jun-1-b.opus" - } - ] - }, - { - "caption": "Jun 26, 1977 — 2nd show", - "slug": "1977-jun-2", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/don-ho-1977-jun-2-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/don-ho-1977-jun-2-b.opus" - } - ] - } - ] - }, - { - "id": 5, - "name": "Don Rickles", - "slug": "don-rickles", - "description": "American stand-up comedian known for insult comedy aimed affectionately\nat celebrities and audience members alike. A regular on television\nvariety and talk shows from the 1960s onward.", - "images": [ - "/images/don-rickles-1.webp" - ], - "shows": [ - { - "caption": "May 25, 1975", - "slug": "1975-may", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/don-rickles-1975-may-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/don-rickles-1975-may-b.opus" - } - ] - } - ] - }, - { - "id": 6, - "name": "Eddy Arnold", - "slug": "eddy-arnold", - "description": "Tennessee-born country singer who placed more than 145 songs on the\ncountry charts across five decades. Hits include \"Make the World Go\nAway\" and \"Cattle Call.\"", - "images": [ - "/images/eddy-arnold-1.webp" - ], - "shows": [ - { - "caption": "1975", - "slug": "1975", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/eddy-arnold-1975-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/eddy-arnold-1975-b.opus" - } - ] - }, - { - "caption": "Nov 1977", - "slug": "1977-nov", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/eddy-arnold-1977-nov-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/eddy-arnold-1977-nov-b.opus" - } - ] - } - ] - }, - { - "id": 7, - "name": "Engelbert Humperdinck", - "slug": "engelbert-humperdinck", - "description": "British pop singer whose 1967 single \"Release Me\" famously kept the\nBeatles' \"Strawberry Fields Forever\" from reaching number one in the\nUK. His stage name was borrowed from a 19th-century German opera\ncomposer.", - "images": [ - "/images/engelbert-humperdinck-1.webp" - ], - "shows": [ - { - "caption": "Oct 1975", - "slug": "1975-oct", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/engelbert-humperdinck-1975-oct-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/engelbert-humperdinck-1975-oct-b.opus" - } - ] - } - ] - }, - { - "id": 8, - "name": "Frankie Laine", - "slug": "frankie-laine", - "description": "American crooner whose hits include \"That's My Desire,\" \"Mule Train,\"\n\"Jezebel,\" and the theme from the television series Rawhide.", - "images": [ - "/images/frankie-laine-1.webp" - ], - "shows": [ - { - "caption": "Sep 1975", - "slug": "1975-sep", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/frankie-laine-1975-sep-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/frankie-laine-1975-sep-b.opus" - } - ] - } - ] - }, - { - "id": 9, - "name": "Gladys Knight & the Pips", - "slug": "gladys-knight", - "description": "American soul and funk group fronted by Gladys Knight with her brother\nand two cousins as the Pips. Hits include \"Midnight Train to Georgia,\"\n\"I Heard It Through the Grapevine,\" and \"Neither One of Us.\"", - "images": [ - "/images/gladys-knight-1.webp", - "/images/gladys-knight-2.webp" - ], - "shows": [ - { - "caption": "Aug 1977 — 1st show", - "slug": "1977-aug-1st", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/gladys-knight-1977-aug-1st-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/gladys-knight-1977-aug-1st-b.opus" - } - ] - }, - { - "caption": "Aug 1977 — 2nd show", - "slug": "1977-aug-2nd", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/gladys-knight-1977-aug-2nd-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/gladys-knight-1977-aug-2nd-b.opus" - } - ] - }, - { - "caption": "Oct 1975 — 1st show", - "slug": "1975-oct-fri", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/gladys-knight-1975-oct-fri-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/gladys-knight-1975-oct-fri-b.opus" - } - ] - }, - { - "caption": "Oct 1975 — 2nd show", - "slug": "1975-oct-sat", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/gladys-knight-1975-oct-sat-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/gladys-knight-1975-oct-sat-b.opus" - } - ] - } - ] - }, - { - "id": 10, - "name": "Glen Campbell & Jud Strunk", - "slug": "glen-campbell-jud-strunk", - "description": "Country-pop superstar Glen Campbell (\"Wichita Lineman,\" \"Rhinestone\nCowboy\") shared this bill with Jud Strunk, a Maine native who reached\nthe U.S. Top 20 in 1973 with the novelty hit \"Daisy a Day.\"", - "images": [ - "/images/glen-campbell-jud-strunk-1.webp" - ], - "shows": [ - { - "caption": "Dec 1973", - "slug": "1973-dec", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/glen-campbell-jud-strunk-1973-dec-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/glen-campbell-jud-strunk-1973-dec-b.opus" - } - ] - } - ] - }, - { - "id": 11, - "name": "Glenn Yarbrough & The Limeliters", - "slug": "glenn-yarbrough-limeliters", - "description": "Folk singer who rose to fame with the Limeliters, one of the leading\nacts of the early-1960s folk revival, before launching a successful\nsolo career. He occasionally rejoined the group for reunion tours.", - "images": [], - "shows": [ - { - "caption": "Oct 1977", - "slug": "1977-oct", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/glenn-yarbrough-limeliters-1977-oct-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/glenn-yarbrough-limeliters-1977-oct-b.opus" - } - ] - } - ] - }, - { - "id": 12, - "name": "Harry Belafonte", - "slug": "harry-belafonte", - "description": "American singer, actor, and civil rights activist who brought Caribbean\nmusic to mainstream audiences with \"Day-O (The Banana Boat Song)\" and\n\"Jump in the Line.\" His 1956 album Calypso was the first by a solo\nartist to sell a million copies in the United States.", - "images": [], - "shows": [ - { - "caption": "May 1976", - "slug": "1976-may", - "sides": [ - { - "id": "a", - "label": "Act I — Side A", - "audio": "/audio/harry-belafonte-1976-may-a.opus" - }, - { - "id": "b", - "label": "Act I — Side B", - "audio": "/audio/harry-belafonte-1976-may-b.opus" - } - ] - } - ] - }, - { - "id": 13, - "name": "Helen Reddy", - "slug": "helen-reddy", - "description": "Australian-American singer best known for \"I Am Woman,\" an anthem\nthat became a touchstone of second-wave feminism. Other hits include\n\"Delta Dawn\" and \"Angie Baby.\"", - "images": [ - "/images/helen-reddy-1.webp" - ], - "shows": [ - { - "caption": "1974", - "slug": "1974", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/helen-reddy-1974-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/helen-reddy-1974-b.opus" - } - ] - } - ] - }, - { - "id": 14, - "name": "Florence Henderson & Jim Nabors", - "slug": "henderson-nabors", - "description": "Florence Henderson (Carol Brady of The Brady Bunch) shared this bill\nwith Jim Nabors (Gomer Pyle of The Andy Griffith Show). Both had\nconcert-singing careers alongside their television roles and were\nregulars on variety programs.", - "images": [ - "/images/henderson-nabors-1.webp", - "/images/henderson-nabors-2.webp" - ], - "shows": [ - { - "caption": "Jul 1975", - "slug": "1975-jul", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/henderson-nabors-1975-jul-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/henderson-nabors-1975-jul-b.opus" - } - ] - } - ] - }, - { - "id": 15, - "name": "The Hues Corporation & The 5th Dimension", - "slug": "hues-corp-5th-dimension", - "description": "The Hues Corporation, who topped the charts in 1974 with \"Rock the\nBoat,\" shared this bill with The 5th Dimension, the late-1960s\nsunshine-pop group behind \"Up, Up and Away\" and the medley\n\"Aquarius/Let the Sunshine In,\" drawn from the musical Hair.", - "images": [ - "/images/hues-corp-5th-dimension-1.webp" - ], - "shows": [ - { - "caption": "1974", - "slug": "1974", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/hues-corp-5th-dimension-1974-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/hues-corp-5th-dimension-1974-b.opus" - } - ] - } - ] - }, - { - "id": 16, - "name": "John Davidson", - "slug": "john-davidson", - "description": "American singer, actor, and television host with a clean-cut style.\nA frequent variety-show guest in the 1960s and '70s, he later hosted\nThat's Incredible! and Hollywood Squares.", - "images": [ - "/images/john-davidson-1.webp" - ], - "shows": [ - { - "caption": "1974", - "slug": "1974", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/john-davidson-1974-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/john-davidson-1974-b.opus" - } - ] - } - ] - }, - { - "id": 17, - "name": "Johnny Mathis", - "slug": "johnny-mathis", - "description": "American singer whose smooth tenor on songs like \"Chances Are,\"\n\"Misty,\" and \"It's Not for Me to Say\" made him one of the best-selling\nrecording artists of the twentieth century.", - "images": [ - "/images/johnny-mathis-1.webp" - ], - "shows": [ - { - "caption": "Aug 1975 — 1st show", - "slug": "1975-aug-sun-1st", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1975-aug-sun-1st-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/johnny-mathis-1975-aug-sun-1st-b.opus" - } - ] - }, - { - "caption": "Aug 1975 — 2nd show", - "slug": "1975-aug-1st", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1975-aug-1st-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/johnny-mathis-1975-aug-1st-b.opus" - } - ] - }, - { - "caption": "Aug 1975 — 3rd show", - "slug": "1975-aug-2nd-half", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1975-aug-2nd-half-a.opus" - } - ] - }, - { - "caption": "Aug 1975 — 4th show", - "slug": "1975-aug-3rd", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1975-aug-3rd-a.opus" - } - ] - }, - { - "caption": "Aug 1976 — 1st show", - "slug": "1976-aug-1", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1976-aug-1-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/johnny-mathis-1976-aug-1-b.opus" - } - ] - }, - { - "caption": "Aug 1976 — 2nd show", - "slug": "1976-aug-2", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/johnny-mathis-1976-aug-2-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/johnny-mathis-1976-aug-2-b.opus" - } - ] - } - ] - }, - { - "id": 18, - "name": "Kate Smith", - "slug": "kate-smith", - "description": "American singer with a 50-year career and a deep contralto voice,\nfamous for her 1939 recording of Irving Berlin's \"God Bless America.\"\nShe hosted radio and television variety programs through the 1950s\nand '60s.", - "images": [ - "/images/kate-smith-1.webp" - ], - "shows": [ - { - "caption": "Nov 1975", - "slug": "1975-nov", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/kate-smith-1975-nov-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/kate-smith-1975-nov-b.opus" - } - ] - } - ] - }, - { - "id": 19, - "name": "Lainie Kazan", - "slug": "lainie-kazan", - "description": "American singer and actress with a powerful belt and Broadway roots.\nAs Barbra Streisand's understudy in Funny Girl, she famously stepped\nin for one performance in 1964. She later became a fixture in supper\nclubs and film comedies.", - "images": [], - "shows": [ - { - "caption": "Aug 1975 — 1st show", - "slug": "1975-aug-1", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/lainie-kazan-1975-aug-1-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/lainie-kazan-1975-aug-1-b.opus" - } - ] - }, - { - "caption": "Aug 1975 — 2nd show", - "slug": "1975-aug-2", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/lainie-kazan-1975-aug-2-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/lainie-kazan-1975-aug-2-b.opus" - } - ] - } - ] - }, - { - "id": 20, - "name": "The Love Machine", - "slug": "love-machine", - "description": "International all-female funk and soul group active in the 1970s.\nThe seven-member ensemble, which included songwriter Sandra Sully,\ntoured Europe, Asia, and Africa and recorded for labels including\nBuddah, Arista, and Motown.", - "images": [], - "shows": [ - { - "caption": "Oct 1976", - "slug": "1976-oct", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/love-machine-1976-oct-a.opus" - } - ] - } - ] - }, - { - "id": 21, - "name": "Tony Martin & Cyd Charisse", - "slug": "martin-charisse", - "description": "Husband-and-wife stage act. Tony Martin sang and Cyd Charisse danced;\nboth were veterans of Hollywood musicals, and they toured together\nthrough the 1970s.", - "images": [], - "shows": [ - { - "caption": "Aug 1975", - "slug": "1975-aug", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/martin-charisse-1975-aug-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/martin-charisse-1975-aug-b.opus" - } - ] - } - ] - }, - { - "id": 22, - "name": "The Mills Brothers", - "slug": "mills-brothers", - "description": "American close-harmony vocal quartet from Piqua, Ohio, active from\nthe 1920s through the 1980s. Best known for \"Paper Doll\" (1943),\n\"Glow Worm,\" and \"You Always Hurt the One You Love.\"", - "images": [ - "/images/mills-brothers-1.webp" - ], - "shows": [ - { - "caption": "Sep 1975", - "slug": "1975-sep", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/mills-brothers-1975-sep-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/mills-brothers-1975-sep-b.opus" - } - ] - } - ] - }, - { - "id": 23, - "name": "Mitzi Gaynor", - "slug": "mitzi-gaynor", - "description": "American actress, singer, and dancer who starred in the 1958 film of\nSouth Pacific opposite Rossano Brazzi. Her touring revues throughout\nthe 1970s showcased her dance numbers and comic timing.", - "images": [ - "/images/mitzi-gaynor-1.webp" - ], - "shows": [ - { - "caption": "Oct 2, 1977", - "slug": "1977-oct", - "sides": [ - { - "id": "i-a", - "label": "Act I — Side A", - "audio": "/audio/mitzi-gaynor-1977-oct-i-a.opus" - }, - { - "id": "i-b", - "label": "Act I — Side B", - "audio": "/audio/mitzi-gaynor-1977-oct-i-b.opus" - }, - { - "id": "ii-a", - "label": "Act II — Side A", - "audio": "/audio/mitzi-gaynor-1977-oct-ii-a.opus" - } - ] - } - ] - }, - { - "id": 24, - "name": "Robert Goulet", - "slug": "robert-goulet", - "description": "Canadian-American baritone who originated the role of Lancelot in\nLerner and Loewe's Camelot on Broadway in 1960. A long career on\ntelevision, in film, and on the Las Vegas circuit followed.", - "images": [ - "/images/robert-goulet-1.webp" - ], - "shows": [ - { - "caption": "Jun 1975 — with Foster Brooks", - "slug": "1975-jun", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/robert-goulet-1975-jun-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/robert-goulet-1975-jun-b.opus" - } - ] - }, - { - "caption": "Oct 1976", - "slug": "1976-oct", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/robert-goulet-1976-oct-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/robert-goulet-1976-oct-b.opus" - } - ] - } - ] - }, - { - "id": 25, - "name": "Roy Clark", - "slug": "roy-clark", - "description": "American country musician and comedian, longtime co-host of the\nsyndicated television show Hee Haw. A virtuoso multi-instrumentalist\nand a Country Music Hall of Fame inductee.", - "images": [ - "/images/roy-clark-1.webp" - ], - "shows": [ - { - "caption": "Apr 1976", - "slug": "1976-apr", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/roy-clark-1976-apr-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/roy-clark-1976-apr-b.opus" - } - ] - } - ] - }, - { - "id": 26, - "name": "Sammy Davis Jr.", - "slug": "sammy-davis-jr", - "description": "American singer, dancer, actor, and member of the Rat Pack, whose\ncareer spanned more than six decades across Broadway, film, and\ntelevision. His signature hit was \"The Candy Man.\"", - "images": [ - "/images/sammy-davis-jr-1.webp", - "/images/sammy-davis-jr-2.webp" - ], - "shows": [ - { - "caption": "1975", - "slug": "1975", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/sammy-davis-jr-1975-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/sammy-davis-jr-1975-b.opus" - } - ] - }, - { - "caption": "Nov 1976", - "slug": "1976-nov", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/sammy-davis-jr-1976-nov-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/sammy-davis-jr-1976-nov-b.opus" - } - ] - } - ] - }, - { - "id": 27, - "name": "Sandler & Young", - "slug": "sandler-young", - "description": "Singing duo Tony Sandler (Belgian) and Ralph Young (American), known\nfor their multilingual repertoire and tight harmony. A staple of\nsupper-club and television variety bookings from the late 1960s\nonward.", - "images": [ - "/images/sandler-young-1.webp" - ], - "shows": [ - { - "caption": "Dec 1975 — 1st show", - "slug": "1975-dec-mill-run", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/sandler-young-1975-dec-mill-run-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/sandler-young-1975-dec-mill-run-b.opus" - } - ] - }, - { - "caption": "Dec 1975 — 2nd show", - "slug": "1975-dec", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/sandler-young-1975-dec-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/sandler-young-1975-dec-b.opus" - } - ] - } - ] - }, - { - "id": 28, - "name": "Shirley Bassey", - "slug": "shirley-bassey", - "description": "Welsh singer with a powerful contralto, internationally known for the\nthree James Bond film theme songs she recorded: \"Goldfinger\" (1964),\n\"Diamonds Are Forever\" (1971), and \"Moonraker\" (1979).", - "images": [ - "/images/shirley-bassey-1.webp" - ], - "shows": [ - { - "caption": "Sep 1976", - "slug": "1976-sep", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/shirley-bassey-1976-sep-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/shirley-bassey-1976-sep-b.opus" - } - ] - } - ] - }, - { - "id": 29, - "name": "Steve Lawrence & Eydie Gormé", - "slug": "steve-lawrence-eydie-gorme", - "description": "American husband-and-wife singing duo who met as Steve Allen's Tonight\nShow regulars in the 1950s and remained inseparable performers until\nEydie's death in 2013. Each maintained a successful solo career\nalongside the duo work.", - "images": [ - "/images/steve-lawrence-eydie-gorme-1.webp" - ], - "shows": [ - { - "caption": "Aug 1977 — 1st show", - "slug": "1977-aug-1", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/steve-lawrence-eydie-gorme-1977-aug-1-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/steve-lawrence-eydie-gorme-1977-aug-1-b.opus" - } - ] - }, - { - "caption": "Aug 1977 — 2nd show", - "slug": "1977-aug-2", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/steve-lawrence-eydie-gorme-1977-aug-2-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/steve-lawrence-eydie-gorme-1977-aug-2-b.opus" - } - ] - } - ] - }, - { - "id": 30, - "name": "The Dells", - "slug": "the-dells", - "description": "Chicago R&B vocal group whose career stretched from the 1950s\n(\"Oh What a Night\") through the 1990s (\"Stay in My Corner\"). One of\nthe longest-lived doo-wop and soul ensembles.", - "images": [], - "shows": [ - { - "caption": "1975", - "slug": "1975", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/the-dells-1975-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/the-dells-1975-b.opus" - } - ] - } - ] - }, - { - "id": 31, - "name": "The Irish Rovers", - "slug": "irish-rovers", - "description": "Canadian-Irish folk group founded in Toronto in the 1960s, best known\nfor \"The Unicorn\" (1968) and \"Wasn't That a Party\" (1981).", - "images": [], - "shows": [ - { - "caption": "Jul 1977 — 1st show", - "slug": "1977-jul-16", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/irish-rovers-1977-jul-16-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/irish-rovers-1977-jul-16-b.opus" - } - ] - }, - { - "caption": "Jul 1977 — 2nd show", - "slug": "1977-jul-17", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/irish-rovers-1977-jul-17-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/irish-rovers-1977-jul-17-b.opus" - } - ] - } - ] - }, - { - "id": 32, - "name": "The Kingston Trio", - "slug": "kingston-trio", - "description": "American folk group from San Francisco, one of the most popular acts\nof the late 1950s and early '60s and a catalyst for the folk revival.\nHits include \"Tom Dooley\" and \"Where Have All the Flowers Gone.\"", - "images": [], - "shows": [ - { - "caption": "Oct 1977", - "slug": "1977-oct", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/kingston-trio-1977-oct-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/kingston-trio-1977-oct-b.opus" - } - ] - } - ] - }, - { - "id": 33, - "name": "The Temptations & Honey Cone", - "slug": "temptations-honey-cone", - "description": "Motown soul giants The Temptations (\"My Girl,\" \"Just My Imagination\")\nshared this bill with Honey Cone, the trio whose 1971 single\n\"Want Ads\" topped the Billboard Hot 100.", - "images": [ - "/images/temptations-honey-cone-1.webp" - ], - "shows": [ - { - "caption": "Dec 30, 1972", - "slug": "1972-dec", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/temptations-honey-cone-1972-dec-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/temptations-honey-cone-1972-dec-b.opus" - } - ] - } - ] - }, - { - "id": 34, - "name": "Tom Jones", - "slug": "tom-jones", - "description": "Welsh singer with a powerhouse baritone who broke through with \"It's\nNot Unusual\" in 1965 and went on to build a decades-long Las Vegas\nresidency career. His variety show This Is Tom Jones aired from 1969\nto 1971.", - "images": [ - "/images/tom-jones-1.webp", - "/images/tom-jones-2.webp" - ], - "shows": [ - { - "caption": "1975", - "slug": "1975", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/tom-jones-1975-a.opus" - } - ] - }, - { - "caption": "Sep 1976", - "slug": "1976-sep", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/tom-jones-1976-sep-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/tom-jones-1976-sep-b.opus" - } - ] - } - ] - }, - { - "id": 35, - "name": "Vic Damone", - "slug": "vic-damone", - "description": "American singer whose smooth baritone made him a fixture on television\nvariety shows and a Las Vegas mainstay. Hits include \"You're Breaking\nMy Heart\" and \"On the Street Where You Live.\"", - "images": [ - "/images/vic-damone-1.webp" - ], - "shows": [ - { - "caption": "Dec 1974", - "slug": "1974-dec", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/vic-damone-1974-dec-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/vic-damone-1974-dec-b.opus" - } - ] - } - ] - }, - { - "id": 36, - "name": "Vikki Carr", - "slug": "vikki-carr", - "description": "American singer of Mexican-American heritage who scored a pop hit with\n\"It Must Be Him\" in 1967 before pivoting to a Spanish-language career\nthat earned her multiple Grammy and Latin Grammy awards.", - "images": [ - "/images/vikki-carr-1.webp", - "/images/vikki-carr-2.webp" - ], - "shows": [ - { - "caption": "1975", - "slug": "1975", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/vikki-carr-1975-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/vikki-carr-1975-b.opus" - } - ] - }, - { - "caption": "May 1975", - "slug": "1975-may", - "sides": [ - { - "id": "a", - "label": "Side A", - "audio": "/audio/vikki-carr-1975-may-a.opus" - }, - { - "id": "b", - "label": "Side B", - "audio": "/audio/vikki-carr-1975-may-b.opus" - } - ] - } - ] - } - ] -} diff --git a/web/src/lib/artists.ts b/web/src/lib/artists.ts deleted file mode 100644 index 542c677..0000000 --- a/web/src/lib/artists.ts +++ /dev/null @@ -1,35 +0,0 @@ -import data from './artists.json'; - -export type Side = { - id: string; - label: string; - audio: string; -}; - -export type Show = { - caption: string; - slug: string; - sides: Side[]; -}; - -export type Artist = { - id: number; - name: string; - slug: string; - description: string; - images: string[]; - shows: Show[]; -}; - -export type Exhibit = { - title: string; - description?: string; - subtitle?: string; -}; - -export const exhibit: Exhibit = data.exhibit; -export const artists: Artist[] = data.artists; - -export function artistById(id: number): Artist | undefined { - return artists.find((a) => a.id === id); -} diff --git a/web/src/lib/auth.svelte.ts b/web/src/lib/auth.svelte.ts index bbe8a62..b1fc11f 100644 --- a/web/src/lib/auth.svelte.ts +++ b/web/src/lib/auth.svelte.ts @@ -38,8 +38,35 @@ export async function login(password: string): Promise { return false; } +export async function loginWithKey(key: string): Promise { + const res = await fetch('/api/key', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ key }), + credentials: 'same-origin' + }); + if (res.ok) { + state = 'signed-in'; + return true; + } + return false; +} + export async function logout() { await fetch('/api/logout', { method: 'POST', credentials: 'same-origin' }); state = 'signed-out'; goto('/login'); } + +export type KeyResult = 'success' | 'failed' | 'absent'; + +export async function consumeKeyParam(): Promise { + if (!browser) return 'absent'; + const url = new URL(window.location.href); + const key = url.searchParams.get('key'); + if (!key) return 'absent'; + url.searchParams.delete('key'); + window.history.replaceState({}, '', url.toString()); + const ok = await loginWithKey(key); + return ok ? 'success' : 'failed'; +} diff --git a/web/src/lib/fonts.svelte.ts b/web/src/lib/fonts.svelte.ts deleted file mode 100644 index 5924d40..0000000 --- a/web/src/lib/fonts.svelte.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { browser } from '$app/environment'; - -// Becomes true once all custom fonts have loaded. Components that contain -// SVG paths whose geometry depends on element size (e.g. the marquee bulb -// ring) can key off this so they remount after the font swap finishes -// resizing the panel. -let ready = $state(false); - -if (browser) { - if ('fonts' in document && typeof document.fonts.ready?.then === 'function') { - document.fonts.ready.then(() => { - ready = true; - }); - } else { - ready = true; - } -} - -export function fontsReady(): boolean { - return ready; -} diff --git a/web/src/lib/precache.svelte.ts b/web/src/lib/precache.svelte.ts index 762ce12..22c281c 100644 --- a/web/src/lib/precache.svelte.ts +++ b/web/src/lib/precache.svelte.ts @@ -1,20 +1,16 @@ import { browser } from '$app/environment'; -import { artists } from './artists'; +import { stops } from './stops'; export type PrecacheState = 'idle' | 'running' | 'complete' | 'unsupported'; let state: PrecacheState = $state('idle'); let done = $state(0); let total = $state(0); -let failed = $state(0); export function precacheState() { - return { state, done, total, failed }; + return { state, done, total }; } -// Precache every image and every audio side. ~1.6 GB at current Opus -// bitrate. Designed for the museum's single-kiosk tablet on a flaky wifi: -// staff hit the page once at setup; visitors thereafter hit cache only. export async function precacheAll(): Promise { if (!browser) return; if (!('serviceWorker' in navigator)) { @@ -30,15 +26,7 @@ export async function precacheAll(): Promise { return; } - const urls = artists.flatMap((a) => [ - ...a.images, - ...a.shows.flatMap((s) => s.sides.map((side) => side.audio)) - ]); - - if (urls.length === 0) { - state = 'complete'; - return; - } + const urls = stops.flatMap((s) => [s.audio, s.image]); state = 'running'; done = 0; @@ -50,16 +38,14 @@ export async function precacheAll(): Promise { if (data.type === 'precache-progress') { done = data.done; total = data.total; - failed = data.failed ?? 0; } else if (data.type === 'precache-done') { done = data.done; total = data.total; - failed = data.failed ?? 0; state = 'complete'; navigator.serviceWorker.removeEventListener('message', onMessage); } }; navigator.serviceWorker.addEventListener('message', onMessage); - target.postMessage({ type: 'precache-artists', urls }); + target.postMessage({ type: 'precache-stops', urls }); } diff --git a/web/src/lib/stops.json b/web/src/lib/stops.json new file mode 100644 index 0000000..f1d313b --- /dev/null +++ b/web/src/lib/stops.json @@ -0,0 +1,24 @@ +{ + "exhibit": { + "title": "Mill Run", + "subtitle": "" + }, + "stops": [ + { + "id": 1, + "title": "Welcome", + "audio": "/audio/01.opus", + "image": "/images/01.webp", + "caption": "An introduction to the exhibit.", + "description": "Placeholder description." + }, + { + "id": 2, + "title": "Stop two placeholder", + "audio": "/audio/02.opus", + "image": "/images/02.webp", + "caption": "", + "description": "" + } + ] +} diff --git a/web/src/lib/stops.ts b/web/src/lib/stops.ts new file mode 100644 index 0000000..99b9914 --- /dev/null +++ b/web/src/lib/stops.ts @@ -0,0 +1,22 @@ +import stopsJson from './stops.json'; + +export type Stop = { + id: number; + title: string; + audio: string; + image: string; + caption?: string; + description?: string; +}; + +export type Exhibit = { + title: string; + subtitle: string; +}; + +export const exhibit: Exhibit = stopsJson.exhibit; +export const stops: Stop[] = stopsJson.stops; + +export function stopById(id: number): Stop | undefined { + return stops.find((s) => s.id === id); +} diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte index 5a231a7..14b740b 100644 --- a/web/src/routes/+layout.svelte +++ b/web/src/routes/+layout.svelte @@ -4,7 +4,7 @@ import { page } from '$app/stores'; import { goto } from '$app/navigation'; import { dev } from '$app/environment'; - import { authState, checkAuth } from '$lib/auth.svelte'; + import { authState, checkAuth, consumeKeyParam } from '$lib/auth.svelte'; import { precacheAll } from '$lib/precache.svelte'; let { children } = $props(); @@ -24,14 +24,18 @@ } } - await checkAuth(); + const keyResult = await consumeKeyParam(); + if (keyResult !== 'success') await checkAuth(); const path = $page.url.pathname; if (authState() === 'signed-out' && path !== '/login') { const params = new URLSearchParams({ next: path }); + if (keyResult === 'failed') params.set('error', 'qr'); await goto('/login?' + params.toString(), { replaceState: true }); } + // Production-only: kick off audio/image bulk precache once authenticated. + // SW does the work; failures non-fatal. if (!dev && authState() === 'signed-in') { precacheAll().catch(() => undefined); } @@ -59,7 +63,7 @@ height: 32px; border-radius: 50%; border: 2px solid var(--rule); - border-top-color: var(--title); + border-top-color: var(--accent); animation: spin 0.8s linear infinite; } @keyframes spin { diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index 4363844..ea6ac8b 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -1,118 +1,63 @@
-
- {#key fontsReady()} - - {/key} -

{exhibit.title}

- {#if exhibit.description} - {#each exhibit.description.split('\n').filter(Boolean) as line} -

{line}

- {/each} - {/if} -
+

{exhibit.title}

+ {#if exhibit.subtitle} +

{exhibit.subtitle}

+ {/if}
-{#if pre.state === 'running' || (pre.state === 'complete' && pre.failed > 0)} +{#if pre.state === 'running'}
- {#if pre.state === 'running'} - - - Caching exhibit for offline listening… {pre.done} / {pre.total} - {#if pre.failed > 0}({pre.failed} retrying){/if} - - - {:else} - - {pre.total - pre.failed} of {pre.total} files cached. {pre.failed} - failed to download — they will stream over the network when played. - - {/if} + + + Loading exhibit for offline listening… {pre.done}/{pre.total} +
{/if} -
- {#each artists as artist (artist.id)} - {@const cover = artist.images[0]} - +
+ {#each stops as stop (stop.id)} +
- {#if cover} - - {:else} - - {/if} +
- {artist.name} - {artistYears(artist)} + {String(stop.id).padStart(2, '0')} + {stop.title}
{/each}
- diff --git a/web/src/routes/artist/[id]/+page.svelte b/web/src/routes/artist/[id]/+page.svelte deleted file mode 100644 index 23fb1d8..0000000 --- a/web/src/routes/artist/[id]/+page.svelte +++ /dev/null @@ -1,312 +0,0 @@ - - -{#if !artist} -
-

Artist not found.

- Back to all artists -
-{:else} -
- - - Back to All Artists - -
- -
-
- {#key `${artist.id}-${fontsReady()}`} - - {/key} -

{artist.name}

-
- - {#if artist.images.length > 0 || artist.description} -
- {#if artist.images.length > 0} -
- {#each artist.images as src, i (src)} -
- -
- {/each} -
- {/if} - - {#if artist.description} -
- {#each artist.description.split(/\n\n+/) as para} -

{para}

- {/each} -
- {/if} -
- {/if} - - - -
- {#each artist.shows as show, showIdx (show.slug)} -
-

{show.caption}

-
- {#each show.sides as side, sideIdx (side.id)} - - {/each} -
-
- {/each} -
- -

- Digitized from analog tapes in the Niles Historical Society archive. -

-
- - -{/if} - - diff --git a/web/src/routes/artist/[id]/SidePlayer.svelte b/web/src/routes/artist/[id]/SidePlayer.svelte deleted file mode 100644 index 45c5414..0000000 --- a/web/src/routes/artist/[id]/SidePlayer.svelte +++ /dev/null @@ -1,253 +0,0 @@ - - -
- - -
- {label} - - {fmt(currentTime)} / {fmt(duration)} -
- - -
- - diff --git a/web/src/routes/login/+page.svelte b/web/src/routes/login/+page.svelte index 969208b..e4e5da1 100644 --- a/web/src/routes/login/+page.svelte +++ b/web/src/routes/login/+page.svelte @@ -1,12 +1,15 @@ + +{#if !stop} +
+

Stop not found.

+ Back to all stops +
+{:else} +
+ + + + {String(stop.id).padStart(2, '0')} +
+ +
+ + {#if volumeWritable} +
+ + +
+ {/if} + + + +

{stop.title}

+ {#if stop.caption} +

{stop.caption}

+ {/if} + + {#if stop.description} +
+ {#each stop.description.split(/\n\n+/) as para} +

{para}

+ {/each} +
+ {/if} +
+ + +{/if} + + diff --git a/web/src/service-worker.ts b/web/src/service-worker.ts index 87ba42c..97aeda5 100644 --- a/web/src/service-worker.ts +++ b/web/src/service-worker.ts @@ -14,7 +14,7 @@ // /audio /img → stale-while-revalidate from ASSET_CACHE // everything → cache-first from SHELL_CACHE // - Messages: -// { type: 'precache-artists', urls: string[] } +// { type: 'precache-stops', urls: string[] } // Bulk-cache a list of URLs into ASSET_CACHE, posting progress back to // the sender via { type: 'precache-progress', done, total } and a final // { type: 'precache-done' } when finished. @@ -72,6 +72,7 @@ sw.addEventListener('fetch', (event) => { event.respondWith( (async () => { + // Navigation: prefer cached shell; fall back to network. if (request.mode === 'navigate') { const shell = await caches.open(SHELL_CACHE); const cached = (await shell.match('/')) || (await shell.match('/index.html')); @@ -88,6 +89,7 @@ sw.addEventListener('fetch', (event) => { const cached = await cache.match(request); if (cached) { if (isContent) { + // Stale-while-revalidate: return cached, refresh in background. event.waitUntil(refresh(cache, request)); } return cached; @@ -117,79 +119,40 @@ async function refresh(cache: Cache, request: Request) { sw.addEventListener('message', (event) => { const data = event.data; - if (data?.type !== 'precache-artists' || !Array.isArray(data.urls)) return; + if (data?.type !== 'precache-stops' || !Array.isArray(data.urls)) return; const urls: string[] = data.urls; const source = event.source; - event.waitUntil(precacheArtists(urls, source)); + event.waitUntil(precacheStops(urls, source)); }); -async function precacheArtists(urls: string[], source: Client | ServiceWorker | MessagePort | null) { +async function precacheStops(urls: string[], source: Client | ServiceWorker | MessagePort | null) { const cache = await caches.open(ASSET_CACHE); - const total = urls.length; let done = 0; - let failed = 0; - - const queue = urls.slice(); - const CONCURRENCY = 3; - const MAX_ATTEMPTS = 3; - const BACKOFF_MS = 800; - - function postProgress() { + const total = urls.length; + for (const url of urls) { + try { + const cached = await cache.match(url); + if (!cached) { + const res = await fetch(url, { credentials: 'same-origin' }); + if (res.ok && res.type === 'basic') await cache.put(url, res); + } + } catch { + // Network error — skip and continue. UI shows the count. + } + done++; try { (source as Client | null)?.postMessage?.({ type: 'precache-progress', done, - total, - failed + total }); - } catch {} - } - - async function fetchWithRetry(url: string): Promise { - for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) { - try { - const res = await fetch(url, { credentials: 'same-origin', cache: 'no-store' }); - if (res.ok && res.type === 'basic') { - await cache.put(url, res); - return true; - } - if (res.status >= 400 && res.status < 500) return false; // permanent - } catch {} - if (attempt < MAX_ATTEMPTS) { - await new Promise((r) => setTimeout(r, BACKOFF_MS * attempt)); - } - } - return false; - } - - async function worker() { - while (queue.length > 0) { - const url = queue.shift(); - if (!url) break; - try { - const cached = await cache.match(url); - if (!cached) { - const ok = await fetchWithRetry(url); - if (!ok) failed++; - } - } catch { - failed++; - } - done++; - postProgress(); + } catch { + // Sender went away. } } - - await Promise.all(Array.from({ length: CONCURRENCY }, worker)); - try { - (source as Client | null)?.postMessage?.({ - type: 'precache-done', - done, - total, - failed - }); + (source as Client | null)?.postMessage?.({ type: 'precache-done', done, total }); } catch { // Sender went away. } diff --git a/web/static/manifest.webmanifest b/web/static/manifest.webmanifest index c9b5c4e..58597e9 100644 --- a/web/static/manifest.webmanifest +++ b/web/static/manifest.webmanifest @@ -1,5 +1,5 @@ { - "name": "Mill Run Theatre", + "name": "Mill Run", "short_name": "Mill Run", "description": "Audio-guided exhibit", "start_url": "/", diff --git a/web/svelte.config.js b/web/svelte.config.js index 939b0eb..05357a3 100644 --- a/web/svelte.config.js +++ b/web/svelte.config.js @@ -14,25 +14,6 @@ export default { serviceWorker: { register: false }, - csp: { - mode: 'hash', - directives: { - 'default-src': ['self'], - 'script-src': ['self'], - 'style-src': ['self', 'unsafe-inline'], - 'img-src': ['self', 'data:', 'blob:'], - 'media-src': ['self', 'blob:'], - 'font-src': ['self', 'data:'], - 'connect-src': ['self'], - 'manifest-src': ['self'], - 'worker-src': ['self'], - 'object-src': ['none'], - 'base-uri': ['self'], - 'frame-ancestors': ['none'], - 'form-action': ['self'], - 'upgrade-insecure-requests': true - } - }, alias: { $content: './src/lib/content' }