[object Object]

← back to Scarlet Riverboat Masquerade

Riverboat room: searchable full Grateful Dead archive — type anything (date/city/venue/song) to search the entire archive.org GratefulDead collection and play any show; curated 5 kept as quick picks; venue marquee shows searched venues

88dc7e079d338dead3914057be01b7f4d0da08f9 · 2026-09-01 22:53:53 -0700 · Steve Abrams

Files touched

Diff

commit 88dc7e079d338dead3914057be01b7f4d0da08f9
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Sep 1 22:53:53 2026 -0700

    Riverboat room: searchable full Grateful Dead archive — type anything (date/city/venue/song) to search the entire archive.org GratefulDead collection and play any show; curated 5 kept as quick picks; venue marquee shows searched venues
---
 index.html | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 56 insertions(+), 9 deletions(-)

diff --git a/index.html b/index.html
index 986ee3e..6480a9a 100644
--- a/index.html
+++ b/index.html
@@ -150,6 +150,16 @@
   .musicroom[data-open="false"] .chev{transform:rotate(-90deg)}
   .musicroom[data-open="false"] .mrbody{display:none}
   .mrbody{padding:0 14px 14px}
+  .mr-search{width:100%;background:rgba(40,12,16,.8);color:var(--ink);border:1px solid var(--panel-edge);border-radius:9px;padding:8px 10px;font-size:12px;margin-bottom:8px}
+  .mr-search::placeholder{color:var(--ink-dim)}
+  .mr-results{max-height:150px;overflow:auto;margin-bottom:8px;display:flex;flex-direction:column;gap:2px}
+  .mr-results:empty{display:none}
+  .mr-result{display:flex;gap:9px;align-items:baseline;width:100%;text-align:left;background:none;border:0;color:var(--ink-dim);font-family:var(--sans);font-size:11.5px;padding:5px 6px;cursor:pointer;border-radius:6px}
+  .mr-result:hover{color:var(--ink);background:rgba(70,20,26,.6)}
+  .mr-result .rd{color:var(--gold);font-variant-numeric:tabular-nums;min-width:74px;flex:none}
+  .mr-result .rv{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
+  .mr-hint{color:var(--ink-dim);font-size:11px;padding:5px 4px;font-style:italic}
+  .mr-picks{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-dim);margin:2px 0 5px}
   .mr-show{width:100%;background:rgba(40,12,16,.7);color:var(--ink);border:1px solid var(--panel-edge);
     border-radius:9px;padding:8px 10px;font-family:var(--serif);font-size:12.5px;cursor:pointer}
   .mr-now{margin:12px 0 3px;color:var(--ink);font-family:var(--serif);font-style:italic;font-size:13px;min-height:18px;
@@ -229,6 +239,9 @@
       <span class="chev" aria-hidden="true">▾</span>
     </header>
     <div class="mrbody" id="mrbody">
+      <input class="mr-search" id="mrSearch" type="search" placeholder="🔍 Search the whole Dead archive — date, city, song…" aria-label="Search the Grateful Dead archive">
+      <div class="mr-results" id="mrResults" role="list"></div>
+      <div class="mr-picks">Curated nights:</div>
       <select class="mr-show" id="mrShow" aria-label="Choose a recording from the Live Music Archive"></select>
       <div class="mr-now" id="mrNow">Choose a night, then press play.</div>
       <div class="mr-sub" id="mrSub"></div>
@@ -494,8 +507,11 @@ function drawSongMotifs(dt){
 function drawVenue(){
   if(!venueOn) return;
   const W=S.W,H=S.H;
-  const idx=clamp((window.SRM&&window.SRM.showIdx!=null)?window.SRM.showIdx:3,0,VENUES.length-1);
-  const V=VENUES[idx];
+  const si=(window.SRM&&window.SRM.showIdx);
+  let vName, vLights;
+  if(si!=null && si>=0 && si<VENUES.length){ vName=VENUES[si].name; vLights=VENUES[si].lights; }
+  else { vName=(window.SRM&&window.SRM.venueLabel)||''; vLights=['#ffcf6e','#ff7a4a','#a8c8ff','#c9a2ff']; }  // searched show
+  const V={name:vName, lights:vLights};
   // stage-light beams fanning down from the rig, gently sweeping, brightening on the beat
   ctx.save(); ctx.globalCompositeOperation='lighter';
   for(let i=0;i<4;i++){
@@ -1441,16 +1457,15 @@ function setFoot(s){
     `a community recording from the Grateful Dead Live Music Archive, streamed from the Internet Archive. Listen-only; nothing is copied or re-hosted here.`;
 }
 
-async function loadShow(i, opts){
+// Load ANY Grateful Dead archive.org item (curated pick OR a search result)
+async function loadShowRef(s, opts){
   opts=opts||{};
   const myToken=++loadToken;               // guard against a stale fetch overwriting a newer selection
   try{ audio.pause(); }catch(e){}          // stop the current night before loading the next
-  showIdx=i; tracks=[]; trackIdx=-1;
-  if(window.SRM) window.SRM.showIdx=i;     // tell the visuals which venue to render
-  const s=CATALOG[i];
-  sel.value=String(i);
+  tracks=[]; trackIdx=-1;
+  if(window.SRM){ window.SRM.showIdx=(s.venueIdx!=null?s.venueIdx:null); window.SRM.venueLabel=s.venue||[s.title,s.date].filter(Boolean).join(' · '); }
   $('mrNow').textContent=`${s.title} — loading set list…`;
-  $('mrSub').textContent=`${s.date} · ${s.sub}`;
+  $('mrSub').textContent=[s.date,s.sub].filter(Boolean).join(' · ');
   $('mrTracks').innerHTML=''; $('mrMsg').hidden=true; $('mrMsg').innerHTML='';
   setFoot(s);
   try{
@@ -1472,13 +1487,38 @@ async function loadShow(i, opts){
     $('mrNow').textContent=`♪ ${tracks[0].title}`;
     highlight();
     $('mrDur').textContent='0:00'; $('mrCur').textContent='0:00'; $('mrSeek').value='0';
-    announce(`Loaded ${s.title}, ${s.date}. ${tracks.length} tracks from the Live Music Archive.`);
+    announce(`Loaded ${s.title}. ${tracks.length} tracks from the Live Music Archive.`);
     if(opts.play) playTrack(0);
   }catch(e){
     if(myToken!==loadToken) return;         // superseded — let the newer selection own the UI
     fallbackEmbed(s);
   }
 }
+async function loadShow(i, opts){ if(sel) sel.value=String(i); return loadShowRef(Object.assign({venueIdx:i}, CATALOG[i]), opts); }
+
+// Search the WHOLE Grateful Dead collection on archive.org — type anything (date, venue, city, song)
+let searchTimer=null;
+async function searchArchive(q){
+  const res=$('mrResults'); if(!res) return;
+  q=(q||'').trim();
+  if(!q){ res.innerHTML=''; return; }
+  res.innerHTML='<div class="mr-hint">Searching the archive…</div>';
+  try{
+    const url='https://archive.org/advancedsearch.php?q='+encodeURIComponent('collection:GratefulDead AND ('+q+')')+
+      '&fl[]=identifier&fl[]=title&fl[]=date&fl[]=venue&fl[]=coverage&sort[]=downloads+desc&rows=25&output=json';
+    const r=await fetch(url,{mode:'cors'}); const j=await r.json();
+    const docs=(j.response&&j.response.docs)||[];
+    if(!docs.length){ res.innerHTML='<div class="mr-hint">No shows found. Try a date (1977-05-08), a city, or a song.</div>'; return; }
+    res.innerHTML='';
+    docs.forEach(d=>{
+      const date=(d.date||'').slice(0,10), place=d.venue||d.coverage||d.title||d.identifier;
+      const b=document.createElement('button'); b.type='button'; b.className='mr-result'; b.setAttribute('role','listitem');
+      b.innerHTML=`<span class="rd">${date||'—'}</span><span class="rv">${place}</span>`;
+      b.addEventListener('click',()=>loadShowRef({id:d.identifier, date:date, title:d.venue||d.title||'Grateful Dead', sub:d.coverage||''}, {play:true}));
+      res.appendChild(b);
+    });
+  }catch(e){ res.innerHTML='<div class="mr-hint">Search is unavailable right now (open over http, not file://).</div>'; }
+}
 
 function fallbackEmbed(s){
   $('mrNow').textContent=s.title;
@@ -1596,6 +1636,13 @@ seek.addEventListener('change',()=>{ const d=audio.duration||0; if(d>0) audio.cu
 
 sel.addEventListener('change',()=>loadShow(+sel.value,{play:true}));
 
+// archive search wiring — type anything, debounced; Enter searches immediately
+const searchEl=$('mrSearch');
+if(searchEl){
+  searchEl.addEventListener('input',()=>{ clearTimeout(searchTimer); searchTimer=setTimeout(()=>searchArchive(searchEl.value),450); });
+  searchEl.addEventListener('keydown',e=>{ if(e.key==='Enter'){ e.preventDefault(); clearTimeout(searchTimer); searchArchive(searchEl.value); } });
+}
+
 $('mrTracksToggle').addEventListener('click',()=>{
   const on=room.classList.toggle('show-tracks');
   $('mrTracksToggle').setAttribute('aria-expanded',String(on));

← 546a5e7 Replace emoji motifs with original DRAWN animated song-items  ·  back to Scarlet Riverboat Masquerade  ·  Add 3D Three.js orb floating over the riverboat — beat-react 4adfed7 →