// === Marquee scroll for overflowing text === (function(){ var styleEl=document.createElement("style"); styleEl.textContent="@keyframes gpMarquee{0%,10%{transform:translateX(0);opacity:1}45%{transform:translateX(var(--gp-scroll-dist));opacity:1}55%{transform:translateX(var(--gp-scroll-dist));opacity:1}63%{transform:translateX(var(--gp-scroll-dist));opacity:0}64%{transform:translateX(0);opacity:0}82%{transform:translateX(0);opacity:0}90%{transform:translateX(0);opacity:1}100%{transform:translateX(0);opacity:1}}@keyframes gpMarquee2{0%,15%{transform:translateX(0);opacity:1}35%{transform:translateX(var(--gp-scroll-dist));opacity:1}42%{transform:translateX(var(--gp-scroll-dist));opacity:1}50%{transform:translateX(var(--gp-scroll-dist));opacity:0}51%{transform:translateX(0);opacity:0}80%{transform:translateX(0);opacity:0}90%{transform:translateX(0);opacity:1}100%{transform:translateX(0);opacity:1}}"; document.head.appendChild(styleEl); })(); function gpApplyMarquee(){return;} var gpMarqueeTimer=null; function gpStartMarquee(){ if(gpMarqueeTimer){clearTimeout(gpMarqueeTimer);gpMarqueeTimer=null;} var l1=document.getElementById("gp-line1"); var l2=document.getElementById("gp-line2"); if(!l1&&!l2)return; if(l1)l1.style.animation="none"; if(l2)l2.style.animation="none"; var isMobile=(window.innerWidth<600); if(isMobile){ var tmr=document.getElementById("gp-timer");if(tmr)tmr.style.display="none"; if(l1){l1.style.transition="none";l1.style.opacity="1";l1.style.transform="translateX(0)";} if(l2){l2.style.transition="none";l2.style.opacity="0";l2.style.transform="translateX(0)";} function getOv(el){if(!el||!el.parentNode)return 0;return Math.max(0,el.offsetWidth-el.parentNode.offsetWidth+120);} function getComposerOv(el){ if(!el||!el.parentNode)return 0; var txt=el.textContent||""; var idx=txt.indexOf(" composed by "); if(idx<0)return getOv(el); var rawOv=el.offsetWidth-el.parentNode.offsetWidth; if(rawOv<=0)return 0; var prefix=txt.substring(0,idx+8); var span=document.createElement("span"); span.style.cssText=window.getComputedStyle(el).cssText; span.style.position="absolute";span.style.visibility="hidden";span.style.width="max-content"; span.textContent=prefix; document.body.appendChild(span); var prefixW=span.offsetWidth; document.body.removeChild(span); return prefixW; } function gpShow(el,cb){ if(!el){if(cb)cb();return;} el.style.transition="none"; el.style.transform="translateX(0)"; void el.offsetWidth; el.style.transition="opacity 1200ms ease"; el.style.opacity="1"; gpMarqueeTimer=setTimeout(cb,1250); } function gpHide(el,cb){ if(!el){if(cb)cb();return;} el.style.transition="opacity 1200ms ease"; el.style.opacity="0"; gpMarqueeTimer=setTimeout(function(){ el.style.transition="none"; el.style.transform="translateX(0)"; if(cb)cb(); },1250); } function gpScroll(el,cb){ if(!el){if(cb)cb();return;} var ov=(el.id==="gp-line2")?getComposerOv(el):getOv(el); if(ov<=0){gpMarqueeTimer=setTimeout(cb,2500);return;} var dist=-ov; var ms=Math.abs(dist)/60*1000; gpMarqueeTimer=setTimeout(function(){ el.style.transition="transform "+ms+"ms linear"; el.style.transform="translateX("+dist+"px)"; gpMarqueeTimer=setTimeout(function(){ gpMarqueeTimer=setTimeout(cb,1500); },ms); },1000); } function cycle(){ var cl1=document.getElementById("gp-line1"); var cl2=document.getElementById("gp-line2"); if(!cl1&&!cl2)return; gpScroll(cl1,function(){ gpHide(cl1,function(){ gpMarqueeTimer=setTimeout(function(){ gpShow(cl2,function(){ gpScroll(cl2,function(){ gpHide(cl2,function(){ gpMarqueeTimer=setTimeout(function(){ gpShow(cl1,function(){ gpMarqueeTimer=setTimeout(cycle,300); }); },800); }); }); }); },800); }); }); } setTimeout(function(){requestAnimationFrame(cycle);},400); } else { if(l1){l1.style.opacity="1";l1.style.transform="translateX(0)";} if(l2){l2.style.opacity="1";l2.style.transform="translateX(0)";} function dGetOv(el){if(!el||!el.parentNode)return 0;return Math.max(0,el.offsetWidth-el.parentNode.offsetWidth+120);} function dGetComposerOv(el){ if(!el||!el.parentNode)return 0; var txt=el.textContent||""; var idx=txt.indexOf(" composed by "); if(idx<0)return dGetOv(el); var rawOv=el.offsetWidth-el.parentNode.offsetWidth; if(rawOv<=0)return 0; var prefix=txt.substring(0,idx+8); var span=document.createElement("span"); span.style.cssText=window.getComputedStyle(el).cssText; span.style.position="absolute";span.style.visibility="hidden";span.style.width="max-content"; span.textContent=prefix; document.body.appendChild(span); var prefixW=span.offsetWidth; document.body.removeChild(span); return prefixW; } var _dt1=null,_dt2=null; function dScroll(el,isL2){ if(!el)return; var ov=isL2?dGetComposerOv(el):dGetOv(el); if(ov<=0)return; var dist=-ov; var ms=Math.abs(dist)/60*1000; function dLoop(){ el.style.transition="none"; el.style.transform="translateX(0)"; void el.offsetWidth; var t1=setTimeout(function(){ el.style.transition="transform "+ms+"ms linear"; el.style.transform="translateX("+dist+"px)"; var t2=setTimeout(function(){ var t3=setTimeout(dLoop,2000); if(isL2){_dt2=t3;}else{_dt1=t3;} },ms); if(isL2){_dt2=t2;}else{_dt1=t2;} },1500); if(isL2){_dt2=t1;}else{_dt1=t1;} } dLoop(); } setTimeout(function(){dScroll(l1,false);dScroll(l2,true);},400); } } function gpAutoColor(img){var tile=img.closest(".gtile");if(!tile)return;try{var cv=document.createElement("canvas");cv.width=50;cv.height=50;var ctx=cv.getContext("2d");ctx.drawImage(img,0,0,50,50);var d=ctx.getImageData(0,0,50,50).data;var buckets={};var best="";var bestCount=0;for(var i=0;i230)continue;if(l<25)continue;var diff=mx-mn;if(diff<30){if(l>170)continue;if(l<60)continue;}var kr=Math.round(r/32)*32;var kg=Math.round(g/32)*32;var kb=Math.round(b/32)*32;var key=kr+","+kg+","+kb;if(!buckets[key])buckets[key]={r:0,g:0,b:0,n:0};buckets[key].r+=r;buckets[key].g+=g;buckets[key].b+=b;buckets[key].n++;if(buckets[key].n>bestCount){bestCount=buckets[key].n;best=key;}}if(bestCount<10)return;var bc=buckets[best];var fr=Math.round(bc.r/bc.n);var fg=Math.round(bc.g/bc.n);var fb=Math.round(bc.b/bc.n);var lum=0.299*fr+0.587*fg+0.114*fb;var cMax=Math.max(fr,fg,fb);var cMin=Math.min(fr,fg,fb);var sat=cMax>0?(cMax-cMin)/cMax:0;if(lum<40)return;if(lum>210)return;if(sat<0.15){if(lum>70){return}}if(lum>200){var f=200/lum;fr=Math.round(fr*f);fg=Math.round(fg*f);fb=Math.round(fb*f);}var hex="#"+((1<<24)+(fr<<16)+(fg<<8)+fb).toString(16).slice(1);tile.setAttribute("data-color",hex);tile.style.borderColor=hex;var pb=tile.querySelector(".gp-tile-play");if(pb)pb.style.background=hex;}catch(e){}} function gpAutoColor(img){var tile=img.closest(".gtile");if(!tile)return;try{var cv=document.createElement("canvas");cv.width=50;cv.height=50;var ctx=cv.getContext("2d");ctx.drawImage(img,0,0,50,50);var d=ctx.getImageData(0,0,50,50).data;var buckets={};var best="";var bestCount=0;for(var i=0;i230)continue;if(l<25)continue;var diff=mx-mn;if(diff<30){if(l>170)continue;if(l<60)continue;}var kr=Math.round(r/32)*32;var kg=Math.round(g/32)*32;var kb=Math.round(b/32)*32;var key=kr+","+kg+","+kb;if(!buckets[key])buckets[key]={r:0,g:0,b:0,n:0};buckets[key].r+=r;buckets[key].g+=g;buckets[key].b+=b;buckets[key].n++;if(buckets[key].n>bestCount){bestCount=buckets[key].n;best=key;}}if(bestCount<10)return;var bc=buckets[best];var fr=Math.round(bc.r/bc.n);var fg=Math.round(bc.g/bc.n);var fb=Math.round(bc.b/bc.n);var lum=0.299*fr+0.587*fg+0.114*fb;var cMax=Math.max(fr,fg,fb);var cMin=Math.min(fr,fg,fb);var sat=cMax>0?(cMax-cMin)/cMax:0;if(lum<40)return;if(lum>210)return;if(sat<0.15){if(lum>70){return}}if(lum>200){var f=200/lum;fr=Math.round(fr*f);fg=Math.round(fg*f);fb=Math.round(fb*f);}var hex="#"+((1<<24)+(fr<<16)+(fg<<8)+fb).toString(16).slice(1);tile.setAttribute("data-color",hex);tile.style.borderColor=hex;var pb=tile.querySelector(".gp-tile-play");if(pb)pb.style.background=hex;}catch(e){}}function gpRippleEffect(tile){var tiles=document.querySelectorAll(".gtile");var cr=tile.getBoundingClientRect();var cx=cr.left+cr.width/2;var cy=cr.top+cr.height/2;var bc=tile.style.borderColor||"#BF3626";var m=bc.match(/(\d+)\s*,\s*(\d+)\s*,\s*(\d+)/);var rr=191;var gg=54;var bb=38;if(m){rr=parseInt(m[1]);gg=parseInt(m[2]);bb=parseInt(m[3])}else if(bc.charAt(0)==="#"){var hx=bc.replace("#","");if(hx.length===3){hx=hx[0]+hx[0]+hx[1]+hx[1]+hx[2]+hx[2]}rr=parseInt(hx.substring(0,2),16);gg=parseInt(hx.substring(2,4),16);bb=parseInt(hx.substring(4,6),16)}var maxDist=0;var dists=[];for(var i=0;imaxDist)maxDist=d}var speed=0.5;for(var j=0;j0?dists[j]/maxDist:0;var delay=Math.round(dists[j]*speed);var energy=Math.pow(1-ratio,2);var bw=Math.max(1,Math.round(5*energy));var alpha=Math.round(energy*100)/100;if(alpha<0.05)alpha=0.05;var col="rgba("+rr+","+gg+","+bb+","+alpha+")";var origBorder=tiles[j].getAttribute("data-orig-border")||tiles[j].style.border;if(!tiles[j].getAttribute("data-orig-border")){tiles[j].setAttribute("data-orig-border",tiles[j].style.border)}var dur=0.3+ratio*0.4;(function(t,d,b,c,ob,du){setTimeout(function(){t.style.transition="border "+du+"s cubic-bezier(0.25,0.8,0.25,1)";t.style.border=b+"px solid "+c;setTimeout(function(){t.style.transition="border 0.6s ease-out";t.style.border=ob;setTimeout(function(){t.style.transition=""},700)},Math.round(du*1000))},d)})(tiles[j],delay,bw,col,origBorder,dur)}}var gpAudio=null;var gpPopup=null;var gpCurrentTile=null;var gpWaveCanvas=null;var gpAnimFrame=null;var gpScrubbing=false;var gpWasPlaying=false;var gpScrubTarget=0;var gpScrubTimer=null;var gpVibeMap={"scary":"spine-tinglingly scary","spooky":"spooky as anything","dramatic":"dead dramatic","cinematic":"gorgeous cinematic","energetic":"turbo-charged","funky":"ultra funky","upbeat":"super-duper upbeat","bouncy":"bouncier-than-a-trampoline","retro":"mega retro","mysterious":"mysteriously marvellous","moody":"gorgeously moody","cool":"ice-cool","romantic":"swooningly romantic","sexy":"saucy","bleak":"hauntingly bleak","orchestral":"beautiful orchestral","atmospheric":"beautifully atmospheric","cheerful":"ridiculously cheerful","aggressive":"hard-hitting","dark":"dark and moody","epic":"stupendously epic","quirky":"wonderfully weird","jazzy":"smooth-as-silk jazzy","bluesy":"soulfully bluesy","latin":"spicy Latin","acoustic":"gorgeous acoustic","electronic":"synth-tastic","weird":"delightfully odd","filmic":"gorgeous filmic","powerful":"thumping great","melancholic":"beautifully melancholic","playful":"super playful","gritty":"proper gritty","chilled":"smooth-as-silk","intense":"blisteringly intense","dreamy":"dreamily beautiful","triumphant":"magnificently triumphant","suspenseful":"nail-bitingly suspenseful","nostalgic":"gorgeously nostalgic","euphoric":"euphoric","historical":"historical","gentle":"beautifully gentle","elegant":"gorgeously elegant","sombre":"hauntingly sombre","tender":"tenderly beautiful","majestic":"majestically gorgeous"};var gpFallback=["super-duper","absolute corker of a","ultra groovy","belting","cracking","funky as you like","top-drawer","stonking","tasty","proper banging","fabtabulous","stupendously brilliant","magnificently funky","fantabulously groovy","splendidly smashing","spectacularly ace","ridiculously good","mega marvellous","tremendously top-notch","blisteringly brilliant","outrageously catchy","unbelievably slick","jaw-droppingly good","bonkersly brilliant","supremely sizzling","astoundingly funky","mind-bogglingly great","terrifically tasty","extraordinarily epic","phenomenally phat","wonderfully wicked","ludicrously lovely","delectably delicious","rip-roaringly good","thumping great"];var gpVibeRotate={"turbo-charged":["high-octane","turbo-charged","full-throttle","mega energetic","seriously punchy","ridiculously zippy"],"super-duper upbeat":["super-duper upbeat","properly upbeat","dead catchy","seriously uplifting","majorly feel-good","outrageously cheerful"],"ultra funky":["ultra funky","phenomenally funky","funky as you like","fabtabulously funky","outrageously funky"],"gorgeous cinematic":["gorgeous cinematic","beautiful cinematic","stupendously cinematic","magnificently cinematic","jaw-droppingly cinematic","breathtakingly cinematic"],"smooth-as-silk jazzy":["smooth-as-silk jazzy","gorgeously jazzy","supremely jazzy","effortlessly jazzy"],"beautiful orchestral":["beautiful orchestral","gorgeous orchestral","magnificently orchestral","stunningly orchestral"],"gorgeous filmic":["gorgeous filmic","beautifully filmic","fabtabulously filmic","stunningly filmic"],"beautifully atmospheric":["beautifully atmospheric","gorgeously atmospheric","hauntingly atmospheric","stunningly atmospheric"]};function gpPickVibe(name,keywords,desc){var vibe="";var era="";if(keywords){var kl=keywords.toLowerCase();var eraMatch=kl.match(/(19[5-8]0)s/);if(eraMatch){var yr=parseInt(eraMatch[1]);if(yr<=1989){var eHash=0;for(var eh=0;eh0)btn.removeChild(btn.firstChild);if(playing){var b1=document.createElement('span');b1.style.cssText='display:inline-block;width:3px;height:8px;background:white;margin-right:2px;border-radius:1px;';var b2=document.createElement('span');b2.style.cssText='display:inline-block;width:3px;height:8px;background:white;border-radius:1px;';btn.appendChild(b1);btn.appendChild(b2)}else{var tri=document.createElement('span');tri.style.cssText='display:inline-block;width:0;height:0;border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:7px solid white;margin-left:1px;';btn.appendChild(tri)}}var gpGlowInterval=null;var gpGlowPhase=0;function gpSetTileGlow(tile,mode){if(gpGlowInterval){clearInterval(gpGlowInterval);gpGlowInterval=null}if(!tile){return}var color=tile.getAttribute('data-color')||'#BF3626';if(mode==='off'){tile.style.borderWidth='2px';tile.style.boxShadow='none';tile.style.transform='scale(1)';return}tile.style.borderWidth='4px';if(mode==='play'){gpGlowPhase=0;gpGlowInterval=setInterval(function(){gpGlowPhase+=0.12;var intensity=8+6*Math.sin(gpGlowPhase);tile.style.boxShadow='0 0 '+intensity+'px '+color},50)}else{tile.style.boxShadow='0 0 10px '+color}}function gpSeedRand(s){var h=0;for(var i=0;i]+>([^<]+)/);var descMatch=xhr.responseText.match(/description:\s*'([^']+)'/);var kwMatch=xhr.responseText.match(/keywords:\s*'([^']+)'/);if(mp3Match){var url=mp3Match[1];var composer=artistMatch?artistMatch[1].replace(/\s*\(PRS\)/g,"").replace(/\s*\(SOCAN\)/g,"").replace(/\s*\(ASCAP\)/g,"").replace(/\s*\(BMI\)/g,"").replace(/\s*\(APRA\)/g,"").replace(/\s*\(IMRO\)/g,"").replace(/\s*\(GEMA\)/g,""):"";var albumCode=albumCodeMatch?albumCodeMatch[1]:"";var albumNameRaw=albumNameMatch?albumNameMatch[1]:"";var albumName=albumNameRaw?gpDecode(albumNameRaw):"";var descText=descMatch?descMatch[1]:"";var kwText=kwMatch?kwMatch[1]:"";var l1=document.getElementById("gp-line1");if(l1){l1.textContent="";var phrase=gpPickVibe(name,kwText,descText);if(albumName){var txt=document.createTextNode(phrase+" from our album ");l1.appendChild(txt);var alink=document.createElement("a");var gpAlbumSlugs={"TFJ110":"a-very-rustic-christmas","TFJ107":"beautifully-devastating-wartorn-cues","TFJ106":"a-very-magical-christmas","TFJ105":"widescreen-wonders-of-the-world","TFJ104":"kaleidoscopic-compositions","TFJ103":"sigma-phonk","TFJ102":"playfully-percussive","TFJ101":"boxfresh-promo-beats-kids","TFJ100":"boxfresh-promo-beats-fashion","TFJ099":"boxfresh-promo-beats-lifestyle","TFJ098":"boxfresh-promo-beats-summer","TFJ097":"boxfresh-promo-beats-sports","TFJ096":"country-folk-winter","TFJ095":"country-folk-autumn","TFJ094":"country-folk-summer","TFJ093":"country-folk-spring","TFJ092":"healing-drones","TFJ091":"jazz-manouche","TFJ090":"racy-indie","TFJ089":"lovely-indie","TFJ088":"sleazy-indie","TFJ087":"real-crimes-surveillance","TFJ086":"real-crimes-missing-persons","TFJ085":"real-crimes-investigation","TFJ084":"real-crimes-forensics","TFJ083":"intricate-connections","TFJ082":"gripping-drones","TFJ081":"traditional-japan","TFJ080":"modern-japan","TFJ079":"epic-dramatic-cinematic-sports","TFJ078":"abstract-works-classic","TFJ077":"abstract-works-electronic","TFJ076":"abstract-works-thematic","TFJ075":"abstract-works-atmospheric","TFJ074":"inner-city-journeys-2","TFJ073":"inner-city-journeys-1","TFJ072":"reality-tensions-racing-against-time","TFJ071":"reality-tensions-under-pressure","TFJ070":"reality-tensions-stress-tests","TFJ069":"documentary-hues-grey-anxiety","TFJ068":"documentary-hues-blue-melancholy","TFJ067":"documentary-hues-amber-hope","TFJ066":"big-hitters","TFJ065":"sophisticated-synthage-part-2-retrograde","TFJ064":"sophisticated-synthage-part-1-futuristic","TFJ063":"super-grinny-mini-tracks","TFJ062":"super-contentedly-friendly-tracks","TFJ061":"super-happy-clappy-tracks","TFJ060":"super-smirky-perky-tracks","TFJ059":"simply-plinky-plonky","TFJ058":"delicately-fragile","TFJ057":"filmic-fluffiness","TFJ056":"sweet-underscores-2","TFJ055":"fresh-underscores","TFJ054":"inspiringly-uplifting","TFJ053":"calm-cosy","TFJ052":"funky-grooves","TFJ051":"vintage-fashions","TFJ050":"cutie-kids","TFJ049":"waves-and-pulses","TFJ048":"highway-usa-2","TFJ047":"swag-beats","TFJ046":"a-very-retro-christmas","TFJ045":"kitchen-dramas","TFJ044":"winning-indie-the-rematch-2","TFJ043":"kooky-quirky-and-peculiar","TFJ042":"full-house","TFJ041":"gorgeously-guitary","TFJ040":"tip-top-drop-top-hip-hop","TFJ039":"things-happening-mysteriously","TFJ038":"things-happening-epically","TFJ037":"things-happening-loudly","TFJ036":"inquisitive-documentary-textures","TFJ035":"light-documentary-textures","TFJ034":"dark-documentary-textures","TFJ033":"urbanistica-night-hours-edition-2","TFJ032":"urbanistica-day-hours-edition-2","TFJ031":"kinda-christmassy","TFJ030":"retro-rewinds","TFJ029":"funky-cuts-2","TFJ028":"old-school-latin-spirits","TFJ027":"nu-skool-latin-spirits","TFJ026":"piano-for-film","TFJ025":"15-songs-by-emme-packer","TFJ024":"particularly-hipstery","TFJ023":"we-mean-business-2","TFJ022":"posh-stuff","TFJ021":"baggybritpopandbeyond","TFJ020":"phat-bangers","TFJ019":"theswingersparty","TFJ018":"itsaconspiracy","TFJ017":"totallyzen","TFJ016":"energybuzz","TFJ015":"winning-indie","TFJ014":"subtlelittlethings","TFJ013":"coffeeshopvibes","TFJ012":"8bittrips","TFJ011":"other-worlds","TFJ010":"seaside-rock","TFJ009":"techheads","TFJ008":"crankedkids","TFJ007":"funkyjams","TFJ006":"destinationexploration","TFJ005":"freakyafrica","TFJ004":"propersoccer","TFJ003":"backintheday","TFJ002":"takeawaymenu","TFJ001":"sex-drugs-rock-n-roll","ATSTAJ018":"david-lol-perry-the-ayahuasca-sessions","ATSTAJ017":"tales-of-sound-and-silence-gods-of-the-weekend","ATSTAJ016":"thomas-mountjoy-floating-in-the-colourfield","ATSTAJ015":"nigel-brown-stories-from-the-open-road","ATSTAJ014":"white-doors-cold-gun-confessions","ATSTAJ013":"enzo-orefice-ces-riffs-netaient-pas-censes-exister-et-pourtant","ATSTAJ012":"james-rogers-dreaming-in-real-time","ATSTAJ011":"donal-scott-for-a-while-we-were-here","ATSTAJ010":"carlos-pacheco-the-thursday-night-basement-jam","ATSTAJ009":"players-certified-platinum","ATSTAJ008":"will-lyons-poems-of-the-everflowing","ATSTAJ007":"marty-zylstra-sunny-side-up","ATSTAJ006":"barry-thompson-mr-thompson-and-his-riff-raff-ragtime-revue","ATSTAJ005":"project-10-lust-love-rejection","ATSTAJ004":"lumen-fold-the-long-dawn","ATSTAJ003":"jose-ibanez-burnouts-bloods-and-brotherhoods","ATSTAJ002":"harvey-mason-halfway-to-somewhere","ATSTAJ001":"lisa-marini-songs-past-midnight"};var aSlug=gpAlbumSlugs[albumCode];alink.href=aSlug?"/album/"+aSlug+"/#play="+encodeURIComponent(track):"/music/";alink.style.cssText="color:#D90000;text-decoration:underline;font-weight:bold;";alink.textContent=albumName;l1.appendChild(alink)}else{l1.textContent=phrase+" from our library"}}var savedEdits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(savedEdits[name]){if(savedEdits[name].vibe){if(l1){while(l1.firstChild)l1.removeChild(l1.firstChild);l1.textContent=savedEdits[name].vibe}}}if(l1){gpAddVibeEdit(l1,name)}var l2=document.getElementById("gp-line2");if(l2){l2.textContent=composer?track+" composed by "+composer:track;gpStartMarquee()}gpAudio=new Audio(url);gpAudio.addEventListener("canplay",function(){gpAudio.play();gpSetIcon(document.getElementById("gp-play"),true);if(gpCurrentTile){gpSetTileGlow(gpCurrentTile,'play')}gpUpdateWave()});gpAudio.addEventListener("ended",function(){gpSetIcon(document.getElementById("gp-play"),false);if(gpCurrentTile){gpSetTileBtn(gpCurrentTile,false);gpSetTileGlow(gpCurrentTile,'off');gpCurrentTile=null};if(gpAnimFrame){cancelAnimationFrame(gpAnimFrame);gpAnimFrame=null}});gpAudio.addEventListener("error",function(){var l2e=document.getElementById("gp-line2");if(l2e){l2e.textContent="Audio unavailable"}});gpAudio.addEventListener("timeupdate",function(){if(!gpAudio)return;var m=Math.floor(gpAudio.currentTime/60);var s=Math.floor(gpAudio.currentTime%60);var dm=Math.floor(gpAudio.duration/60);var ds=Math.floor(gpAudio.duration%60);var tmr=document.getElementById("gp-timer");if(tmr){tmr.textContent=m+":"+(s<10?"0":"")+s+" / "+dm+":"+(ds<10?"0":"")+ds}})}else{var l1f=document.getElementById("gp-line1");if(l1f){l1f.textContent=name+" used this track \u2022 Track not found in library"}}}};var amp=String.fromCharCode(38);xhr.send("action=fetchtracks_jplayer_search"+amp+"data=%22"+encodeURIComponent(track)+"%22"+amp+"cf_mix=MAIN+MIX")}function gpTogglePlay(){if(!gpAudio)return;if(gpAudio.paused){gpAudio.play();gpSetIcon(document.getElementById("gp-play"),true);if(gpCurrentTile){gpSetTileBtn(gpCurrentTile,true);gpSetTileGlow(gpCurrentTile,'play')}gpUpdateWave()}else{gpAudio.pause();gpSetIcon(document.getElementById("gp-play"),false);if(gpCurrentTile){gpSetTileBtn(gpCurrentTile,false);gpSetTileGlow(gpCurrentTile,'pause')}if(gpAnimFrame){cancelAnimationFrame(gpAnimFrame);gpAnimFrame=null}}}function gpClose(){document.removeEventListener("keydown",gpKeyHandler);if(gpCurrentTile){gpSetTileBtn(gpCurrentTile,false);gpSetTileGlow(gpCurrentTile,'off');gpCurrentTile=null}if(gpAudio){gpAudio.pause();gpAudio=null}if(gpAnimFrame){cancelAnimationFrame(gpAnimFrame);gpAnimFrame=null}if(gpPopup){gpPopup.style.bottom="-100px";setTimeout(function(){if(gpPopup){gpPopup.remove();gpPopup=null}},400)}gpWaveCanvas=null}function filterGroupies(cat){var tiles=document.querySelectorAll(".gtile");var btns=document.querySelectorAll(".gf-btn");for(var i=0;i]+>/g,"").trim();if(clean){try{if(clean.indexOf("GPCONFIG:")===0){clean=decodeURIComponent(escape(atob(clean.substring(9))))}else{clean=clean.replace(/\u201c/g,'"').replace(/\u201d/g,'"').replace(/\u2018/g,"'").replace(/\u2019/g,"'")}var edits=JSON.parse(clean);var localEdits=JSON.parse(localStorage.getItem("gpEdits")||"{}");var skeys=Object.keys(edits);for(var si=0;si=0;si--){if(!allSpans[si].classList.contains("gp-tile-play")&&allSpans[si].parentNode===t){allSpans[si].textContent=e.name;break}}}if(e.vibe){var l1=t.querySelector(".gp-tile-l1");if(l1){while(l1.firstChild)l1.removeChild(l1.firstChild);l1.textContent=e.vibe}}if(e.hidden){t.setAttribute("data-draft","1");if(!document.getElementById("wpadminbar")){t.style.display="none"}else{t.style.outline="2px dashed #F59E0B";t.style.opacity="0.7"}}if(e.hidden===false){t.removeAttribute("data-draft");t.style.outline="none";t.style.opacity="1";t.style.display=""}}}catch(ex){console.log("Edit error for "+gn,ex)}}}function gpSetColor(tile,color,btn){var gn=tile.getAttribute("data-gname");tile.setAttribute("data-color",color);tile.style.borderColor=color;btn.style.background=color;var playBtn=tile.querySelector(".gp-tile-play");if(playBtn){playBtn.style.background=color}var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gn])edits[gn]={};edits[gn].borderColor=color;localStorage.setItem("gpEdits",JSON.stringify(edits));}function gpToggleHide(tile,btn){var gn=tile.getAttribute("data-gname");var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gn])edits[gn]={};var isDraft=tile.getAttribute("data-draft")==="1";if(isDraft){tile.removeAttribute("data-draft");tile.style.outline="none";tile.style.opacity="1";edits[gn].hidden=false;btn.textContent="●";btn.title="Hide from live site";btn.style.background="rgba(0,0,0,0.5)";}else{tile.setAttribute("data-draft","1");tile.style.outline="2px dashed #F59E0B";tile.style.opacity="0.7";edits[gn].hidden=true;btn.textContent="○";btn.title="Show on live site";btn.style.background="rgba(245,158,11,0.8)";}localStorage.setItem("gpEdits",JSON.stringify(edits));var dc=tile.parentNode;if(dc){var dt=dc.querySelectorAll('[data-draft="1"]');for(var dk=0;dkDrop logo'); img.style.cssText="width:70px;height:70px;object-fit:contain;position:absolute;top:50%;left:50%;transform:translate(-50%,-55%);"; img.setAttribute("crossorigin","anonymous"); tile.appendChild(img); var nameSpan=document.createElement("span"); nameSpan.textContent=gname; nameSpan.style.cssText="position:absolute;bottom:6px;left:0;right:0;text-align:center;font-size:11px;font-weight:bold;color:#333;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:0 4px;"; tile.appendChild(nameSpan); var playBtn=document.createElement("span"); playBtn.className="gp-tile-play"; playBtn.innerHTML="▶"; playBtn.style.cssText="position:absolute;top:4px;right:4px;width:24px;height:24px;background:#ccc;color:white;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:10px;cursor:pointer;"; playBtn.onclick=function(e){e.stopPropagation();if(typeof playGroupieTrack==="function"){playGroupieTrack(tile)}}; tile.appendChild(playBtn); /* Add drag-drop for logo */ tile.addEventListener("dragover",function(e){e.preventDefault();e.stopPropagation();tile.style.outline="3px dashed #D90000"}); tile.addEventListener("dragleave",function(e){e.preventDefault();tile.style.outline="none"}); tile.addEventListener("drop",function(e){e.preventDefault();e.stopPropagation();tile.style.outline="none";var file=e.dataTransfer.files[0];if(!file||!file.type.startsWith("image/"))return;var reader=new FileReader();reader.onload=function(ev){var timg=tile.querySelector("img");if(timg)timg.src=ev.target.result;var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gname])edits[gname]={};edits[gname].logo=ev.target.result;localStorage.setItem("gpEdits",JSON.stringify(edits))};reader.readAsDataURL(file)}); grid.appendChild(tile); gpAddPencil(tile); gpAddDeleteX(tile); tile.classList.add("gp-ready"); /* Save to edits */ var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}"); if(!edits[gname])edits[gname]={}; edits[gname].category=cat; if(track)edits[gname].tracks=track; localStorage.setItem("gpEdits",JSON.stringify(edits)); }; document.body.appendChild(addBtn); /* === Red X delete on every tile (admin only) === */ function gpAddDeleteX(tile){ var x=document.createElement("span"); x.className="gp-delete-x"; x.textContent="\u2715"; x.style.cssText="position:absolute;right:4px;top:50%;transform:translateY(-50%);width:20px;height:20px;background:#D90000;color:white;border-radius:50%;display:none;align-items:center;justify-content:center;font-size:11px;font-weight:bold;cursor:pointer;z-index:10;line-height:20px;text-align:center;"; x.onclick=function(e){ e.stopPropagation(); var gn=tile.getAttribute("data-gname"); if(!confirm("Delete tile: "+gn+"?"))return; tile.remove(); var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}"); if(!edits[gn])edits[gn]={}; edits[gn].hidden=true; localStorage.setItem("gpEdits",JSON.stringify(edits)); }; tile.appendChild(x); tile.addEventListener("mouseenter",function(){x.style.display="flex"}); tile.addEventListener("mouseleave",function(){x.style.display="none"}); } /* Add delete X to all existing tiles */ for(var di=0;di0){gpHandleDrop(tile,files[0])}});var btnCss="position:absolute;right:2px;width:14px;height:14px;background:rgba(0,0,0,0.5);color:white;border-radius:50%;font-size:10px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;opacity:0;transition:opacity 0.2s;line-height:1;font-weight:bold;";var plusBtn=document.createElement("span");plusBtn.textContent="+";plusBtn.style.cssText=btnCss+"top:3px;";plusBtn.onclick=function(e){e.stopPropagation();gpResizeLogo(tile,5)};var minusBtn=document.createElement("span");minusBtn.textContent="–";minusBtn.style.cssText=btnCss+"top:19px;";minusBtn.onclick=function(e){e.stopPropagation();gpResizeLogo(tile,-5)};tile.appendChild(plusBtn);tile.appendChild(minusBtn);var hideBtn=document.createElement("span");var isHidden=tile.getAttribute("data-draft")==="1";hideBtn.textContent=isHidden?"○":"●";hideBtn.title=isHidden?"Show on live site":"Hide from live site";hideBtn.style.cssText=btnCss+"bottom:4px;right:auto;left:2px;";if(isHidden){hideBtn.style.background="rgba(245,158,11,0.8)"}hideBtn.onclick=function(e){e.stopPropagation();gpToggleHide(tile,hideBtn)};tile.appendChild(hideBtn);var colorBtn=document.createElement("span");colorBtn.textContent="■";colorBtn.title="Change border colour";var curColor=tile.getAttribute("data-color")||"#BF3626";colorBtn.style.cssText=btnCss+"top:4px;left:50%;transform:translateX(-50%);right:auto;background:"+curColor+";";var colorInput=document.createElement("input");colorInput.type="color";colorInput.value=curColor;colorInput.style.cssText="position:absolute;opacity:0;width:0;height:0;pointer-events:none;";colorBtn.onclick=function(e){e.stopPropagation();if(window.EyeDropper){var dropper=new EyeDropper();dropper.open().then(function(result){colorInput.value=result.sRGBHex;gpSetColor(tile,result.sRGBHex,colorBtn)}).catch(function(){})}else{colorInput.click()}};colorInput.addEventListener("input",function(){gpSetColor(tile,colorInput.value,colorBtn)});tile.appendChild(colorBtn);tile.appendChild(colorInput);tile.addEventListener("mouseenter",function(){hideBtn.style.opacity="1";colorBtn.style.opacity="1"});tile.addEventListener("mouseleave",function(){hideBtn.style.opacity="0";colorBtn.style.opacity="0"});var tImg=tile.querySelector("img");if(tImg){tImg.style.cursor="move";tImg.addEventListener("mouseenter",function(){gpHoverTile=tile});tImg.addEventListener("mouseleave",function(){gpHoverTile=null})}tile.addEventListener("mouseenter",function(){plusBtn.style.opacity="1";minusBtn.style.opacity="1"});tile.addEventListener("mouseleave",function(){plusBtn.style.opacity="0";minusBtn.style.opacity="0"})}function gpEditTile(tile){var gn=tile.getAttribute("data-gname");var ns=tile.querySelectorAll("span");var nameSpan=null;for(var j=0;j160)w=160;if(h>160)h=160;img.style.width=w+"px";img.style.height=h+"px";var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gn])edits[gn]={};edits[gn].logoSize=w;localStorage.setItem("gpEdits",JSON.stringify(edits))}function gpMoveLogo(tile,dx,dy){var img=tile.querySelector("img");if(!img)return;var gn=tile.getAttribute("data-gname");var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gn])edits[gn]={};var cx=edits[gn].logoX||0;var cy=edits[gn].logoY||0;cx=cx+dx;cy=cy+dy;edits[gn].logoX=cx;edits[gn].logoY=cy;img.style.transform="translate("+cx+"px,"+cy+"px)";localStorage.setItem("gpEdits",JSON.stringify(edits))}function gpHandleDrop(tile,file){if(!file.type.match("image.*"))return;var gn=tile.getAttribute("data-gname");var reader=new FileReader();reader.onload=function(ev){var img=new Image();img.onload=function(){var canvas=document.createElement("canvas");canvas.width=200;canvas.height=200;var ctx=canvas.getContext("2d");ctx.fillStyle="#ffffff";ctx.fillRect(0,0,200,200);var scale=Math.min(168/img.width,168/img.height);var nw=Math.round(img.width*scale);var nh=Math.round(img.height*scale);var ox=Math.round((200-nw)/2);var oy=Math.round((200-nh)/2);ctx.drawImage(img,ox,oy,nw,nh);var dataUri=canvas.toDataURL("image/png");var tileImg=tile.querySelector("img");if(tileImg){tileImg.src=dataUri;tileImg.style.display=""}else{var newImg=document.createElement("img");newImg.src=dataUri;newImg.style.cssText="width:100px;height:100px;object-fit:contain;margin-bottom:4px;border-radius:8px;position:relative;z-index:1;";tile.insertBefore(newImg,tile.firstChild)}var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gn])edits[gn]={};edits[gn].logo=dataUri;localStorage.setItem("gpEdits",JSON.stringify(edits))};img.src=ev.target.result};reader.readAsDataURL(file)}function gpAddVibeEdit(l1el,gname){if(!gpAdminReady)return;var existing=l1el.querySelector(".gp-vibe-pencil");if(existing)existing.remove();var pencil=document.createElement("span");pencil.className="gp-vibe-pencil";pencil.textContent="\u270F";pencil.style.cssText="display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;background:rgba(0,0,0,0.5);color:white;border-radius:50%;font-size:10px;cursor:pointer;margin-left:6px;vertical-align:middle;flex-shrink:0;";pencil.onclick=function(e){e.stopPropagation();var edits=JSON.parse(localStorage.getItem("gpEdits")||"{}");if(!edits[gname])edits[gname]={};var curText="";var nodes=l1el.childNodes;for(var i=0;i filterGroupies('xxx') document.addEventListener('click', function(e) { var btn = e.target.closest('[data-filter]'); if (btn) { filterGroupies(btn.getAttribute('data-filter')); return; } // Click on tile or play button -> play track var tile = e.target.closest('.gtile'); if (tile) { var gname = tile.getAttribute('data-gname'); var track = tile.getAttribute('data-track'); if (gname && track) playGroupieTrack(gname, track, tile); return; } }); // Hover effects on tiles (mouseover/mouseout) document.addEventListener('mouseover', function(e) { var tile = e.target.closest('.gtile'); if (tile && !tile._hovering) { tile._hovering = true; var color = tile.getAttribute('data-color') || '#d00'; tile.style.borderColor = color; tile.style.boxShadow = '0 4px 16px ' + color + '44'; tile.style.transform = 'translateY(-4px) scale(1.03)'; var playBtn = tile.querySelector('.gp-tile-play'); if (playBtn) { playBtn.style.opacity = '1'; playBtn.style.transform = 'scale(1)'; } } }); document.addEventListener('mouseout', function(e) { var tile = e.target.closest('.gtile'); if (tile && tile._hovering) { // Check if we actually left the tile var related = e.relatedTarget; if (related && tile.contains(related)) return; tile._hovering = false; var color = tile.getAttribute('data-color') || '#ddd'; tile.style.borderColor = color; tile.style.boxShadow = 'none'; tile.style.transform = ''; var playBtn = tile.querySelector('.gp-tile-play'); if (playBtn) { playBtn.style.opacity = '0.8'; playBtn.style.transform = 'scale(0.9)'; } } }); // Image onload -> gpAutoColor, onerror -> hide tile function handleImages() { var imgs = document.querySelectorAll('.gtile .gp-tile-img'); for (var i = 0; i < imgs.length; i++) { (function(img) { if (img._handled) return; img._handled = true; if (img.complete && img.naturalWidth > 0) { gpAutoColor(img); } else { img.addEventListener('load', function() { gpAutoColor(img); }); img.addEventListener('error', function() { var tile = img.closest('.gtile'); if (tile) tile.style.display = 'none'; }); } })(imgs[i]); } } // Run after DOM ready and also after a short delay for dynamic tiles if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', handleImages); } else { handleImages(); } setTimeout(handleImages, 2000); })();