← back to Dead Agentabrams
Sync ROOM 01: searchable full Grateful Dead archive
9461cadbfceb8dfde340f3a586e75c57286f9836 · 2026-09-01 22:53:53 -0700 · Steve Abrams
Files touched
Diff
commit 9461cadbfceb8dfde340f3a586e75c57286f9836
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Sep 1 22:53:53 2026 -0700
Sync ROOM 01: searchable full Grateful Dead archive
---
room/index.html | 65 +++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 56 insertions(+), 9 deletions(-)
diff --git a/room/index.html b/room/index.html
index 986ee3e..6480a9a 100644
--- a/room/index.html
+++ b/room/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));
← 5b3f52d Sync ROOM 01: drawn animated song-motif items
·
back to Dead Agentabrams
·
Sync ROOM 01: 3D beat-reactive orb over the riverboat 5b06f4e →