diff --git a/dist/assets/index-BHCNYw42.js b/dist/assets/index-BailLCJ0.js similarity index 87% rename from dist/assets/index-BHCNYw42.js rename to dist/assets/index-BailLCJ0.js index d48094b..ca16719 100644 --- a/dist/assets/index-BHCNYw42.js +++ b/dist/assets/index-BailLCJ0.js @@ -256,7 +256,7 @@ to { * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */var ea=k,W4=U4;function H4(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var q4=typeof Object.is=="function"?Object.is:H4,G4=W4.useSyncExternalStore,Y4=ea.useRef,K4=ea.useEffect,X4=ea.useMemo,Q4=ea.useDebugValue;Dg.useSyncExternalStoreWithSelector=function(e,t,n,r,s){var i=Y4(null);if(i.current===null){var o={hasValue:!1,value:null};i.current=o}else o=i.current;i=X4(function(){function l(h){if(!c){if(c=!0,d=h,h=r(h),s!==void 0&&o.hasValue){var p=o.value;if(s(p,h))return f=p}return f=h}if(p=f,q4(d,h))return p;var g=r(h);return s!==void 0&&s(p,g)?(d=h,p):(d=h,f=g)}var c=!1,d,f,u=n===void 0?null:n;return[function(){return l(t())},u===null?void 0:function(){return l(u())}]},[t,n,r,s]);var a=G4(e,i[0],i[1]);return K4(function(){o.hasValue=!0,o.value=a},[a]),Q4(a),a};Lg.exports=Dg;var Z4=Lg.exports;const J4=cu(Z4),Fg={},{useDebugValue:eb}=Gs,{useSyncExternalStoreWithSelector:tb}=J4;let ih=!1;const nb=e=>e;function rb(e,t=nb,n){(Fg?"production":void 0)!=="production"&&n&&!ih&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),ih=!0);const r=tb(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return eb(r),r}const sb=e=>{(Fg?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?L4(e):e,n=(r,s)=>rb(t,r,s);return Object.assign(n,t),n},ib=e=>sb,ob={};function ab(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var i;const o=l=>l===null?null:JSON.parse(l,void 0),a=(i=n.getItem(s))!=null?i:null;return a instanceof Promise?a.then(o):o(a)},setItem:(s,i)=>n.setItem(s,JSON.stringify(i,void 0)),removeItem:s=>n.removeItem(s)}}const Hs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return Hs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return Hs(r)(n)}}}},lb=(e,t)=>(n,r,s)=>{let i={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:x=>x,version:0,merge:(x,v)=>({...v,...x}),...t},o=!1;const a=new Set,l=new Set;let c;try{c=i.getStorage()}catch{}if(!c)return e((...x)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...x)},r,s);const d=Hs(i.serialize),f=()=>{const x=i.partialize({...r()});let v;const y=d({state:x,version:i.version}).then(w=>c.setItem(i.name,w)).catch(w=>{v=w});if(v)throw v;return y},u=s.setState;s.setState=(x,v)=>{u(x,v),f()};const h=e((...x)=>{n(...x),f()},r,s);let p;const g=()=>{var x;if(!c)return;o=!1,a.forEach(y=>y(r()));const v=((x=i.onRehydrateStorage)==null?void 0:x.call(i,r()))||void 0;return Hs(c.getItem.bind(c))(i.name).then(y=>{if(y)return i.deserialize(y)}).then(y=>{if(y)if(typeof y.version=="number"&&y.version!==i.version){if(i.migrate)return i.migrate(y.state,y.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return y.state}).then(y=>{var w;return p=i.merge(y,(w=r())!=null?w:h),n(p,!0),f()}).then(()=>{v==null||v(p,void 0),o=!0,l.forEach(y=>y(p))}).catch(y=>{v==null||v(void 0,y)})};return s.persist={setOptions:x=>{i={...i,...x},x.getStorage&&(c=x.getStorage())},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>g(),hasHydrated:()=>o,onHydrate:x=>(a.add(x),()=>{a.delete(x)}),onFinishHydration:x=>(l.add(x),()=>{l.delete(x)})},g(),p||h},ub=(e,t)=>(n,r,s)=>{let i={storage:ab(()=>localStorage),partialize:g=>g,version:0,merge:(g,x)=>({...x,...g}),...t},o=!1;const a=new Set,l=new Set;let c=i.storage;if(!c)return e((...g)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...g)},r,s);const d=()=>{const g=i.partialize({...r()});return c.setItem(i.name,{state:g,version:i.version})},f=s.setState;s.setState=(g,x)=>{f(g,x),d()};const u=e((...g)=>{n(...g),d()},r,s);s.getInitialState=()=>u;let h;const p=()=>{var g,x;if(!c)return;o=!1,a.forEach(y=>{var w;return y((w=r())!=null?w:u)});const v=((x=i.onRehydrateStorage)==null?void 0:x.call(i,(g=r())!=null?g:u))||void 0;return Hs(c.getItem.bind(c))(i.name).then(y=>{if(y)if(typeof y.version=="number"&&y.version!==i.version){if(i.migrate)return[!0,i.migrate(y.state,y.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,y.state];return[!1,void 0]}).then(y=>{var w;const[b,S]=y;if(h=i.merge(S,(w=r())!=null?w:u),n(h,!0),b)return d()}).then(()=>{v==null||v(h,void 0),h=r(),o=!0,l.forEach(y=>y(h))}).catch(y=>{v==null||v(void 0,y)})};return s.persist={setOptions:g=>{i={...i,...g},g.storage&&(c=g.storage)},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>p(),hasHydrated:()=>o,onHydrate:g=>(a.add(g),()=>{a.delete(g)}),onFinishHydration:g=>(l.add(g),()=>{l.delete(g)})},i.skipHydration||p(),h||u},cb=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((ob?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),lb(e,t)):ub(e,t),db=cb,oh={currentUser:null,partnerUser:null,isLoading:!1,error:null,currentTrack:null,isPlaying:!1},ae=ib()(db(e=>({...oh,mixedPlaylists:[],memoryLane:[],theme:"green",setCurrentUser:t=>e({currentUser:t}),setPartnerUser:t=>e({partnerUser:t}),logout:()=>e({currentUser:null,partnerUser:null,currentTrack:null,isPlaying:!1,mixedPlaylists:[],memoryLane:[],error:null}),setLoading:t=>e({isLoading:t}),setError:t=>e({error:t}),setCurrentTrack:t=>e({currentTrack:t}),setIsPlaying:t=>e({isPlaying:t}),addMixedPlaylist:t=>e(n=>({mixedPlaylists:[...n.mixedPlaylists,t]})),removeMixedPlaylist:t=>e(n=>({mixedPlaylists:n.mixedPlaylists.filter(r=>r.id!==t)})),setMixedPlaylists:t=>e({mixedPlaylists:t}),addMemoryLaneItem:t=>e(n=>({memoryLane:[...n.memoryLane,t].sort((r,s)=>new Date(s.date).getTime()-new Date(r.date).getTime())})),removeMemoryLaneItem:t=>e(n=>({memoryLane:n.memoryLane.filter(r=>r.id!==t)})),setTheme:t=>e({theme:t}),clearAllData:()=>e({...oh,mixedPlaylists:[],memoryLane:[]})}),{name:"spotify-app-settings",partialize:e=>({theme:e.theme})}));function fb(){{const e="/api";try{const t=typeof window<"u"&&window.location.protocol==="https:",n=new URL(e,window.location.origin);if(t&&n.protocol==="http:"&&n.hostname==="159.195.9.107"&&(n.port==="8081"||n.port===""))return"https://159.195.9.107:8082"}catch{}return e}}const Br=fb();function qt(){try{const e=localStorage.getItem("spotify-user");if(!e)return null;const t=JSON.parse(e);return(t==null?void 0:t.jwt)||(t==null?void 0:t.token)||null}catch{return null}}async function Pt(e,t,n){const r=await fetch(`${Br}${e}`,{method:"POST",headers:{"Content-Type":"application/json",...n?{Authorization:`Bearer ${n}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}},body:t?JSON.stringify(t):void 0});if(!r.ok){const s=await r.text();throw new Error(s||`Request failed: ${r.status}`)}return r.json()}async function se(e,t){const n=await fetch(`${Br}${e}`,{headers:{...t?{Authorization:`Bearer ${t}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}}});if(!n.ok){const r=await n.text();throw new Error(r||`Request failed: ${n.status}`)}return n.json()}function hb(e){const t=qt(),n=new URL(`${Br}${e}`,window.location.origin);return t&&n.searchParams.set("token",t),new EventSource(n.toString())}async function pb(e,t,n){const r=await fetch(`${Br}${e}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...qt()?{Authorization:`Bearer ${qt()}`}:{}},body:new URLSearchParams(t).toString()});if(!r.ok){const s=await r.text();throw new Error(s||`Request failed: ${r.status}`)}return r.json()}async function mb(e,t){const n=await fetch(`${Br}${e}`,{method:"DELETE",headers:{...t?{Authorization:`Bearer ${t}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}}});if(!n.ok){const r=await n.text();throw new Error(r||`Request failed: ${n.status}`)}return n.json()}const Vr=e=>{const t={green:{primary:"bg-theme-green-primary text-white",secondary:"bg-theme-green-secondary text-white",accent:"bg-theme-green-accent text-white",border:"border-theme-green-primary",text:"text-theme-green-primary",gradient:"from-theme-green-primary to-theme-green-secondary",glass:"bg-theme-green-primary/10 border-theme-green-primary/30",hover:"hover:bg-theme-green-primary/20",cssVars:{primary:"#1db954",secondary:"#1ed760",accent:"#00e676"}},pink:{primary:"bg-theme-pink-primary text-white",secondary:"bg-theme-pink-secondary text-white",accent:"bg-theme-pink-accent text-white",border:"border-theme-pink-primary",text:"text-theme-pink-primary",gradient:"from-theme-pink-primary to-theme-pink-secondary",glass:"bg-theme-pink-primary/10 border-theme-pink-primary/30",hover:"hover:bg-theme-pink-primary/20",cssVars:{primary:"#ec4899",secondary:"#f472b6",accent:"#fb7185"}},blue:{primary:"bg-theme-blue-primary text-white",secondary:"bg-theme-blue-secondary text-white",accent:"bg-theme-blue-accent text-white",border:"border-theme-blue-primary",text:"text-theme-blue-primary",gradient:"from-theme-blue-primary to-theme-blue-secondary",glass:"bg-theme-blue-primary/10 border-theme-blue-primary/30",hover:"hover:bg-theme-blue-primary/20",cssVars:{primary:"#3b82f6",secondary:"#60a5fa",accent:"#93c5fd"}},red:{primary:"bg-theme-red-primary text-white",secondary:"bg-theme-red-secondary text-white",accent:"bg-theme-red-accent text-white",border:"border-theme-red-primary",text:"text-theme-red-primary",gradient:"from-theme-red-primary to-theme-red-secondary",glass:"bg-theme-red-primary/10 border-theme-red-primary/30",hover:"hover:bg-theme-red-primary/20",cssVars:{primary:"#dc2626",secondary:"#ef4444",accent:"#f87171"}},purple:{primary:"bg-theme-purple-primary text-white",secondary:"bg-theme-purple-secondary text-white",accent:"bg-theme-purple-accent text-white",border:"border-theme-purple-primary",text:"text-theme-purple-primary",gradient:"from-theme-purple-primary to-theme-purple-secondary",glass:"bg-theme-purple-primary/10 border-theme-purple-primary/30",hover:"hover:bg-theme-purple-primary/20",cssVars:{primary:"#8b5cf6",secondary:"#a78bfa",accent:"#c4b5fd"}},yellow:{primary:"bg-theme-yellow-primary text-black",secondary:"bg-theme-yellow-secondary text-black",accent:"bg-theme-yellow-accent text-black",border:"border-theme-yellow-primary",text:"text-theme-yellow-primary",gradient:"from-theme-yellow-primary to-theme-yellow-secondary",glass:"bg-theme-yellow-primary/10 border-theme-yellow-primary/30",hover:"hover:bg-theme-yellow-primary/20",cssVars:{primary:"#eab308",secondary:"#f59e0b",accent:"#fbbf24"}},turquoise:{primary:"bg-theme-turquoise-primary text-white",secondary:"bg-theme-turquoise-secondary text-white",accent:"bg-theme-turquoise-accent text-white",border:"border-theme-turquoise-primary",text:"text-theme-turquoise-primary",gradient:"from-theme-turquoise-primary to-theme-turquoise-secondary",glass:"bg-theme-turquoise-primary/10 border-theme-turquoise-primary/30",hover:"hover:bg-theme-turquoise-primary/20",cssVars:{primary:"#06b6d4",secondary:"#22d3ee",accent:"#67e8f9"}}},n=t[e]||t.green;if(typeof document<"u"){const r=document.documentElement;r.style.setProperty("--theme-primary",n.cssVars.primary),r.style.setProperty("--theme-secondary",n.cssVars.secondary),r.style.setProperty("--theme-accent",n.cssVars.accent)}return n},ah=e=>({green:120,pink:300,blue:360,red:245,purple:280,yellow:200,turquoise:40})[e]||120;function bs(e){let t=e[0],n=e[1],r=e[2];return Math.sqrt(t*t+n*n+r*r)}function au(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function gb(e,t,n,r){return e[0]=t,e[1]=n,e[2]=r,e}function lh(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e}function uh(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e}function yb(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e}function vb(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e}function Ua(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e}function xb(e,t){let n=t[0]-e[0],r=t[1]-e[1],s=t[2]-e[2];return Math.sqrt(n*n+r*r+s*s)}function wb(e,t){let n=t[0]-e[0],r=t[1]-e[1],s=t[2]-e[2];return n*n+r*r+s*s}function ch(e){let t=e[0],n=e[1],r=e[2];return t*t+n*n+r*r}function bb(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e}function Sb(e,t){return e[0]=1/t[0],e[1]=1/t[1],e[2]=1/t[2],e}function lu(e,t){let n=t[0],r=t[1],s=t[2],i=n*n+r*r+s*s;return i>0&&(i=1/Math.sqrt(i)),e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function Ig(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function dh(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[0],a=n[1],l=n[2];return e[0]=s*l-i*a,e[1]=i*o-r*l,e[2]=r*a-s*o,e}function kb(e,t,n,r){let s=t[0],i=t[1],o=t[2];return e[0]=s+r*(n[0]-s),e[1]=i+r*(n[1]-i),e[2]=o+r*(n[2]-o),e}function Cb(e,t,n,r,s){const i=Math.exp(-r*s);let o=t[0],a=t[1],l=t[2];return e[0]=n[0]+(o-n[0])*i,e[1]=n[1]+(a-n[1])*i,e[2]=n[2]+(l-n[2])*i,e}function Pb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[3]*r+n[7]*s+n[11]*i+n[15];return o=o||1,e[0]=(n[0]*r+n[4]*s+n[8]*i+n[12])/o,e[1]=(n[1]*r+n[5]*s+n[9]*i+n[13])/o,e[2]=(n[2]*r+n[6]*s+n[10]*i+n[14])/o,e}function jb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[3]*r+n[7]*s+n[11]*i+n[15];return o=o||1,e[0]=(n[0]*r+n[4]*s+n[8]*i)/o,e[1]=(n[1]*r+n[5]*s+n[9]*i)/o,e[2]=(n[2]*r+n[6]*s+n[10]*i)/o,e}function Eb(e,t,n){let r=t[0],s=t[1],i=t[2];return e[0]=r*n[0]+s*n[3]+i*n[6],e[1]=r*n[1]+s*n[4]+i*n[7],e[2]=r*n[2]+s*n[5]+i*n[8],e}function Tb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[0],a=n[1],l=n[2],c=n[3],d=a*i-l*s,f=l*r-o*i,u=o*s-a*r,h=a*u-l*f,p=l*d-o*u,g=o*f-a*d,x=c*2;return d*=x,f*=x,u*=x,h*=2,p*=2,g*=2,e[0]=r+d+h,e[1]=s+f+p,e[2]=i+u+g,e}const Nb=function(){const e=[0,0,0],t=[0,0,0];return function(n,r){au(e,n),au(t,r),lu(e,e),lu(t,t);let s=Ig(e,t);return s>1?0:s<-1?Math.PI:Math.acos(s)}}();function Mb(e,t){return e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]}class mt extends Array{constructor(t=0,n=t,r=t){return super(t,n,r),this}get x(){return this[0]}get y(){return this[1]}get z(){return this[2]}set x(t){this[0]=t}set y(t){this[1]=t}set z(t){this[2]=t}set(t,n=t,r=t){return t.length?this.copy(t):(gb(this,t,n,r),this)}copy(t){return au(this,t),this}add(t,n){return n?lh(this,t,n):lh(this,this,t),this}sub(t,n){return n?uh(this,t,n):uh(this,this,t),this}multiply(t){return t.length?yb(this,this,t):Ua(this,this,t),this}divide(t){return t.length?vb(this,this,t):Ua(this,this,1/t),this}inverse(t=this){return Sb(this,t),this}len(){return bs(this)}distance(t){return t?xb(this,t):bs(this)}squaredLen(){return ch(this)}squaredDistance(t){return t?wb(this,t):ch(this)}negate(t=this){return bb(this,t),this}cross(t,n){return n?dh(this,t,n):dh(this,this,t),this}scale(t){return Ua(this,this,t),this}normalize(){return lu(this,this),this}dot(t){return Ig(this,t)}equals(t){return Mb(this,t)}applyMatrix3(t){return Eb(this,this,t),this}applyMatrix4(t){return Pb(this,this,t),this}scaleRotateMatrix4(t){return jb(this,this,t),this}applyQuaternion(t){return Tb(this,this,t),this}angle(t){return Nb(this,t)}lerp(t,n){return kb(this,this,t,n),this}smoothLerp(t,n,r){return Cb(this,this,t,n,r),this}clone(){return new mt(this[0],this[1],this[2])}fromArray(t,n=0){return this[0]=t[n],this[1]=t[n+1],this[2]=t[n+2],this}toArray(t=[],n=0){return t[n]=this[0],t[n+1]=this[1],t[n+2]=this[2],t}transformDirection(t){const n=this[0],r=this[1],s=this[2];return this[0]=t[0]*n+t[4]*r+t[8]*s,this[1]=t[1]*n+t[5]*r+t[9]*s,this[2]=t[2]*n+t[6]*r+t[10]*s,this.normalize()}}const fh=new mt;let _b=1,Ab=1,hh=!1;class Lb{constructor(t,n={}){t.canvas||console.error("gl not passed as first argument to Geometry"),this.gl=t,this.attributes=n,this.id=_b++,this.VAOs={},this.drawRange={start:0,count:0},this.instancedCount=0,this.gl.renderer.bindVertexArray(null),this.gl.renderer.currentGeometry=null,this.glState=this.gl.renderer.state;for(let r in n)this.addAttribute(r,n[r])}addAttribute(t,n){if(this.attributes[t]=n,n.id=Ab++,n.size=n.size||1,n.type=n.type||(n.data.constructor===Float32Array?this.gl.FLOAT:n.data.constructor===Uint16Array?this.gl.UNSIGNED_SHORT:this.gl.UNSIGNED_INT),n.target=t==="index"?this.gl.ELEMENT_ARRAY_BUFFER:this.gl.ARRAY_BUFFER,n.normalized=n.normalized||!1,n.stride=n.stride||0,n.offset=n.offset||0,n.count=n.count||(n.stride?n.data.byteLength/n.stride:n.data.length/n.size),n.divisor=n.instanced||0,n.needsUpdate=!1,n.usage=n.usage||this.gl.STATIC_DRAW,n.buffer||this.updateAttribute(n),n.divisor){if(this.isInstanced=!0,this.instancedCount&&this.instancedCount!==n.count*n.divisor)return console.warn("geometry has multiple instanced buffers of different length"),this.instancedCount=Math.min(this.instancedCount,n.count*n.divisor);this.instancedCount=n.count*n.divisor}else t==="index"?this.drawRange.count=n.count:this.attributes.index||(this.drawRange.count=Math.max(this.drawRange.count,n.count))}updateAttribute(t){const n=!t.buffer;n&&(t.buffer=this.gl.createBuffer()),this.glState.boundBuffer!==t.buffer&&(this.gl.bindBuffer(t.target,t.buffer),this.glState.boundBuffer=t.buffer),n?this.gl.bufferData(t.target,t.data,t.usage):this.gl.bufferSubData(t.target,0,t.data),t.needsUpdate=!1}setIndex(t){this.addAttribute("index",t)}setDrawRange(t,n){this.drawRange.start=t,this.drawRange.count=n}setInstancedCount(t){this.instancedCount=t}createVAO(t){this.VAOs[t.attributeOrder]=this.gl.renderer.createVertexArray(),this.gl.renderer.bindVertexArray(this.VAOs[t.attributeOrder]),this.bindAttributes(t)}bindAttributes(t){t.attributeLocations.forEach((n,{name:r,type:s})=>{if(!this.attributes[r]){console.warn(`active attribute ${r} not being supplied`);return}const i=this.attributes[r];this.gl.bindBuffer(i.target,i.buffer),this.glState.boundBuffer=i.buffer;let o=1;s===35674&&(o=2),s===35675&&(o=3),s===35676&&(o=4);const a=i.size/o,l=o===1?0:o*o*4,c=o===1?0:o*4;for(let d=0;d{const a=this.attributes[o];a.needsUpdate&&this.updateAttribute(a)});let r=2;((s=this.attributes.index)==null?void 0:s.type)===this.gl.UNSIGNED_INT&&(r=4),this.isInstanced?this.attributes.index?this.gl.renderer.drawElementsInstanced(n,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+this.drawRange.start*r,this.instancedCount):this.gl.renderer.drawArraysInstanced(n,this.drawRange.start,this.drawRange.count,this.instancedCount):this.attributes.index?this.gl.drawElements(n,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+this.drawRange.start*r):this.gl.drawArrays(n,this.drawRange.start,this.drawRange.count)}getPosition(){const t=this.attributes.position;if(t.data)return t;if(!hh)return console.warn("No position buffer data found to compute bounds"),hh=!0}computeBoundingBox(t){t||(t=this.getPosition());const n=t.data,r=t.size;this.bounds||(this.bounds={min:new mt,max:new mt,center:new mt,scale:new mt,radius:1/0});const s=this.bounds.min,i=this.bounds.max,o=this.bounds.center,a=this.bounds.scale;s.set(1/0),i.set(-1/0);for(let l=0,c=n.length;le;function rb(e,t=nb,n){(Fg?"production":void 0)!=="production"&&n&&!ih&&(console.warn("[DEPRECATED] Use `createWithEqualityFn` instead of `create` or use `useStoreWithEqualityFn` instead of `useStore`. They can be imported from 'zustand/traditional'. https://github.com/pmndrs/zustand/discussions/1937"),ih=!0);const r=tb(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return eb(r),r}const sb=e=>{(Fg?"production":void 0)!=="production"&&typeof e!="function"&&console.warn("[DEPRECATED] Passing a vanilla store will be unsupported in a future version. Instead use `import { useStore } from 'zustand'`.");const t=typeof e=="function"?L4(e):e,n=(r,s)=>rb(t,r,s);return Object.assign(n,t),n},ib=e=>sb,ob={};function ab(e,t){let n;try{n=e()}catch{return}return{getItem:s=>{var i;const o=l=>l===null?null:JSON.parse(l,void 0),a=(i=n.getItem(s))!=null?i:null;return a instanceof Promise?a.then(o):o(a)},setItem:(s,i)=>n.setItem(s,JSON.stringify(i,void 0)),removeItem:s=>n.removeItem(s)}}const Hs=e=>t=>{try{const n=e(t);return n instanceof Promise?n:{then(r){return Hs(r)(n)},catch(r){return this}}}catch(n){return{then(r){return this},catch(r){return Hs(r)(n)}}}},lb=(e,t)=>(n,r,s)=>{let i={getStorage:()=>localStorage,serialize:JSON.stringify,deserialize:JSON.parse,partialize:x=>x,version:0,merge:(x,v)=>({...v,...x}),...t},o=!1;const a=new Set,l=new Set;let c;try{c=i.getStorage()}catch{}if(!c)return e((...x)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...x)},r,s);const d=Hs(i.serialize),f=()=>{const x=i.partialize({...r()});let v;const y=d({state:x,version:i.version}).then(w=>c.setItem(i.name,w)).catch(w=>{v=w});if(v)throw v;return y},u=s.setState;s.setState=(x,v)=>{u(x,v),f()};const h=e((...x)=>{n(...x),f()},r,s);let p;const g=()=>{var x;if(!c)return;o=!1,a.forEach(y=>y(r()));const v=((x=i.onRehydrateStorage)==null?void 0:x.call(i,r()))||void 0;return Hs(c.getItem.bind(c))(i.name).then(y=>{if(y)return i.deserialize(y)}).then(y=>{if(y)if(typeof y.version=="number"&&y.version!==i.version){if(i.migrate)return i.migrate(y.state,y.version);console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return y.state}).then(y=>{var w;return p=i.merge(y,(w=r())!=null?w:h),n(p,!0),f()}).then(()=>{v==null||v(p,void 0),o=!0,l.forEach(y=>y(p))}).catch(y=>{v==null||v(void 0,y)})};return s.persist={setOptions:x=>{i={...i,...x},x.getStorage&&(c=x.getStorage())},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>g(),hasHydrated:()=>o,onHydrate:x=>(a.add(x),()=>{a.delete(x)}),onFinishHydration:x=>(l.add(x),()=>{l.delete(x)})},g(),p||h},ub=(e,t)=>(n,r,s)=>{let i={storage:ab(()=>localStorage),partialize:g=>g,version:0,merge:(g,x)=>({...x,...g}),...t},o=!1;const a=new Set,l=new Set;let c=i.storage;if(!c)return e((...g)=>{console.warn(`[zustand persist middleware] Unable to update item '${i.name}', the given storage is currently unavailable.`),n(...g)},r,s);const d=()=>{const g=i.partialize({...r()});return c.setItem(i.name,{state:g,version:i.version})},f=s.setState;s.setState=(g,x)=>{f(g,x),d()};const u=e((...g)=>{n(...g),d()},r,s);s.getInitialState=()=>u;let h;const p=()=>{var g,x;if(!c)return;o=!1,a.forEach(y=>{var w;return y((w=r())!=null?w:u)});const v=((x=i.onRehydrateStorage)==null?void 0:x.call(i,(g=r())!=null?g:u))||void 0;return Hs(c.getItem.bind(c))(i.name).then(y=>{if(y)if(typeof y.version=="number"&&y.version!==i.version){if(i.migrate)return[!0,i.migrate(y.state,y.version)];console.error("State loaded from storage couldn't be migrated since no migrate function was provided")}else return[!1,y.state];return[!1,void 0]}).then(y=>{var w;const[b,S]=y;if(h=i.merge(S,(w=r())!=null?w:u),n(h,!0),b)return d()}).then(()=>{v==null||v(h,void 0),h=r(),o=!0,l.forEach(y=>y(h))}).catch(y=>{v==null||v(void 0,y)})};return s.persist={setOptions:g=>{i={...i,...g},g.storage&&(c=g.storage)},clearStorage:()=>{c==null||c.removeItem(i.name)},getOptions:()=>i,rehydrate:()=>p(),hasHydrated:()=>o,onHydrate:g=>(a.add(g),()=>{a.delete(g)}),onFinishHydration:g=>(l.add(g),()=>{l.delete(g)})},i.skipHydration||p(),h||u},cb=(e,t)=>"getStorage"in t||"serialize"in t||"deserialize"in t?((ob?"production":void 0)!=="production"&&console.warn("[DEPRECATED] `getStorage`, `serialize` and `deserialize` options are deprecated. Use `storage` option instead."),lb(e,t)):ub(e,t),db=cb,oh={currentUser:null,partnerUser:null,isLoading:!1,error:null,currentTrack:null,isPlaying:!1},ae=ib()(db(e=>({...oh,mixedPlaylists:[],memoryLane:[],theme:"green",setCurrentUser:t=>e({currentUser:t}),setPartnerUser:t=>e({partnerUser:t}),logout:()=>e({currentUser:null,partnerUser:null,currentTrack:null,isPlaying:!1,mixedPlaylists:[],memoryLane:[],error:null}),setLoading:t=>e({isLoading:t}),setError:t=>e({error:t}),setCurrentTrack:t=>e({currentTrack:t}),setIsPlaying:t=>e({isPlaying:t}),addMixedPlaylist:t=>e(n=>({mixedPlaylists:[...n.mixedPlaylists,t]})),removeMixedPlaylist:t=>e(n=>({mixedPlaylists:n.mixedPlaylists.filter(r=>r.id!==t)})),setMixedPlaylists:t=>e({mixedPlaylists:t}),addMemoryLaneItem:t=>e(n=>({memoryLane:[...n.memoryLane,t].sort((r,s)=>new Date(s.date).getTime()-new Date(r.date).getTime())})),removeMemoryLaneItem:t=>e(n=>({memoryLane:n.memoryLane.filter(r=>r.id!==t)})),setTheme:t=>e({theme:t}),clearAllData:()=>e({...oh,mixedPlaylists:[],memoryLane:[]})}),{name:"spotify-app-settings",partialize:e=>({theme:e.theme})}));function fb(){{const e="/api";try{const t=typeof window<"u"&&window.location.protocol==="https:",n=new URL(e,window.location.origin);if(t&&n.protocol==="http:"&&n.hostname==="159.195.9.107"&&(n.port==="8081"||n.port===""))return"https://159.195.9.107:3443"}catch{}return e}}const Br=fb();function qt(){try{const e=localStorage.getItem("spotify-user");if(!e)return null;const t=JSON.parse(e);return(t==null?void 0:t.jwt)||(t==null?void 0:t.token)||null}catch{return null}}async function Pt(e,t,n){const r=await fetch(`${Br}${e}`,{method:"POST",headers:{"Content-Type":"application/json",...n?{Authorization:`Bearer ${n}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}},body:t?JSON.stringify(t):void 0});if(!r.ok){const s=await r.text();throw new Error(s||`Request failed: ${r.status}`)}return r.json()}async function se(e,t){const n=await fetch(`${Br}${e}`,{headers:{...t?{Authorization:`Bearer ${t}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}}});if(!n.ok){const r=await n.text();throw new Error(r||`Request failed: ${n.status}`)}return n.json()}function hb(e){const t=qt(),n=new URL(`${Br}${e}`,window.location.origin);return t&&n.searchParams.set("token",t),new EventSource(n.toString())}async function pb(e,t,n){const r=await fetch(`${Br}${e}`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded",...qt()?{Authorization:`Bearer ${qt()}`}:{}},body:new URLSearchParams(t).toString()});if(!r.ok){const s=await r.text();throw new Error(s||`Request failed: ${r.status}`)}return r.json()}async function mb(e,t){const n=await fetch(`${Br}${e}`,{method:"DELETE",headers:{...t?{Authorization:`Bearer ${t}`}:qt()?{Authorization:`Bearer ${qt()}`}:{}}});if(!n.ok){const r=await n.text();throw new Error(r||`Request failed: ${n.status}`)}return n.json()}const Vr=e=>{const t={green:{primary:"bg-theme-green-primary text-white",secondary:"bg-theme-green-secondary text-white",accent:"bg-theme-green-accent text-white",border:"border-theme-green-primary",text:"text-theme-green-primary",gradient:"from-theme-green-primary to-theme-green-secondary",glass:"bg-theme-green-primary/10 border-theme-green-primary/30",hover:"hover:bg-theme-green-primary/20",cssVars:{primary:"#1db954",secondary:"#1ed760",accent:"#00e676"}},pink:{primary:"bg-theme-pink-primary text-white",secondary:"bg-theme-pink-secondary text-white",accent:"bg-theme-pink-accent text-white",border:"border-theme-pink-primary",text:"text-theme-pink-primary",gradient:"from-theme-pink-primary to-theme-pink-secondary",glass:"bg-theme-pink-primary/10 border-theme-pink-primary/30",hover:"hover:bg-theme-pink-primary/20",cssVars:{primary:"#ec4899",secondary:"#f472b6",accent:"#fb7185"}},blue:{primary:"bg-theme-blue-primary text-white",secondary:"bg-theme-blue-secondary text-white",accent:"bg-theme-blue-accent text-white",border:"border-theme-blue-primary",text:"text-theme-blue-primary",gradient:"from-theme-blue-primary to-theme-blue-secondary",glass:"bg-theme-blue-primary/10 border-theme-blue-primary/30",hover:"hover:bg-theme-blue-primary/20",cssVars:{primary:"#3b82f6",secondary:"#60a5fa",accent:"#93c5fd"}},red:{primary:"bg-theme-red-primary text-white",secondary:"bg-theme-red-secondary text-white",accent:"bg-theme-red-accent text-white",border:"border-theme-red-primary",text:"text-theme-red-primary",gradient:"from-theme-red-primary to-theme-red-secondary",glass:"bg-theme-red-primary/10 border-theme-red-primary/30",hover:"hover:bg-theme-red-primary/20",cssVars:{primary:"#dc2626",secondary:"#ef4444",accent:"#f87171"}},purple:{primary:"bg-theme-purple-primary text-white",secondary:"bg-theme-purple-secondary text-white",accent:"bg-theme-purple-accent text-white",border:"border-theme-purple-primary",text:"text-theme-purple-primary",gradient:"from-theme-purple-primary to-theme-purple-secondary",glass:"bg-theme-purple-primary/10 border-theme-purple-primary/30",hover:"hover:bg-theme-purple-primary/20",cssVars:{primary:"#8b5cf6",secondary:"#a78bfa",accent:"#c4b5fd"}},yellow:{primary:"bg-theme-yellow-primary text-black",secondary:"bg-theme-yellow-secondary text-black",accent:"bg-theme-yellow-accent text-black",border:"border-theme-yellow-primary",text:"text-theme-yellow-primary",gradient:"from-theme-yellow-primary to-theme-yellow-secondary",glass:"bg-theme-yellow-primary/10 border-theme-yellow-primary/30",hover:"hover:bg-theme-yellow-primary/20",cssVars:{primary:"#eab308",secondary:"#f59e0b",accent:"#fbbf24"}},turquoise:{primary:"bg-theme-turquoise-primary text-white",secondary:"bg-theme-turquoise-secondary text-white",accent:"bg-theme-turquoise-accent text-white",border:"border-theme-turquoise-primary",text:"text-theme-turquoise-primary",gradient:"from-theme-turquoise-primary to-theme-turquoise-secondary",glass:"bg-theme-turquoise-primary/10 border-theme-turquoise-primary/30",hover:"hover:bg-theme-turquoise-primary/20",cssVars:{primary:"#06b6d4",secondary:"#22d3ee",accent:"#67e8f9"}}},n=t[e]||t.green;if(typeof document<"u"){const r=document.documentElement;r.style.setProperty("--theme-primary",n.cssVars.primary),r.style.setProperty("--theme-secondary",n.cssVars.secondary),r.style.setProperty("--theme-accent",n.cssVars.accent)}return n},ah=e=>({green:120,pink:300,blue:360,red:245,purple:280,yellow:200,turquoise:40})[e]||120;function bs(e){let t=e[0],n=e[1],r=e[2];return Math.sqrt(t*t+n*n+r*r)}function au(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e}function gb(e,t,n,r){return e[0]=t,e[1]=n,e[2]=r,e}function lh(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e}function uh(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e}function yb(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e}function vb(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e}function Ua(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e}function xb(e,t){let n=t[0]-e[0],r=t[1]-e[1],s=t[2]-e[2];return Math.sqrt(n*n+r*r+s*s)}function wb(e,t){let n=t[0]-e[0],r=t[1]-e[1],s=t[2]-e[2];return n*n+r*r+s*s}function ch(e){let t=e[0],n=e[1],r=e[2];return t*t+n*n+r*r}function bb(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e}function Sb(e,t){return e[0]=1/t[0],e[1]=1/t[1],e[2]=1/t[2],e}function lu(e,t){let n=t[0],r=t[1],s=t[2],i=n*n+r*r+s*s;return i>0&&(i=1/Math.sqrt(i)),e[0]=t[0]*i,e[1]=t[1]*i,e[2]=t[2]*i,e}function Ig(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function dh(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[0],a=n[1],l=n[2];return e[0]=s*l-i*a,e[1]=i*o-r*l,e[2]=r*a-s*o,e}function kb(e,t,n,r){let s=t[0],i=t[1],o=t[2];return e[0]=s+r*(n[0]-s),e[1]=i+r*(n[1]-i),e[2]=o+r*(n[2]-o),e}function Cb(e,t,n,r,s){const i=Math.exp(-r*s);let o=t[0],a=t[1],l=t[2];return e[0]=n[0]+(o-n[0])*i,e[1]=n[1]+(a-n[1])*i,e[2]=n[2]+(l-n[2])*i,e}function Pb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[3]*r+n[7]*s+n[11]*i+n[15];return o=o||1,e[0]=(n[0]*r+n[4]*s+n[8]*i+n[12])/o,e[1]=(n[1]*r+n[5]*s+n[9]*i+n[13])/o,e[2]=(n[2]*r+n[6]*s+n[10]*i+n[14])/o,e}function jb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[3]*r+n[7]*s+n[11]*i+n[15];return o=o||1,e[0]=(n[0]*r+n[4]*s+n[8]*i)/o,e[1]=(n[1]*r+n[5]*s+n[9]*i)/o,e[2]=(n[2]*r+n[6]*s+n[10]*i)/o,e}function Eb(e,t,n){let r=t[0],s=t[1],i=t[2];return e[0]=r*n[0]+s*n[3]+i*n[6],e[1]=r*n[1]+s*n[4]+i*n[7],e[2]=r*n[2]+s*n[5]+i*n[8],e}function Tb(e,t,n){let r=t[0],s=t[1],i=t[2],o=n[0],a=n[1],l=n[2],c=n[3],d=a*i-l*s,f=l*r-o*i,u=o*s-a*r,h=a*u-l*f,p=l*d-o*u,g=o*f-a*d,x=c*2;return d*=x,f*=x,u*=x,h*=2,p*=2,g*=2,e[0]=r+d+h,e[1]=s+f+p,e[2]=i+u+g,e}const Nb=function(){const e=[0,0,0],t=[0,0,0];return function(n,r){au(e,n),au(t,r),lu(e,e),lu(t,t);let s=Ig(e,t);return s>1?0:s<-1?Math.PI:Math.acos(s)}}();function Mb(e,t){return e[0]===t[0]&&e[1]===t[1]&&e[2]===t[2]}class mt extends Array{constructor(t=0,n=t,r=t){return super(t,n,r),this}get x(){return this[0]}get y(){return this[1]}get z(){return this[2]}set x(t){this[0]=t}set y(t){this[1]=t}set z(t){this[2]=t}set(t,n=t,r=t){return t.length?this.copy(t):(gb(this,t,n,r),this)}copy(t){return au(this,t),this}add(t,n){return n?lh(this,t,n):lh(this,this,t),this}sub(t,n){return n?uh(this,t,n):uh(this,this,t),this}multiply(t){return t.length?yb(this,this,t):Ua(this,this,t),this}divide(t){return t.length?vb(this,this,t):Ua(this,this,1/t),this}inverse(t=this){return Sb(this,t),this}len(){return bs(this)}distance(t){return t?xb(this,t):bs(this)}squaredLen(){return ch(this)}squaredDistance(t){return t?wb(this,t):ch(this)}negate(t=this){return bb(this,t),this}cross(t,n){return n?dh(this,t,n):dh(this,this,t),this}scale(t){return Ua(this,this,t),this}normalize(){return lu(this,this),this}dot(t){return Ig(this,t)}equals(t){return Mb(this,t)}applyMatrix3(t){return Eb(this,this,t),this}applyMatrix4(t){return Pb(this,this,t),this}scaleRotateMatrix4(t){return jb(this,this,t),this}applyQuaternion(t){return Tb(this,this,t),this}angle(t){return Nb(this,t)}lerp(t,n){return kb(this,this,t,n),this}smoothLerp(t,n,r){return Cb(this,this,t,n,r),this}clone(){return new mt(this[0],this[1],this[2])}fromArray(t,n=0){return this[0]=t[n],this[1]=t[n+1],this[2]=t[n+2],this}toArray(t=[],n=0){return t[n]=this[0],t[n+1]=this[1],t[n+2]=this[2],t}transformDirection(t){const n=this[0],r=this[1],s=this[2];return this[0]=t[0]*n+t[4]*r+t[8]*s,this[1]=t[1]*n+t[5]*r+t[9]*s,this[2]=t[2]*n+t[6]*r+t[10]*s,this.normalize()}}const fh=new mt;let _b=1,Ab=1,hh=!1;class Lb{constructor(t,n={}){t.canvas||console.error("gl not passed as first argument to Geometry"),this.gl=t,this.attributes=n,this.id=_b++,this.VAOs={},this.drawRange={start:0,count:0},this.instancedCount=0,this.gl.renderer.bindVertexArray(null),this.gl.renderer.currentGeometry=null,this.glState=this.gl.renderer.state;for(let r in n)this.addAttribute(r,n[r])}addAttribute(t,n){if(this.attributes[t]=n,n.id=Ab++,n.size=n.size||1,n.type=n.type||(n.data.constructor===Float32Array?this.gl.FLOAT:n.data.constructor===Uint16Array?this.gl.UNSIGNED_SHORT:this.gl.UNSIGNED_INT),n.target=t==="index"?this.gl.ELEMENT_ARRAY_BUFFER:this.gl.ARRAY_BUFFER,n.normalized=n.normalized||!1,n.stride=n.stride||0,n.offset=n.offset||0,n.count=n.count||(n.stride?n.data.byteLength/n.stride:n.data.length/n.size),n.divisor=n.instanced||0,n.needsUpdate=!1,n.usage=n.usage||this.gl.STATIC_DRAW,n.buffer||this.updateAttribute(n),n.divisor){if(this.isInstanced=!0,this.instancedCount&&this.instancedCount!==n.count*n.divisor)return console.warn("geometry has multiple instanced buffers of different length"),this.instancedCount=Math.min(this.instancedCount,n.count*n.divisor);this.instancedCount=n.count*n.divisor}else t==="index"?this.drawRange.count=n.count:this.attributes.index||(this.drawRange.count=Math.max(this.drawRange.count,n.count))}updateAttribute(t){const n=!t.buffer;n&&(t.buffer=this.gl.createBuffer()),this.glState.boundBuffer!==t.buffer&&(this.gl.bindBuffer(t.target,t.buffer),this.glState.boundBuffer=t.buffer),n?this.gl.bufferData(t.target,t.data,t.usage):this.gl.bufferSubData(t.target,0,t.data),t.needsUpdate=!1}setIndex(t){this.addAttribute("index",t)}setDrawRange(t,n){this.drawRange.start=t,this.drawRange.count=n}setInstancedCount(t){this.instancedCount=t}createVAO(t){this.VAOs[t.attributeOrder]=this.gl.renderer.createVertexArray(),this.gl.renderer.bindVertexArray(this.VAOs[t.attributeOrder]),this.bindAttributes(t)}bindAttributes(t){t.attributeLocations.forEach((n,{name:r,type:s})=>{if(!this.attributes[r]){console.warn(`active attribute ${r} not being supplied`);return}const i=this.attributes[r];this.gl.bindBuffer(i.target,i.buffer),this.glState.boundBuffer=i.buffer;let o=1;s===35674&&(o=2),s===35675&&(o=3),s===35676&&(o=4);const a=i.size/o,l=o===1?0:o*o*4,c=o===1?0:o*4;for(let d=0;d{const a=this.attributes[o];a.needsUpdate&&this.updateAttribute(a)});let r=2;((s=this.attributes.index)==null?void 0:s.type)===this.gl.UNSIGNED_INT&&(r=4),this.isInstanced?this.attributes.index?this.gl.renderer.drawElementsInstanced(n,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+this.drawRange.start*r,this.instancedCount):this.gl.renderer.drawArraysInstanced(n,this.drawRange.start,this.drawRange.count,this.instancedCount):this.attributes.index?this.gl.drawElements(n,this.drawRange.count,this.attributes.index.type,this.attributes.index.offset+this.drawRange.start*r):this.gl.drawArrays(n,this.drawRange.start,this.drawRange.count)}getPosition(){const t=this.attributes.position;if(t.data)return t;if(!hh)return console.warn("No position buffer data found to compute bounds"),hh=!0}computeBoundingBox(t){t||(t=this.getPosition());const n=t.data,r=t.size;this.bounds||(this.bounds={min:new mt,max:new mt,center:new mt,scale:new mt,radius:1/0});const s=this.bounds.min,i=this.bounds.max,o=this.bounds.center,a=this.bounds.scale;s.set(1/0),i.set(-1/0);for(let l=0,c=n.length;l{const t=kk(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:o=>{const a=o.split(Lc);return a[0]===""&&a.length!==1&&a.shift(),Gg(a,t)||Sk(o)},getConflictingClassGroupIds:(o,a)=>{const l=n[o]||[];return a&&r[o]?[...l,...r[o]]:l}}},Gg=(e,t)=>{var o;if(e.length===0)return t.classGroupId;const n=e[0],r=t.nextPart.get(n),s=r?Gg(e.slice(1),r):void 0;if(s)return s;if(t.validators.length===0)return;const i=e.join(Lc);return(o=t.validators.find(({validator:a})=>a(i)))==null?void 0:o.classGroupId},Ah=/^\[(.+)\]$/,Sk=e=>{if(Ah.test(e)){const t=Ah.exec(e)[1],n=t==null?void 0:t.substring(0,t.indexOf(":"));if(n)return"arbitrary.."+n}},kk=e=>{const{theme:t,prefix:n}=e,r={nextPart:new Map,validators:[]};return Pk(Object.entries(e.classGroups),n).forEach(([i,o])=>{uu(o,r,i,t)}),r},uu=(e,t,n,r)=>{e.forEach(s=>{if(typeof s=="string"){const i=s===""?t:Lh(t,s);i.classGroupId=n;return}if(typeof s=="function"){if(Ck(s)){uu(s(r),t,n,r);return}t.validators.push({validator:s,classGroupId:n});return}Object.entries(s).forEach(([i,o])=>{uu(o,Lh(t,i),n,r)})})},Lh=(e,t)=>{let n=e;return t.split(Lc).forEach(r=>{n.nextPart.has(r)||n.nextPart.set(r,{nextPart:new Map,validators:[]}),n=n.nextPart.get(r)}),n},Ck=e=>e.isThemeGetter,Pk=(e,t)=>t?e.map(([n,r])=>{const s=r.map(i=>typeof i=="string"?t+i:typeof i=="object"?Object.fromEntries(Object.entries(i).map(([o,a])=>[t+o,a])):i);return[n,s]}):e,jk=e=>{if(e<1)return{get:()=>{},set:()=>{}};let t=0,n=new Map,r=new Map;const s=(i,o)=>{n.set(i,o),t++,t>e&&(t=0,r=n,n=new Map)};return{get(i){let o=n.get(i);if(o!==void 0)return o;if((o=r.get(i))!==void 0)return s(i,o),o},set(i,o){n.has(i)?n.set(i,o):s(i,o)}}},Yg="!",Ek=e=>{const{separator:t,experimentalParseClassName:n}=e,r=t.length===1,s=t[0],i=t.length,o=a=>{const l=[];let c=0,d=0,f;for(let x=0;xd?f-d:void 0;return{modifiers:l,hasImportantModifier:h,baseClassName:p,maybePostfixModifierPosition:g}};return n?a=>n({className:a,parseClassName:o}):o},Tk=e=>{if(e.length<=1)return e;const t=[];let n=[];return e.forEach(r=>{r[0]==="["?(t.push(...n.sort(),r),n=[]):n.push(r)}),t.push(...n.sort()),t},Nk=e=>({cache:jk(e.cacheSize),parseClassName:Ek(e),...bk(e)}),Mk=/\s+/,_k=(e,t)=>{const{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:s}=t,i=[],o=e.trim().split(Mk);let a="";for(let l=o.length-1;l>=0;l-=1){const c=o[l],{modifiers:d,hasImportantModifier:f,baseClassName:u,maybePostfixModifierPosition:h}=n(c);let p=!!h,g=r(p?u.substring(0,h):u);if(!g){if(!p){a=c+(a.length>0?" "+a:a);continue}if(g=r(u),!g){a=c+(a.length>0?" "+a:a);continue}p=!1}const x=Tk(d).join(":"),v=f?x+Yg:x,y=v+g;if(i.includes(y))continue;i.push(y);const w=s(g,p);for(let b=0;b0?" "+a:a)}return a};function Ak(){let e=0,t,n,r="";for(;e{if(typeof e=="string")return e;let t,n="";for(let r=0;rf(d),e());return n=Nk(c),r=n.cache.get,s=n.cache.set,i=a,a(l)}function a(l){const c=r(l);if(c)return c;const d=_k(l,n);return s(l,d),d}return function(){return i(Ak.apply(null,arguments))}}const ne=e=>{const t=n=>n[e]||[];return t.isThemeGetter=!0,t},Xg=/^\[(?:([a-z-]+):)?(.+)\]$/i,Dk=/^\d+\/\d+$/,Rk=new Set(["px","full","screen"]),Vk=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Fk=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,Ik=/^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/,zk=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,Ok=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,Mt=e=>Cr(e)||Rk.has(e)||Dk.test(e),Kt=e=>Ur(e,"length",Yk),Cr=e=>!!e&&!Number.isNaN(Number(e)),Ya=e=>Ur(e,"number",Cr),ts=e=>!!e&&Number.isInteger(Number(e)),$k=e=>e.endsWith("%")&&Cr(e.slice(0,-1)),H=e=>Xg.test(e),Xt=e=>Vk.test(e),Bk=new Set(["length","size","percentage"]),Uk=e=>Ur(e,Bk,Qg),Wk=e=>Ur(e,"position",Qg),Hk=new Set(["image","url"]),qk=e=>Ur(e,Hk,Xk),Gk=e=>Ur(e,"",Kk),ns=()=>!0,Ur=(e,t,n)=>{const r=Xg.exec(e);return r?r[1]?typeof t=="string"?r[1]===t:t.has(r[1]):n(r[2]):!1},Yk=e=>Fk.test(e)&&!Ik.test(e),Qg=()=>!1,Kk=e=>zk.test(e),Xk=e=>Ok.test(e),Qk=()=>{const e=ne("colors"),t=ne("spacing"),n=ne("blur"),r=ne("brightness"),s=ne("borderColor"),i=ne("borderRadius"),o=ne("borderSpacing"),a=ne("borderWidth"),l=ne("contrast"),c=ne("grayscale"),d=ne("hueRotate"),f=ne("invert"),u=ne("gap"),h=ne("gradientColorStops"),p=ne("gradientColorStopPositions"),g=ne("inset"),x=ne("margin"),v=ne("opacity"),y=ne("padding"),w=ne("saturate"),b=ne("scale"),S=ne("sepia"),C=ne("skew"),P=ne("space"),j=ne("translate"),D=()=>["auto","contain","none"],T=()=>["auto","hidden","clip","visible","scroll"],z=()=>["auto",H,t],V=()=>[H,t],U=()=>["",Mt,Kt],R=()=>["auto",Cr,H],Q=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],A=()=>["solid","dashed","dotted","double","none"],q=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],_=()=>["start","end","center","between","around","evenly","stretch"],N=()=>["","0",H],F=()=>["auto","avoid","all","avoid-page","page","left","right","column"],L=()=>[Cr,H];return{cacheSize:500,separator:":",theme:{colors:[ns],spacing:[Mt,Kt],blur:["none","",Xt,H],brightness:L(),borderColor:[e],borderRadius:["none","","full",Xt,H],borderSpacing:V(),borderWidth:U(),contrast:L(),grayscale:N(),hueRotate:L(),invert:N(),gap:V(),gradientColorStops:[e],gradientColorStopPositions:[$k,Kt],inset:z(),margin:z(),opacity:L(),padding:V(),saturate:L(),scale:L(),sepia:N(),skew:L(),space:V(),translate:V()},classGroups:{aspect:[{aspect:["auto","square","video",H]}],container:["container"],columns:[{columns:[Xt]}],"break-after":[{"break-after":F()}],"break-before":[{"break-before":F()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...Q(),H]}],overflow:[{overflow:T()}],"overflow-x":[{"overflow-x":T()}],"overflow-y":[{"overflow-y":T()}],overscroll:[{overscroll:D()}],"overscroll-x":[{"overscroll-x":D()}],"overscroll-y":[{"overscroll-y":D()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[g]}],"inset-x":[{"inset-x":[g]}],"inset-y":[{"inset-y":[g]}],start:[{start:[g]}],end:[{end:[g]}],top:[{top:[g]}],right:[{right:[g]}],bottom:[{bottom:[g]}],left:[{left:[g]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",ts,H]}],basis:[{basis:z()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",H]}],grow:[{grow:N()}],shrink:[{shrink:N()}],order:[{order:["first","last","none",ts,H]}],"grid-cols":[{"grid-cols":[ns]}],"col-start-end":[{col:["auto",{span:["full",ts,H]},H]}],"col-start":[{"col-start":R()}],"col-end":[{"col-end":R()}],"grid-rows":[{"grid-rows":[ns]}],"row-start-end":[{row:["auto",{span:[ts,H]},H]}],"row-start":[{"row-start":R()}],"row-end":[{"row-end":R()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",H]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",H]}],gap:[{gap:[u]}],"gap-x":[{"gap-x":[u]}],"gap-y":[{"gap-y":[u]}],"justify-content":[{justify:["normal",..._()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",..._(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[..._(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[y]}],px:[{px:[y]}],py:[{py:[y]}],ps:[{ps:[y]}],pe:[{pe:[y]}],pt:[{pt:[y]}],pr:[{pr:[y]}],pb:[{pb:[y]}],pl:[{pl:[y]}],m:[{m:[x]}],mx:[{mx:[x]}],my:[{my:[x]}],ms:[{ms:[x]}],me:[{me:[x]}],mt:[{mt:[x]}],mr:[{mr:[x]}],mb:[{mb:[x]}],ml:[{ml:[x]}],"space-x":[{"space-x":[P]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[P]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",H,t]}],"min-w":[{"min-w":[H,t,"min","max","fit"]}],"max-w":[{"max-w":[H,t,"none","full","min","max","fit","prose",{screen:[Xt]},Xt]}],h:[{h:[H,t,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[H,t,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[H,t,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[H,t,"auto","min","max","fit"]}],"font-size":[{text:["base",Xt,Kt]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",Ya]}],"font-family":[{font:[ns]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",H]}],"line-clamp":[{"line-clamp":["none",Cr,Ya]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",Mt,H]}],"list-image":[{"list-image":["none",H]}],"list-style-type":[{list:["none","disc","decimal",H]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[e]}],"placeholder-opacity":[{"placeholder-opacity":[v]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[e]}],"text-opacity":[{"text-opacity":[v]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...A(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",Mt,Kt]}],"underline-offset":[{"underline-offset":["auto",Mt,H]}],"text-decoration-color":[{decoration:[e]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:V()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",H]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",H]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[v]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...Q(),Wk]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",Uk]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},qk]}],"bg-color":[{bg:[e]}],"gradient-from-pos":[{from:[p]}],"gradient-via-pos":[{via:[p]}],"gradient-to-pos":[{to:[p]}],"gradient-from":[{from:[h]}],"gradient-via":[{via:[h]}],"gradient-to":[{to:[h]}],rounded:[{rounded:[i]}],"rounded-s":[{"rounded-s":[i]}],"rounded-e":[{"rounded-e":[i]}],"rounded-t":[{"rounded-t":[i]}],"rounded-r":[{"rounded-r":[i]}],"rounded-b":[{"rounded-b":[i]}],"rounded-l":[{"rounded-l":[i]}],"rounded-ss":[{"rounded-ss":[i]}],"rounded-se":[{"rounded-se":[i]}],"rounded-ee":[{"rounded-ee":[i]}],"rounded-es":[{"rounded-es":[i]}],"rounded-tl":[{"rounded-tl":[i]}],"rounded-tr":[{"rounded-tr":[i]}],"rounded-br":[{"rounded-br":[i]}],"rounded-bl":[{"rounded-bl":[i]}],"border-w":[{border:[a]}],"border-w-x":[{"border-x":[a]}],"border-w-y":[{"border-y":[a]}],"border-w-s":[{"border-s":[a]}],"border-w-e":[{"border-e":[a]}],"border-w-t":[{"border-t":[a]}],"border-w-r":[{"border-r":[a]}],"border-w-b":[{"border-b":[a]}],"border-w-l":[{"border-l":[a]}],"border-opacity":[{"border-opacity":[v]}],"border-style":[{border:[...A(),"hidden"]}],"divide-x":[{"divide-x":[a]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[a]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[v]}],"divide-style":[{divide:A()}],"border-color":[{border:[s]}],"border-color-x":[{"border-x":[s]}],"border-color-y":[{"border-y":[s]}],"border-color-s":[{"border-s":[s]}],"border-color-e":[{"border-e":[s]}],"border-color-t":[{"border-t":[s]}],"border-color-r":[{"border-r":[s]}],"border-color-b":[{"border-b":[s]}],"border-color-l":[{"border-l":[s]}],"divide-color":[{divide:[s]}],"outline-style":[{outline:["",...A()]}],"outline-offset":[{"outline-offset":[Mt,H]}],"outline-w":[{outline:[Mt,Kt]}],"outline-color":[{outline:[e]}],"ring-w":[{ring:U()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[e]}],"ring-opacity":[{"ring-opacity":[v]}],"ring-offset-w":[{"ring-offset":[Mt,Kt]}],"ring-offset-color":[{"ring-offset":[e]}],shadow:[{shadow:["","inner","none",Xt,Gk]}],"shadow-color":[{shadow:[ns]}],opacity:[{opacity:[v]}],"mix-blend":[{"mix-blend":[...q(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":q()}],filter:[{filter:["","none"]}],blur:[{blur:[n]}],brightness:[{brightness:[r]}],contrast:[{contrast:[l]}],"drop-shadow":[{"drop-shadow":["","none",Xt,H]}],grayscale:[{grayscale:[c]}],"hue-rotate":[{"hue-rotate":[d]}],invert:[{invert:[f]}],saturate:[{saturate:[w]}],sepia:[{sepia:[S]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[n]}],"backdrop-brightness":[{"backdrop-brightness":[r]}],"backdrop-contrast":[{"backdrop-contrast":[l]}],"backdrop-grayscale":[{"backdrop-grayscale":[c]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[d]}],"backdrop-invert":[{"backdrop-invert":[f]}],"backdrop-opacity":[{"backdrop-opacity":[v]}],"backdrop-saturate":[{"backdrop-saturate":[w]}],"backdrop-sepia":[{"backdrop-sepia":[S]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[o]}],"border-spacing-x":[{"border-spacing-x":[o]}],"border-spacing-y":[{"border-spacing-y":[o]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",H]}],duration:[{duration:L()}],ease:[{ease:["linear","in","out","in-out",H]}],delay:[{delay:L()}],animate:[{animate:["none","spin","ping","pulse","bounce",H]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[b]}],"scale-x":[{"scale-x":[b]}],"scale-y":[{"scale-y":[b]}],rotate:[{rotate:[ts,H]}],"translate-x":[{"translate-x":[j]}],"translate-y":[{"translate-y":[j]}],"skew-x":[{"skew-x":[C]}],"skew-y":[{"skew-y":[C]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",H]}],accent:[{accent:["auto",e]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",H]}],"caret-color":[{caret:[e]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":V()}],"scroll-mx":[{"scroll-mx":V()}],"scroll-my":[{"scroll-my":V()}],"scroll-ms":[{"scroll-ms":V()}],"scroll-me":[{"scroll-me":V()}],"scroll-mt":[{"scroll-mt":V()}],"scroll-mr":[{"scroll-mr":V()}],"scroll-mb":[{"scroll-mb":V()}],"scroll-ml":[{"scroll-ml":V()}],"scroll-p":[{"scroll-p":V()}],"scroll-px":[{"scroll-px":V()}],"scroll-py":[{"scroll-py":V()}],"scroll-ps":[{"scroll-ps":V()}],"scroll-pe":[{"scroll-pe":V()}],"scroll-pt":[{"scroll-pt":V()}],"scroll-pr":[{"scroll-pr":V()}],"scroll-pb":[{"scroll-pb":V()}],"scroll-pl":[{"scroll-pl":V()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",H]}],fill:[{fill:[e,"none"]}],"stroke-w":[{stroke:[Mt,Kt,Ya]}],stroke:[{stroke:[e,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},Zk=Lk(Qk);function Dh(...e){return Zk(wk(e))}function Zg(e){const t=Math.floor(e/6e4),n=Math.floor(e%6e4/1e3);return`${t}:${n.toString().padStart(2,"0")}`}function Pr(e){const t=new Date(e),r=(new Date().getTime()-t.getTime())/(1e3*60*60);return r<1?`${Math.floor(r*60)}m ago`:r<24?`${Math.floor(r)}h ago`:`${Math.floor(r/24)}d ago`}const Jk=()=>{var V,U,R,Q,A,q,_,N,F,L;const[e,t]=k.useState(!1),[n,r]=k.useState(!1),[s,i]=k.useState({x:0,y:0}),[o,a]=k.useState(!1),[l,c]=k.useState({x:0,y:0}),{currentUser:d,partnerUser:f,logout:u,theme:h,setTheme:p,setPartnerUser:g}=ae(),[x,v]=k.useState(""),[y,w]=k.useState(!1),[b,S]=k.useState(!1),C=En(),P=[{name:"Dashboard",href:"/",icon:Xe},{name:"Last Listened",href:"/last-listened",icon:vt},{name:"Mixed Playlist",href:"/mixed-playlist",icon:Ug},{name:"Memory Lane",href:"/memory-lane",icon:Yn}],j=()=>{u(),localStorage.removeItem("spotify-user"),localStorage.removeItem("spotify-partner")},D=async()=>{var E,W;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!((W=f==null?void 0:f.user)!=null&&W.id))&&confirm(`Are you sure you want to remove ${f.user.display_name} as your partner?`)){S(!0);try{await Pt("/partners/remove",{partnerId:f.user.id})}catch(X){try{await Pt("/partners/clear",{userId:d.user.id})}catch(te){console.error("Failed to remove partner:",X,te)}}finally{g(null),localStorage.removeItem("spotify-partner"),S(!1)}}},T=Vr(h);k.useEffect(()=>{Vr(h)},[h]),k.useEffect(()=>{if(n){const E=Math.min(600,window.innerWidth-40),W=Math.min(window.innerHeight*.9,800),X=(window.innerWidth-E)/2,te=(window.innerHeight-W)/2;i({x:X,y:te})}},[n]),k.useEffect(()=>{const E=X=>{o&&i({x:X.clientX-l.x,y:X.clientY-l.y})},W=()=>{a(!1)};return o&&(document.addEventListener("mousemove",E),document.addEventListener("mouseup",W)),()=>{document.removeEventListener("mousemove",E),document.removeEventListener("mouseup",W)}},[o,l]);const z=E=>{a(!0),c({x:E.clientX-s.x,y:E.clientY-s.y})};return m.jsxs(O.nav,{initial:{y:-100,opacity:0},animate:{y:0,opacity:1},className:"sticky top-0 z-50",style:{background:"rgba(0, 0, 0, 0.8)",backdropFilter:"blur(20px)",borderBottom:"1px solid rgba(255, 255, 255, 0.05)"},children:[m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:[m.jsxs("div",{className:"flex justify-between items-center h-16",children:[m.jsxs(zi,{to:"/",className:"flex items-center space-x-2",children:[m.jsx(O.div,{whileHover:{scale:1.1,rotate:5},className:"w-8 h-8 rounded-full flex items-center justify-center",style:{background:`linear-gradient(135deg, ${((V=T.cssVars)==null?void 0:V.primary)||"#1db954"} 0%, ${((U=T.cssVars)==null?void 0:U.secondary)||"#1ed760"} 100%)`},children:m.jsx(Xe,{className:"w-5 h-5 text-white"})}),m.jsx("span",{className:"text-xl font-bold gradient-text",children:"Our Musical Journey"})]}),m.jsx("div",{className:"hidden md:flex items-center space-x-1",children:P.map(E=>{var X,te,G,be;const W=C.pathname===E.href;return m.jsxs(zi,{to:E.href,className:Dh("flex items-center space-x-2 px-4 py-2 rounded-xl transition-all duration-300",W?"text-white":"text-white/60 hover:text-white hover:bg-white/5"),style:W?{background:`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`,border:`1px solid ${((G=T.cssVars)==null?void 0:G.primary)||"#1db954"}30`}:{},children:[m.jsx(E.icon,{className:"w-4 h-4",style:{color:W?(be=T.cssVars)==null?void 0:be.primary:void 0}}),m.jsx("span",{className:"font-medium",children:E.name})]},E.name)})}),m.jsxs("div",{className:"hidden md:flex items-center space-x-4",children:[!f&&m.jsxs("div",{className:"flex items-center space-x-2",children:[m.jsx("input",{value:x,onChange:E=>v(E.target.value),placeholder:"Partner Spotify ID",className:"bg-white/10 text-white text-sm px-2 py-1 rounded"}),m.jsx("button",{disabled:y||!x,onClick:async()=>{var E;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!x)){w(!0);try{await Pt("/partners/request",{toUid:x})}finally{w(!1)}}},className:`${T.primary} ${T.hover} text-white px-3 py-1 rounded text-sm disabled:opacity-50`,children:y?"Sending...":"Send Request"})]}),f&&m.jsxs(O.div,{initial:{scale:0},animate:{scale:1},className:"flex items-center space-x-2 text-sm text-white/70",children:[m.jsx(Ss,{className:"w-4 h-4"}),m.jsxs("span",{children:["+ ",(R=f.user)==null?void 0:R.display_name]})]}),m.jsxs(O.button,{whileHover:{scale:1.05},whileTap:{scale:.95},onClick:()=>r(!0),className:"flex items-center space-x-2 px-3 py-2 rounded-xl text-white/60 hover:text-white transition-all duration-300",style:{color:(Q=T.cssVars)==null?void 0:Q.primary},onMouseEnter:E=>{E.currentTarget.style.background="rgba(255, 255, 255, 0.05)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Mh,{className:"w-4 h-4"}),m.jsx("span",{className:"hidden lg:block",children:"Settings"})]}),m.jsxs(O.button,{whileHover:{scale:1.05},whileTap:{scale:.95},onClick:j,className:"flex items-center space-x-2 px-3 py-2 rounded-xl text-white/60 hover:text-white transition-all duration-300",onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Th,{className:"w-4 h-4"}),m.jsx("span",{className:"hidden lg:block",children:"Logout"})]})]}),m.jsx("button",{onClick:()=>t(!e),className:"md:hidden p-2 rounded-lg text-white/70 hover:text-white hover:bg-white/10 transition-all duration-300",children:e?m.jsx(_h,{className:"w-6 h-6"}):m.jsx(hk,{className:"w-6 h-6"})})]}),e&&m.jsx(O.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:"auto"},exit:{opacity:0,height:0},className:"md:hidden py-4 border-t border-white/10",children:m.jsxs("div",{className:"space-y-2",children:[P.map(E=>{var X,te,G,be;const W=C.pathname===E.href;return m.jsxs(zi,{to:E.href,onClick:()=>t(!1),className:Dh("flex items-center space-x-3 px-4 py-3 rounded-xl transition-all duration-300",W?"text-white":"text-white/60 hover:text-white hover:bg-white/5"),style:W?{background:`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`,border:`1px solid ${((G=T.cssVars)==null?void 0:G.primary)||"#1db954"}30`}:{},children:[m.jsx(E.icon,{className:"w-5 h-5",style:{color:W?(be=T.cssVars)==null?void 0:be.primary:void 0}}),m.jsx("span",{className:"font-medium",children:E.name})]},E.name)}),m.jsxs("div",{className:"pt-4 border-t border-white/10",children:[f&&m.jsxs("div",{className:"flex items-center space-x-3 px-4 py-2 text-sm text-white/70",children:[m.jsx(Ss,{className:"w-4 h-4"}),m.jsxs("span",{children:["Connected with ",(A=f.user)==null?void 0:A.display_name]})]}),m.jsxs("button",{onClick:()=>{r(!0),t(!1)},className:"w-full flex items-center space-x-3 px-4 py-3 rounded-xl text-white/60 hover:text-white transition-all duration-300",style:{color:(q=T.cssVars)==null?void 0:q.primary},onMouseEnter:E=>{E.currentTarget.style.background="rgba(255, 255, 255, 0.05)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Mh,{className:"w-5 h-5"}),m.jsx("span",{className:"font-medium",children:"Settings"})]}),m.jsxs("button",{onClick:j,className:"w-full flex items-center space-x-3 px-4 py-3 rounded-xl text-white/60 hover:text-white transition-all duration-300",onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Th,{className:"w-5 h-5"}),m.jsx("span",{className:"font-medium",children:"Logout"})]})]})]})})]}),n&&m.jsxs(m.Fragment,{children:[m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:"fixed inset-0 bg-black/50 backdrop-blur-md z-40",onClick:()=>r(!1)}),m.jsxs(O.div,{initial:{opacity:0,scale:.8,y:30},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.8,y:30},className:"fixed z-50 overflow-hidden",style:{left:s.x,top:s.y,width:Math.min(600,window.innerWidth-40),height:Math.min(window.innerHeight*.9,800),background:"linear-gradient(135deg, rgba(0,0,0,0.9) 0%, rgba(20,20,20,0.95) 50%, rgba(0,0,0,0.9) 100%)",backdropFilter:"blur(24px) saturate(180%)",WebkitBackdropFilter:"blur(24px) saturate(180%)",border:"1px solid rgba(255,255,255,0.2)",borderRadius:"16px",boxShadow:"0 25px 50px rgba(0,0,0,0.5)",cursor:o?"grabbing":"default"},children:[m.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-white/20 cursor-grab active:cursor-grabbing select-none",onMouseDown:z,style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsxs("div",{className:"flex items-center space-x-3",children:[m.jsxs("div",{className:"flex space-x-2",children:[m.jsx("div",{className:"w-3 h-3 rounded-full bg-red-500"}),m.jsx("div",{className:"w-3 h-3 rounded-full bg-yellow-500"}),m.jsx("div",{className:"w-3 h-3 rounded-full bg-green-500"})]}),m.jsx("h2",{className:"text-lg font-semibold text-white",children:"Settings"})]}),m.jsx("button",{onClick:()=>r(!1),className:"text-white/70 hover:text-white hover:bg-white/10 p-2 rounded-lg transition-all duration-200",children:m.jsx(_h,{className:"w-5 h-5"})})]}),m.jsx("div",{className:"overflow-y-auto p-4 sm:p-6",style:{height:"calc(100% - 60px)"},children:m.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[(d==null?void 0:d.user)&&m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Your Account"}),m.jsxs("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsx("div",{className:"text-sm text-white/70 mb-2 font-medium",children:"Spotify ID"}),m.jsx("div",{className:"text-white font-mono text-sm break-all rounded-lg p-3 mb-3",style:{background:"rgba(0,0,0,0.4)",border:"1px solid rgba(255,255,255,0.1)"},children:d.user.id}),m.jsxs("div",{className:"text-sm text-white/80",children:["Display Name: ",m.jsx("span",{className:"text-white font-medium",children:d.user.display_name})]})]})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Partner"}),f?m.jsx("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:m.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-3 sm:space-y-0",children:[m.jsxs("div",{className:"flex items-center space-x-3 sm:space-x-4",children:[m.jsx("div",{className:"w-10 h-10 sm:w-12 sm:h-12 bg-gradient-to-br from-purple-500 to-pink-500 rounded-full flex items-center justify-center shadow-lg",children:m.jsx(Ss,{className:"w-5 h-5 sm:w-6 sm:h-6 text-white"})}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("div",{className:"text-white font-semibold text-base sm:text-lg truncate",children:(_=f.user)==null?void 0:_.display_name}),m.jsx("div",{className:"text-xs text-white/70 break-all rounded px-2 py-1 mt-1 inline-block",style:{background:"rgba(0,0,0,0.3)",border:"1px solid rgba(255,255,255,0.1)"},children:(N=f.user)==null?void 0:N.id}),m.jsx("div",{className:"text-sm text-green-400 font-medium mt-2",children:"✓ Connected"})]})]}),m.jsxs("button",{onClick:D,disabled:b,className:"flex items-center space-x-2 p-2 sm:p-3 text-red-400 hover:text-red-300 rounded-xl transition-all duration-200 disabled:opacity-50 self-start sm:self-auto",style:{background:"rgba(239, 68, 68, 0.1)"},onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.2)"},onMouseLeave:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},children:[m.jsx(Wg,{className:"w-4 h-4 sm:w-5 sm:h-5"}),m.jsx("span",{className:"text-sm sm:hidden",children:"Remove"})]})]})}):m.jsxs("div",{className:"rounded-xl p-4 border border-white/20 space-y-4 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsxs("div",{children:[m.jsx("label",{className:"text-sm text-white/70 mb-2 block font-medium",children:"Partner Spotify ID"}),m.jsx("input",{value:x,onChange:E=>v(E.target.value),placeholder:"Enter partner's Spotify ID...",className:"w-full text-white text-sm px-4 py-3 rounded-xl placeholder-white/50 border focus:outline-none transition-all",style:{background:"rgba(0,0,0,0.4)",border:"1px solid rgba(255,255,255,0.2)"},onFocus:E=>{E.target.style.border="1px solid rgba(255,255,255,0.4)"},onBlur:E=>{E.target.style.border="1px solid rgba(255,255,255,0.2)"}})]}),m.jsx("button",{disabled:y||!x,onClick:async()=>{var E;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!x)){w(!0);try{await Pt("/partners/request",{toUid:x}),v("")}finally{w(!1)}}},className:"w-full text-white px-4 py-3 rounded-xl text-sm disabled:opacity-50 transition-all duration-200 font-medium",style:{background:`linear-gradient(135deg, ${((F=T.cssVars)==null?void 0:F.primary)||"#1db954"} 0%, ${((L=T.cssVars)==null?void 0:L.secondary)||"#1ed760"} 100%)`},onMouseEnter:E=>{var W;E.currentTarget.style.transform="translateY(-1px)",E.currentTarget.style.boxShadow=`0 8px 25px ${((W=T.cssVars)==null?void 0:W.primary)||"#1db954"}40`},onMouseLeave:E=>{E.currentTarget.style.transform="translateY(0)",E.currentTarget.style.boxShadow="none"},children:y?"Sending...":"Send Partner Request"})]})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Color Theme"}),m.jsx("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:m.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-3",children:[{name:"Green",value:"green",color:"from-green-500 to-emerald-500"},{name:"Pink",value:"pink",color:"from-pink-500 to-rose-500"},{name:"Blue",value:"blue",color:"from-blue-400 to-cyan-400"},{name:"Red",value:"red",color:"from-red-600 to-red-800"},{name:"Purple",value:"purple",color:"from-purple-500 to-violet-600"},{name:"Yellow",value:"yellow",color:"from-yellow-400 to-orange-500"},{name:"Turquoise",value:"turquoise",color:"from-cyan-400 to-blue-500"}].map(E=>{var W,X,te;return m.jsxs("button",{onClick:()=>p(E.value),className:"flex items-center space-x-3 p-3 rounded-xl border transition-all duration-200",style:{border:h===E.value?`2px solid ${((W=T.cssVars)==null?void 0:W.primary)||"#1db954"}`:"1px solid rgba(255,255,255,0.2)",background:h===E.value?`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`:"rgba(255,255,255,0.02)"},onMouseEnter:G=>{var be;h!==E.value?(G.currentTarget.style.background="rgba(255,255,255,0.08)",G.currentTarget.style.border="1px solid rgba(255,255,255,0.4)",G.currentTarget.style.transform="translateY(-2px)",G.currentTarget.style.boxShadow="0 4px 12px rgba(0,0,0,0.3)"):(G.currentTarget.style.transform="translateY(-1px)",G.currentTarget.style.boxShadow=`0 6px 20px ${((be=T.cssVars)==null?void 0:be.primary)||"#1db954"}30`)},onMouseLeave:G=>{h!==E.value?(G.currentTarget.style.background="rgba(255,255,255,0.02)",G.currentTarget.style.border="1px solid rgba(255,255,255,0.2)",G.currentTarget.style.transform="translateY(0)",G.currentTarget.style.boxShadow="none"):(G.currentTarget.style.transform="translateY(0)",G.currentTarget.style.boxShadow="none")},children:[m.jsx("div",{className:`w-5 h-5 rounded-full bg-gradient-to-r ${E.color} shadow-sm`}),m.jsx("span",{className:"text-white text-sm font-medium",children:E.name})]},E.value)})})})]})]})})]})]})]})};var Jg={exports:{}};(function(e){var t=function(){var n="https://api.spotify.com/v1",r=null,s=null,i=function(u,h){return u.abort=h,u},o=function(u,h){var p;if(s!==null){var g=s.defer();u(function(x){g.resolve(x)},function(x){g.reject(x)}),p=g.promise}else window.Promise&&(p=new window.Promise(u));return p?new i(p,h):null},a=function(){var u=Array.prototype.slice.call(arguments),h=u[0],p=u.slice(1);return h=h||{},p.forEach(function(g){for(var x in g)g.hasOwnProperty(x)&&(h[x]=g[x])}),h},l=function(u,h){var p="";for(var g in h)if(h.hasOwnProperty(g)){var x=h[g];p+=encodeURIComponent(g)+"="+encodeURIComponent(x)+"&"}return p.length>0&&(p=p.substring(0,p.length-1),u=u+"?"+p),u},c=function(u,h){var p=new XMLHttpRequest,g=function(x,v){function y(C){x&&x(C),h&&h(null,C)}function w(){v&&v(p),h&&h(p,null)}var b=u.type||"GET";if(p.open(b,l(u.url,u.params)),r&&p.setRequestHeader("Authorization","Bearer "+r),p.onreadystatechange=function(){if(p.readyState===4){var C=null;try{C=p.responseText?JSON.parse(p.responseText):""}catch(P){console.error(P)}p.status>=200&&p.status<300?y(C):w()}},b==="GET")p.send(null);else{var S=null;u.postData&&(u.contentType==="image/jpeg"?(S=u.postData,p.setRequestHeader("Content-Type",u.contentType)):(S=JSON.stringify(u.postData),p.setRequestHeader("Content-Type","application/json"))),p.send(S)}};return h?(g(),null):o(g,function(){p.abort()})},d=function(u,h,p,g){var x={},v=null;typeof h=="object"?(x=h,v=p):typeof h=="function"&&(v=h);var y=u.type||"GET";return y!=="GET"&&u.postData&&!g?u.postData=a(u.postData,x):u.params=a(u.params,x),c(u,v)},f=function(){};return f.prototype={constructor:t},f.prototype.getGeneric=function(u,h){var p={url:u};return d(p,h)},f.prototype.getMe=function(u,h){var p={url:n+"/me"};return d(p,u,h)},f.prototype.getMySavedTracks=function(u,h){var p={url:n+"/me/tracks"};return d(p,u,h)},f.prototype.addToMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMySavedAlbums=function(u,h){var p={url:n+"/me/albums"};return d(p,u,h)},f.prototype.addToMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMyTopArtists=function(u,h){var p={url:n+"/me/top/artists"};return d(p,u,h)},f.prototype.getMyTopTracks=function(u,h){var p={url:n+"/me/top/tracks"};return d(p,u,h)},f.prototype.getMyRecentlyPlayedTracks=function(u,h){var p={url:n+"/me/player/recently-played"};return d(p,u,h)},f.prototype.followUsers=function(u,h){var p={url:n+"/me/following/",type:"PUT",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.followArtists=function(u,h){var p={url:n+"/me/following/",type:"PUT",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.followPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/followers",type:"PUT",postData:{}};return d(g,h,p)},f.prototype.unfollowUsers=function(u,h){var p={url:n+"/me/following/",type:"DELETE",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.unfollowArtists=function(u,h){var p={url:n+"/me/following/",type:"DELETE",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.unfollowPlaylist=function(u,h){var p={url:n+"/playlists/"+u+"/followers",type:"DELETE"};return d(p,h)},f.prototype.isFollowingUsers=function(u,h){var p={url:n+"/me/following/contains",type:"GET",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.isFollowingArtists=function(u,h){var p={url:n+"/me/following/contains",type:"GET",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.areFollowingPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/followers/contains",type:"GET",params:{ids:h.join(",")}};return d(g,p)},f.prototype.getFollowedArtists=function(u,h){var p={url:n+"/me/following",type:"GET",params:{type:"artist"}};return d(p,u,h)},f.prototype.getUser=function(u,h,p){var g={url:n+"/users/"+encodeURIComponent(u)};return d(g,h,p)},f.prototype.getUserPlaylists=function(u,h,p){var g;return typeof u=="string"?g={url:n+"/users/"+encodeURIComponent(u)+"/playlists"}:(g={url:n+"/me/playlists"},p=h,h=u),d(g,h,p)},f.prototype.getPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u};return d(g,h,p)},f.prototype.getPlaylistTracks=function(u,h,p){var g={url:n+"/playlists/"+u+"/tracks"};return d(g,h,p)},f.prototype.getPlaylistCoverImage=function(u,h){var p={url:n+"/playlists/"+u+"/images"};return d(p,h)},f.prototype.createPlaylist=function(u,h,p){var g={url:n+"/users/"+encodeURIComponent(u)+"/playlists",type:"POST",postData:h};return d(g,h,p)},f.prototype.changePlaylistDetails=function(u,h,p){var g={url:n+"/playlists/"+u,type:"PUT",postData:h};return d(g,h,p)},f.prototype.addTracksToPlaylist=function(u,h,p,g){var x={url:n+"/playlists/"+u+"/tracks",type:"POST",postData:{uris:h}};return d(x,p,g,!0)},f.prototype.replaceTracksInPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/tracks",type:"PUT",postData:{uris:h}};return d(g,{},p)},f.prototype.reorderTracksInPlaylist=function(u,h,p,g,x){var v={url:n+"/playlists/"+u+"/tracks",type:"PUT",postData:{range_start:h,insert_before:p}};return d(v,g,x)},f.prototype.removeTracksFromPlaylist=function(u,h,p){var g=h.map(function(v){return typeof v=="string"?{uri:v}:v}),x={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{tracks:g}};return d(x,{},p)},f.prototype.removeTracksFromPlaylistWithSnapshotId=function(u,h,p,g){var x=h.map(function(y){return typeof y=="string"?{uri:y}:y}),v={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{tracks:x,snapshot_id:p}};return d(v,{},g)},f.prototype.removeTracksFromPlaylistInPositions=function(u,h,p,g){var x={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{positions:h,snapshot_id:p}};return d(x,{},g)},f.prototype.uploadCustomPlaylistCoverImage=function(u,h,p){var g={url:n+"/playlists/"+u+"/images",type:"PUT",postData:h.replace(/^data:image\/jpeg;base64,/,""),contentType:"image/jpeg"};return d(g,{},p)},f.prototype.getAlbum=function(u,h,p){var g={url:n+"/albums/"+u};return d(g,h,p)},f.prototype.getAlbumTracks=function(u,h,p){var g={url:n+"/albums/"+u+"/tracks"};return d(g,h,p)},f.prototype.getAlbums=function(u,h,p){var g={url:n+"/albums/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getTrack=function(u,h,p){var g={};return g.url=n+"/tracks/"+u,d(g,h,p)},f.prototype.getTracks=function(u,h,p){var g={url:n+"/tracks/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getArtist=function(u,h,p){var g={url:n+"/artists/"+u};return d(g,h,p)},f.prototype.getArtists=function(u,h,p){var g={url:n+"/artists/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getArtistAlbums=function(u,h,p){var g={url:n+"/artists/"+u+"/albums"};return d(g,h,p)},f.prototype.getArtistTopTracks=function(u,h,p,g){var x={url:n+"/artists/"+u+"/top-tracks",params:{country:h}};return d(x,p,g)},f.prototype.getArtistRelatedArtists=function(u,h,p){var g={url:n+"/artists/"+u+"/related-artists"};return d(g,h,p)},f.prototype.getFeaturedPlaylists=function(u,h){var p={url:n+"/browse/featured-playlists"};return d(p,u,h)},f.prototype.getNewReleases=function(u,h){var p={url:n+"/browse/new-releases"};return d(p,u,h)},f.prototype.getCategories=function(u,h){var p={url:n+"/browse/categories"};return d(p,u,h)},f.prototype.getCategory=function(u,h,p){var g={url:n+"/browse/categories/"+u};return d(g,h,p)},f.prototype.getCategoryPlaylists=function(u,h,p){var g={url:n+"/browse/categories/"+u+"/playlists"};return d(g,h,p)},f.prototype.search=function(u,h,p,g){var x={url:n+"/search/",params:{q:u,type:h.join(",")}};return d(x,p,g)},f.prototype.searchAlbums=function(u,h,p){return this.search(u,["album"],h,p)},f.prototype.searchArtists=function(u,h,p){return this.search(u,["artist"],h,p)},f.prototype.searchTracks=function(u,h,p){return this.search(u,["track"],h,p)},f.prototype.searchPlaylists=function(u,h,p){return this.search(u,["playlist"],h,p)},f.prototype.searchShows=function(u,h,p){return this.search(u,["show"],h,p)},f.prototype.searchEpisodes=function(u,h,p){return this.search(u,["episode"],h,p)},f.prototype.getAudioFeaturesForTrack=function(u,h){var p={};return p.url=n+"/audio-features/"+u,d(p,{},h)},f.prototype.getAudioFeaturesForTracks=function(u,h){var p={url:n+"/audio-features",params:{ids:u}};return d(p,{},h)},f.prototype.getAudioAnalysisForTrack=function(u,h){var p={};return p.url=n+"/audio-analysis/"+u,d(p,{},h)},f.prototype.getRecommendations=function(u,h){var p={url:n+"/recommendations"};return d(p,u,h)},f.prototype.getAvailableGenreSeeds=function(u){var h={url:n+"/recommendations/available-genre-seeds"};return d(h,{},u)},f.prototype.getMyDevices=function(u){var h={url:n+"/me/player/devices"};return d(h,{},u)},f.prototype.getMyCurrentPlaybackState=function(u,h){var p={url:n+"/me/player"};return d(p,u,h)},f.prototype.getMyCurrentPlayingTrack=function(u,h){var p={url:n+"/me/player/currently-playing"};return d(p,u,h)},f.prototype.transferMyPlayback=function(u,h,p){var g=h||{};g.device_ids=u;var x={type:"PUT",url:n+"/me/player",postData:g};return d(x,h,p)},f.prototype.play=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={};["context_uri","uris","offset","position_ms"].forEach(function(y){y in u&&(g[y]=u[y])});var x={type:"PUT",url:n+"/me/player/play",params:p,postData:g},v=typeof u=="function"?u:{};return d(x,v,h)},f.prototype.queue=function(u,h,p){h=h||{};var g="device_id"in h?{uri:u,device_id:h.device_id}:{uri:u},x={type:"POST",url:n+"/me/player/queue",params:g};return d(x,h,p)},f.prototype.pause=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"PUT",url:n+"/me/player/pause",params:p};return d(g,u,h)},f.prototype.skipToNext=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"POST",url:n+"/me/player/next",params:p};return d(g,u,h)},f.prototype.skipToPrevious=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"POST",url:n+"/me/player/previous",params:p};return d(g,u,h)},f.prototype.seek=function(u,h,p){h=h||{};var g={position_ms:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/seek",params:g};return d(x,h,p)},f.prototype.setRepeat=function(u,h,p){h=h||{};var g={state:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/repeat",params:g};return d(x,h,p)},f.prototype.setVolume=function(u,h,p){h=h||{};var g={volume_percent:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/volume",params:g};return d(x,h,p)},f.prototype.setShuffle=function(u,h,p){h=h||{};var g={state:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/shuffle",params:g};return d(x,h,p)},f.prototype.getShow=function(u,h,p){var g={};return g.url=n+"/shows/"+u,d(g,h,p)},f.prototype.getShows=function(u,h,p){var g={url:n+"/shows/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMySavedShows=function(u,h){var p={url:n+"/me/shows"};return d(p,u,h)},f.prototype.addToMySavedShows=function(u,h,p){var g={url:n+"/me/shows",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedShows=function(u,h,p){var g={url:n+"/me/shows",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedShows=function(u,h,p){var g={url:n+"/me/shows/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getShowEpisodes=function(u,h,p){var g={url:n+"/shows/"+u+"/episodes"};return d(g,h,p)},f.prototype.getEpisode=function(u,h,p){var g={};return g.url=n+"/episodes/"+u,d(g,h,p)},f.prototype.getEpisodes=function(u,h,p){var g={url:n+"/episodes/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getAccessToken=function(){return r},f.prototype.setAccessToken=function(u){r=u},f.prototype.setPromiseImplementation=function(u){var h=!1;try{var p=new u(function(g){g()});typeof p.then=="function"&&typeof p.catch=="function"&&(h=!0)}catch(g){console.error(g)}if(h)s=u;else throw new Error("Unsupported implementation of Promises/A+")},f}();e.exports=t})(Jg);var e6=Jg.exports;const t6=cu(e6),n6="7cab80d02df44a5bb96725be60a45875",ey="https://159.195.9.107:3443/callback.html";console.log("🔍 Debug - Current redirect URI:",ey);console.log("🔍 Debug - Environment VITE_REDIRECT_URI:","https://159.195.9.107:3443/callback.html");const jo=new t6,r6=()=>{const e=["user-read-private","user-read-email","user-read-recently-played","user-top-read","playlist-read-private","playlist-read-collaborative","playlist-modify-public","playlist-modify-private","user-read-playback-state","user-modify-playback-state","user-read-currently-playing"].join(" "),n=`https://accounts.spotify.com/authorize?${new URLSearchParams({client_id:n6,response_type:"code",redirect_uri:ey,scope:e,show_dialog:"true"}).toString()}`;return console.log("🔍 Debug - Generated Spotify Auth URL:",n),n},s6=async(e,t)=>{jo.setAccessToken(e),await jo.play({uris:[t]})},i6=async e=>{jo.setAccessToken(e),await jo.pause()},o6=()=>{const[e,t]=k.useState(!1),n=()=>{t(!0),window.location.href=r6()},r=[{icon:vt,title:"Last Listened",description:"Discover what your partner is listening to right now and play it instantly"},{icon:Yn,title:"Mixed Playlist",description:"AI-powered playlists that blend your musical tastes perfectly"},{icon:Xe,title:"Memory Lane",description:"Create beautiful musical memories and shared experiences together"}];return m.jsx("div",{className:"min-h-screen flex items-center justify-center px-4 bg-black",children:m.jsxs("div",{className:"max-w-4xl w-full relative",children:[m.jsxs(O.div,{initial:{opacity:0,y:50},animate:{opacity:1,y:0},transition:{duration:.8},className:"text-center mb-12",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:.2,type:"spring",stiffness:200},className:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-pink-500 to-red-500 rounded-full flex items-center justify-center",children:m.jsx(Xe,{className:"w-10 h-10 text-white"})}),m.jsxs("h1",{className:"text-5xl md:text-6xl font-bold mb-4",children:[m.jsx("span",{className:"gradient-text",children:"Our Musical"}),m.jsx("br",{}),m.jsx("span",{className:"text-white",children:"Journey"})]}),m.jsx("p",{className:"text-xl text-white/70 max-w-2xl mx-auto leading-relaxed",children:"A private space where two hearts connect through music. Discover, share, and create beautiful musical memories together."})]}),m.jsx(O.div,{initial:{opacity:0,y:30},animate:{opacity:1,y:0},transition:{delay:.4,duration:.8},className:"grid md:grid-cols-3 gap-6 mb-12",children:r.map((s,i)=>m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5+i*.1},whileHover:{y:-8,scale:1.03},className:"glass-bubble rounded-3xl p-8 text-center group cursor-pointer",children:[m.jsx(O.div,{whileHover:{rotate:15,scale:1.15},className:"w-16 h-16 mx-auto mb-6 bg-gradient-to-br from-purple-500/30 via-blue-500/30 to-pink-500/30 rounded-2xl flex items-center justify-center backdrop-blur-sm",children:m.jsx(s.icon,{className:"w-8 h-8 text-white"})}),m.jsx("h3",{className:"text-2xl font-bold text-white mb-3",children:s.title}),m.jsx("p",{className:"text-white/70 text-sm leading-relaxed",children:s.description})]},s.title))}),m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},transition:{delay:.8,duration:.6},className:"glass-fluid rounded-3xl p-10 max-w-lg mx-auto",children:[m.jsxs("div",{className:"text-center mb-8",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:1,type:"spring",stiffness:200},className:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-purple-500/30 via-blue-500/30 to-pink-500/30 rounded-2xl flex items-center justify-center backdrop-blur-sm",children:m.jsx(Hg,{className:"w-10 h-10 text-white"})}),m.jsx("h2",{className:"text-3xl font-bold text-white mb-3",children:"Begin Your Journey"}),m.jsx("p",{className:"text-white/70 text-lg",children:"Connect your Spotify account to start your musical love story"})]}),m.jsx(O.button,{whileHover:{scale:1.05,boxShadow:"0 15px 40px rgba(147, 51, 234, 0.4)"},whileTap:{scale:.95},onClick:n,disabled:e,className:"w-full bg-gradient-to-r from-purple-600 via-blue-600 to-pink-600 hover:from-purple-700 hover:via-blue-700 hover:to-pink-700 text-white font-bold py-5 px-8 rounded-2xl transition-all duration-300 flex items-center justify-center space-x-3 disabled:opacity-50 shadow-2xl",children:e?m.jsx("div",{className:"w-6 h-6 border-2 border-white border-t-transparent rounded-full animate-spin"}):m.jsxs(m.Fragment,{children:[m.jsx("span",{className:"text-lg",children:"Connect with Spotify"}),m.jsx(lk,{className:"w-6 h-6"})]})}),m.jsx("p",{className:"text-sm text-white/60 text-center mt-6 leading-relaxed",children:"We'll only access your listening history and playlist data to create your personalized musical journey"})]}),m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},transition:{delay:1,duration:.6},className:"text-center mt-12",children:m.jsx("p",{className:"text-white/40 text-sm",children:"Made with 💕 for a special someone"})})]})})},a6=()=>{var P,j,D,T,z,V,U,R,Q,A,q,_,N,F,L,E,W,X,te,G,be,ri,Jn,Mn,wt,ta,Dc;const{currentUser:e,partnerUser:t,theme:n}=ae(),r=Vr(n),[s,i]=k.useState([]),[o,a]=k.useState(!1),[l,c]=k.useState(null),[d,f]=k.useState(""),[u,h]=k.useState(!1),[p,g]=k.useState(null),[x,v]=k.useState(null);k.useEffect(()=>{let $;const me=async()=>{var Pe,Te,nt;try{const er=(Pe=e==null?void 0:e.user)==null?void 0:Pe.id;if(er){const na=await se(`/users/${er}/recently-played`),Wr=ae.getState().currentUser;Wr&&ae.getState().setCurrentUser({...Wr,recentlyPlayed:na})}const Rc=(nt=(Te=ae.getState().partnerUser)==null?void 0:Te.user)==null?void 0:nt.id;if(Rc){const na=await se(`/users/${Rc}/recently-played`),Wr=ae.getState().partnerUser;Wr&&ae.getState().setPartnerUser({...Wr,recentlyPlayed:na})}}catch{}$=setTimeout(me,3e4)};return me(),()=>clearTimeout($)},[(P=e==null?void 0:e.user)==null?void 0:P.id,(j=t==null?void 0:t.user)==null?void 0:j.id]),k.useEffect(()=>{(async()=>{var me;if((me=e==null?void 0:e.user)!=null&&me.id){a(!0);try{const Pe=await se(`/partners/requests/${e.user.id}`);i(Pe)}catch{i([])}finally{a(!1)}}})()},[(D=e==null?void 0:e.user)==null?void 0:D.id]),k.useEffect(()=>{let $;const me=async()=>{var Te;if((Te=e==null?void 0:e.user)!=null&&Te.id)try{const nt=await se(`/users/${e.user.id}/status`);c(nt)}catch{}},Pe=()=>{if(!(l!=null&&l.nextSyncAt)){f("");return}const Te=l.nextSyncAt-Date.now();if(Te<=0){f("now");return}const nt=Math.floor(Te/6e4),er=Math.floor(Te%6e4/1e3);f(`${nt}m ${er}s`)};return me(),$=setInterval(()=>{Pe()},1e3),()=>clearInterval($)},[(T=e==null?void 0:e.user)==null?void 0:T.id,l==null?void 0:l.nextSyncAt]),k.useEffect(()=>{let $;const me=async()=>{var Pe,Te;try{const nt=(Pe=e==null?void 0:e.user)==null?void 0:Pe.id;nt&&(g(await se(`/users/${nt}/now-playing`)),(Te=t==null?void 0:t.user)!=null&&Te.id?v(await se(`/users/${t.user.id}/now-playing`)):v(null))}catch{}$=setTimeout(me,8e3)};return me(),()=>clearTimeout($)},[(z=e==null?void 0:e.user)==null?void 0:z.id,(V=t==null?void 0:t.user)==null?void 0:V.id]);const y=async()=>{var $;if(($=e==null?void 0:e.user)!=null&&$.id){h(!0);try{await Pt(`/users/${e.user.id}/sync`);const me=await se(`/users/${e.user.id}/status`);c(me);const[Pe,Te]=await Promise.all([se(`/users/${e.user.id}/recently-played`),se(`/users/${e.user.id}/top-tracks?time_range=short_term`)]),nt=ae.getState().currentUser;nt&&ae.getState().setCurrentUser({...nt,recentlyPlayed:Pe,topTracks:Te.map(er=>er.track)}),he.success("Synced latest data")}catch{he.error("Failed to sync")}finally{h(!1)}}},w=async $=>{await Pt(`/partners/requests/${$}/accept`),i(me=>me.filter(Pe=>Pe.id!==$))},b=async $=>{await Pt(`/partners/requests/${$}/decline`),i(me=>me.filter(Pe=>Pe.id!==$))},S=[{title:"Last Listened",description:"See what your partner is listening to right now",icon:vt,href:"/last-listened",primaryColor:((U=r.cssVars)==null?void 0:U.primary)||"#1db954",secondaryColor:((R=r.cssVars)==null?void 0:R.secondary)||"#1ed760",accentColor:((Q=r.cssVars)==null?void 0:Q.accent)||"#00e676"},{title:"Mixed Playlist",description:"Create AI-powered playlists blending both your tastes",icon:Ug,href:"/mixed-playlist",primaryColor:((A=r.cssVars)==null?void 0:A.secondary)||"#1ed760",secondaryColor:((q=r.cssVars)==null?void 0:q.accent)||"#00e676",accentColor:((_=r.cssVars)==null?void 0:_.primary)||"#1db954"},{title:"Memory Lane",description:"Your shared musical journey and memories",icon:Yn,href:"/memory-lane",primaryColor:((N=r.cssVars)==null?void 0:N.accent)||"#00e676",secondaryColor:((F=r.cssVars)==null?void 0:F.primary)||"#1db954",accentColor:((L=r.cssVars)==null?void 0:L.secondary)||"#1ed760"}],C=()=>{var $;return($=e==null?void 0:e.recentlyPlayed)!=null&&$[0]?Pr(e.recentlyPlayed[0].played_at):null};return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2",children:["Welcome back, ",m.jsx("span",{className:"gradient-text",children:(E=e==null?void 0:e.user)==null?void 0:E.display_name})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"Ready to explore your musical connection together?"})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"grid md:grid-cols-2 gap-6 mb-8",children:[m.jsxs("div",{className:"glass rounded-2xl p-6",children:[m.jsx("div",{className:"text-white/70 mb-2",children:"You"}),p!=null&&p.is_playing&&(p!=null&&p.item)?m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("img",{src:((te=(X=(W=p.item.album)==null?void 0:W.images)==null?void 0:X[0])==null?void 0:te.url)||"/placeholder-album.png",className:"w-14 h-14 rounded"}),m.jsxs("div",{className:"min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:p.item.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(G=p.item.artists)==null?void 0:G.map($=>$.name).join(", ")})]})]}):m.jsx("div",{className:"text-white/50",children:"Not playing"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6",children:[m.jsx("div",{className:"text-white/70 mb-2",children:"Partner"}),x!=null&&x.is_playing&&(x!=null&&x.item)?m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("img",{src:((Jn=(ri=(be=x.item.album)==null?void 0:be.images)==null?void 0:ri[0])==null?void 0:Jn.url)||"/placeholder-album.png",className:"w-14 h-14 rounded"}),m.jsxs("div",{className:"min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:x.item.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(Mn=x.item.artists)==null?void 0:Mn.map($=>$.name).join(", ")})]})]}):m.jsx("div",{className:"text-white/50",children:"Not playing"})]})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.1},className:"mb-8",children:[m.jsxs("div",{className:"flex items-center justify-between mb-4",children:[m.jsx("div",{className:"text-white/70 text-sm",children:(l==null?void 0:l.lastSyncedAt)&&m.jsxs("span",{children:["Last sync: ",new Date(l.lastSyncedAt).toLocaleTimeString()," • Next in: ",d||"—"]})}),m.jsx("button",{onClick:y,disabled:u,className:"bg-white/10 hover:bg-white/20 text-white px-4 py-2 rounded-lg text-sm disabled:opacity-50",children:u?"Refreshing…":"Hard Refresh"})]}),t?m.jsx("div",{className:"glass-bubble rounded-3xl p-8 border border-spotify-green/30 glow",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsx("div",{className:"w-16 h-16 bg-gradient-to-br from-spotify-green to-green-600 rounded-2xl flex items-center justify-center",children:m.jsx(Xe,{className:"w-8 h-8 text-white"})}),m.jsxs("div",{children:[m.jsxs("h3",{className:"text-xl font-semibold text-white",children:["Connected with ",(wt=t.user)==null?void 0:wt.display_name]}),m.jsx("p",{className:"text-white/70",children:"Your musical journey is ready to begin! 💕"})]})]})}):m.jsx("div",{className:"glass-bubble rounded-3xl p-8 border border-orange-500/30",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsx("div",{className:"w-16 h-16 bg-gradient-to-br from-orange-500 to-red-500 rounded-2xl flex items-center justify-center",children:m.jsx(Ac,{className:"w-8 h-8 text-white"})}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-xl font-semibold text-white",children:"Invite your partner"}),m.jsx("p",{className:"text-white/70 mb-2",children:"Ask your partner to search you in the app and send a request."}),o?m.jsx("div",{className:"text-white/60",children:"Loading requests..."}):s.length>0?m.jsx("div",{className:"space-y-3",children:s.map($=>m.jsxs("div",{className:"flex items-center justify-between bg-white/5 rounded-lg p-3",children:[m.jsxs("div",{className:"text-white/80 text-sm",children:["Request from ",$.from_user_id]}),m.jsxs("div",{className:"space-x-2",children:[m.jsx("button",{onClick:()=>w($.id),className:"bg-spotify-green hover:bg-spotify-green/90 text-white px-3 py-1 rounded-md text-sm",children:"Accept"}),m.jsx("button",{onClick:()=>b($.id),className:"bg-white/10 hover:bg-white/20 text-white px-3 py-1 rounded-md text-sm",children:"Decline"})]})]},$.id))}):m.jsx("div",{className:"text-white/60 text-sm",children:"No incoming requests yet"})]})]})})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.2},className:"grid grid-cols-1 md:grid-cols-3 gap-6 mb-8",children:[m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-blue-500/30 to-cyan-500/30 rounded-xl flex items-center justify-center",children:m.jsx(Po,{className:"w-6 h-6 text-blue-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Your last played"}),m.jsx("p",{className:"text-white font-semibold",children:C()||"No recent plays"})]})]})}),m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-green-500/30 to-emerald-500/30 rounded-xl flex items-center justify-center",children:m.jsx(gk,{className:"w-6 h-6 text-green-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Top tracks analyzed"}),m.jsxs("p",{className:"text-white font-semibold",children:[((ta=e==null?void 0:e.topTracks)==null?void 0:ta.length)||0," songs"]})]})]})}),m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-purple-500/30 to-pink-500/30 rounded-xl flex items-center justify-center",children:m.jsx(Ss,{className:"w-6 h-6 text-purple-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Recently played"}),m.jsxs("p",{className:"text-white font-semibold",children:[((Dc=e==null?void 0:e.recentlyPlayed)==null?void 0:Dc.length)||0," tracks"]})]})]})})]}),m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},className:"grid md:grid-cols-3 gap-6",children:S.map(($,me)=>m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.4+me*.1},whileHover:{y:-5,scale:1.02},children:m.jsx(zi,{to:$.href,children:m.jsxs("div",{className:`glass rounded-2xl p-6 h-full border ${$.borderColor} group cursor-pointer transition-all duration-300 hover:shadow-xl`,children:[m.jsx("div",{className:"w-12 h-12 rounded-xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300",style:{background:`linear-gradient(135deg, ${$.primaryColor}20 0%, ${$.secondaryColor}10 100%)`,border:`1px solid ${$.primaryColor}30`},children:m.jsx($.icon,{className:"w-6 h-6",style:{color:$.primaryColor}})}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:$.title}),m.jsx("p",{className:"text-white/70 text-sm leading-relaxed mb-4",children:$.description}),m.jsx("div",{className:"w-full h-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300",style:{background:`linear-gradient(90deg, ${$.primaryColor} 0%, ${$.secondaryColor} 100%)`}})]})})},$.title))}),(e==null?void 0:e.recentlyPlayed)&&e.recentlyPlayed.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.6},className:"mt-8",children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"Your Recent Activity"}),m.jsx("div",{className:"glass rounded-2xl p-6",children:m.jsx("div",{className:"space-y-4",children:e.recentlyPlayed.slice(0,3).map(($,me)=>{var Pe,Te;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:.7+me*.1},className:"flex items-center space-x-4 p-3 rounded-lg hover:bg-white/5 transition-colors",children:[m.jsx("img",{src:((Pe=$.track.album.images[0])==null?void 0:Pe.url)||"/placeholder-album.png",alt:$.track.album.name,className:"w-12 h-12 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h4",{className:"text-white font-medium",children:$.track.name}),m.jsx("p",{className:"text-white/70 text-sm",children:(Te=$.track.artists[0])==null?void 0:Te.name})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Pr($.played_at)})]},$.track.id)})})})]})]})};let ji=!1;const Rh=()=>{const[e]=Ax(),t=Wo(),{setCurrentUser:n,setPartnerUser:r,currentUser:s}=ae(),[i,o]=k.useState("loading"),[a,l]=k.useState("");k.useEffect(()=>{(async()=>{if(ji){console.log("🔍 CallbackPage - Already processing globally, skipping...");return}ji=!0,console.log("🔍 CallbackPage - Global processing flag set to TRUE");try{const u=e.get("code"),h=e.get("error");if(console.log("🔍 CallbackPage - Code:",u),console.log("🔍 CallbackPage - Error:",h),h)throw new Error("Spotify authorization was denied");if(!u)throw new Error("No authorization code received");l("Exchanging authorization code..."),console.log("🔍 CallbackPage - Exchanging code with backend...");const p=await pb("/auth/exchange",{code:u});l("Syncing your music data..."),await Pt(`/users/${p.uid}/sync`,void 0,p.token),l("Loading your profile...");const[g,x,v]=await Promise.all([se(`/users/${p.uid}`),se(`/users/${p.uid}/recently-played`),se(`/users/${p.uid}/top-tracks?time_range=short_term`)]),y={user:g,accessToken:p.access_token,refreshToken:p.refresh_token,isAuthenticated:!0,recentlyPlayed:x,topTracks:v.map(w=>w.track),topArtists:[],jwt:p.token};localStorage.setItem("spotify-user",JSON.stringify(y)),s?(r(y),localStorage.setItem("spotify-partner",JSON.stringify(y)),l("Partner connected! Your musical journey begins...")):(n(y),l("Welcome! Setting up your musical journey...")),o("success"),he.success(s?"Partner connected successfully!":"Successfully connected to Spotify!",{duration:3e3}),setTimeout(()=>{t("/"),setTimeout(()=>{ji=!1,console.log("🔍 CallbackPage - Global processing flag set to FALSE (after success)")},1e3)},2e3)}catch(u){console.error("🔍 CallbackPage - ERROR:",u),console.error("🔍 CallbackPage - Error details:",{message:u instanceof Error?u.message:"Unknown error",stack:u instanceof Error?u.stack:void 0}),o("error"),l(u instanceof Error?u.message:"An unexpected error occurred"),he.error("Failed to connect to Spotify. Please try again."),setTimeout(()=>{t("/"),setTimeout(()=>{ji=!1,console.log("🔍 CallbackPage - Global processing flag set to FALSE (after error)")},1e3)},3e3)}})()},[e,t,n,r,s]);const c=()=>{switch(i){case"loading":return m.jsx(fk,{className:"w-12 h-12 text-spotify-green animate-spin"});case"success":return m.jsx(dk,{className:"w-12 h-12 text-green-400"});case"error":return m.jsx(xk,{className:"w-12 h-12 text-red-400"})}},d=()=>{switch(i){case"loading":return"border-spotify-green/30";case"success":return"border-green-400/30";case"error":return"border-red-400/30"}};return m.jsx("div",{className:"min-h-screen flex items-center justify-center px-4 bg-black",children:m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},className:"glass-fluid rounded-3xl p-10 max-w-md w-full text-center",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:.2,type:"spring",stiffness:200},className:`w-20 h-20 mx-auto mb-6 rounded-full border-2 flex items-center justify-center ${d()}`,children:c()}),m.jsxs(O.h2,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},className:"text-2xl font-bold text-white mb-4",children:[i==="loading"&&"Connecting...",i==="success"&&"Success!",i==="error"&&"Connection Failed"]}),m.jsx(O.p,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.4},className:"text-white/70 mb-6",children:a}),i==="loading"&&m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},transition:{delay:.5},className:"w-full bg-white/10 rounded-full h-2 mb-4",children:m.jsx(O.div,{className:"bg-spotify-green h-2 rounded-full",initial:{width:0},animate:{width:"100%"},transition:{duration:3,ease:"easeInOut"}})}),i==="error"&&m.jsx(O.button,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},whileHover:{scale:1.05},whileTap:{scale:.95},onClick:()=>t("/"),className:"bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-300",children:"Try Again"}),i==="success"&&m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},className:"text-spotify-green text-sm",children:"Redirecting you to your musical journey..."})]})})},l6=()=>{var g,x,v;const{currentUser:e,partnerUser:t,currentTrack:n,isPlaying:r,setCurrentTrack:s,setIsPlaying:i,theme:o}=ae(),a=Vr(o),[l,c]=k.useState(!1),[d,f]=k.useState(null),u=k.useMemo(()=>{const y=((e==null?void 0:e.recentlyPlayed)||[]).map(P=>({who:"you",played_at:new Date(P.played_at).getTime(),track:P.track,key:`you-${P.track.id}-${P.played_at}`})),w=((t==null?void 0:t.recentlyPlayed)||[]).map(P=>({who:"partner",played_at:new Date(P.played_at).getTime(),track:P.track,key:`partner-${P.track.id}-${P.played_at}`})),b=[...y,...w].sort((P,j)=>j.played_at-P.played_at).slice(0,30),S=new Set,C=new Set;return b.forEach(P=>{const j=P.track.id;S.has(j)?C.add(j):S.add(j)}),{items:b,overlaps:C}},[e==null?void 0:e.recentlyPlayed,t==null?void 0:t.recentlyPlayed]),h=async(y,w)=>{var b,S;if(!(e!=null&&e.accessToken)){he.error("Not authenticated with Spotify");return}try{c(!0),f(w),r&&d===w?(await i6(e.accessToken),i(!1),s(null),f(null)):(await s6(e.accessToken,y),i(!0),s(((S=(b=e.recentlyPlayed)==null?void 0:b.find(C=>C.track.id===w))==null?void 0:S.track)||null)),he.success(r&&d===w?"Paused":"Now playing")}catch(C){console.error("Playback error:",C),he.error("Failed to play track. Make sure Spotify is open on your device.")}finally{c(!1)}},p=({user:y,title:w,isPartner:b=!1})=>{var C,P,j,D,T;if(!((C=y==null?void 0:y.recentlyPlayed)!=null&&C.length))return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 text-center",children:[m.jsx(vt,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No recent activity"}),m.jsxs("p",{className:"text-white/70",children:[b?"Your partner":"You"," haven't played any music recently"]})]});const S=y.recentlyPlayed[0];return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-6",children:[m.jsxs("div",{className:"flex items-center space-x-4 mb-6",children:[m.jsx("div",{className:`w-12 h-12 rounded-full flex items-center justify-center ${b?"bg-gradient-to-br from-pink-500 to-purple-600":"bg-gradient-to-br from-blue-500 to-cyan-600"}`,children:m.jsx(Ss,{className:"w-6 h-6 text-white"})}),m.jsxs("div",{children:[m.jsx("h2",{className:"text-2xl font-bold text-white",children:w}),m.jsxs("p",{className:"text-white/70",children:["Last played: ",Pr(S.played_at)]})]})]}),m.jsx(O.div,{whileHover:{scale:1.02},className:"bg-white/5 rounded-xl p-6 mb-6 border border-white/10",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsxs("div",{className:"relative",children:[m.jsx("img",{src:((P=S.track.album.images[0])==null?void 0:P.url)||"/placeholder-album.png",alt:S.track.album.name,className:"w-20 h-20 rounded-lg object-cover"}),r&&d===S.track.id&&m.jsx("div",{className:"absolute inset-0 rounded-lg flex items-center justify-center",style:{backgroundColor:`${((j=a.cssVars)==null?void 0:j.primary)||"#1db954"}20`},children:m.jsx(yk,{className:"w-6 h-6",style:{color:((D=a.cssVars)==null?void 0:D.primary)||"#1db954"}})})]}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h3",{className:"text-xl font-semibold text-white mb-1",children:S.track.name}),m.jsx("p",{className:"text-white/70 mb-2",children:S.track.artists.map(z=>z.name).join(", ")}),m.jsxs("p",{className:"text-white/50 text-sm",children:[S.track.album.name," • ",Zg(S.track.duration_ms)]})]}),m.jsxs("div",{className:"flex items-center space-x-3",children:[m.jsx("button",{onClick:()=>h(S.track.external_urls.spotify,S.track.id),disabled:l,className:"w-12 h-12 rounded-full flex items-center justify-center transition-all duration-300 text-white disabled:opacity-50",style:{backgroundColor:r&&d===S.track.id?"#ef4444":((T=a.cssVars)==null?void 0:T.primary)||"#1db954"},onMouseEnter:z=>{l||(z.currentTarget.style.opacity="0.9")},onMouseLeave:z=>{l||(z.currentTarget.style.opacity="1")},children:l&&d===S.track.id?m.jsx("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}):r&&d===S.track.id?m.jsx(pk,{className:"w-5 h-5"}):m.jsx(Nh,{className:"w-5 h-5 ml-0.5"})}),m.jsx("a",{href:S.track.external_urls.spotify,target:"_blank",rel:"noopener noreferrer",className:"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors",children:m.jsx(Bg,{className:"w-4 h-4 text-white"})})]})]})}),m.jsxs("div",{children:[m.jsxs("h3",{className:"text-lg font-semibold text-white mb-4 flex items-center space-x-2",children:[m.jsx(Po,{className:"w-5 h-5"}),m.jsx("span",{children:"Recent History"})]}),m.jsx("div",{className:"space-y-3",children:y.recentlyPlayed.slice(0,5).map((z,V)=>{var U,R,Q;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:V*.1},className:"flex items-center space-x-4 p-3 rounded-lg hover:bg-white/5 transition-colors group",children:[m.jsx("img",{src:((U=z.track.album.images[0])==null?void 0:U.url)||"/placeholder-album.png",alt:z.track.album.name,className:"w-12 h-12 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h4",{className:"text-white font-medium group-hover:text-spotify-green transition-colors",children:z.track.name}),m.jsx("p",{className:"text-white/70 text-sm",children:(R=z.track.artists[0])==null?void 0:R.name})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Pr(z.played_at)}),m.jsx("button",{onClick:()=>h(z.track.external_urls.spotify,z.track.id),disabled:l,className:"opacity-0 group-hover:opacity-100 w-8 h-8 rounded-full flex items-center justify-center transition-all disabled:opacity-50",style:{backgroundColor:((Q=a.cssVars)==null?void 0:Q.primary)||"#1db954"},onMouseEnter:A=>{l||(A.currentTarget.style.opacity="0.9")},onMouseLeave:A=>{l||(A.currentTarget.style.opacity="1")},children:m.jsx(Nh,{className:"w-4 h-4 text-white ml-0.5"})})]},z.track.id)})})]})]})};return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2 flex items-center space-x-3",children:[m.jsx(Xe,{className:"w-10 h-10",style:{color:((g=a.cssVars)==null?void 0:g.primary)||"#1db954"}}),m.jsx("span",{children:"What's Playing"})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"Discover what you and your partner are listening to right now"})]}),m.jsxs("div",{className:"grid lg:grid-cols-2 gap-8",children:[e&&m.jsx(p,{user:e,title:`${(x=e.user)==null?void 0:x.display_name}'s Music`,isPartner:!1}),t&&m.jsx(p,{user:t,title:`${(v=t.user)==null?void 0:v.display_name}'s Music`,isPartner:!0}),!t&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 text-center",children:[m.jsx(Xe,{className:"w-16 h-16 mx-auto mb-4 text-pink-400"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"Waiting for your partner"}),m.jsx("p",{className:"text-white/70 mb-4",children:"Invite your partner to connect their Spotify account to see their music"}),m.jsx("button",{className:"bg-pink-500 hover:bg-pink-600 text-white px-6 py-3 rounded-lg transition-colors",children:"Send Invitation"})]})]}),e&&t&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 mt-8",children:[m.jsxs("h3",{className:"text-lg font-semibold text-white mb-4 flex items-center space-x-2",children:[m.jsx(Po,{className:"w-5 h-5"}),m.jsx("span",{children:"Shared Timeline"})]}),m.jsx("div",{className:"space-y-3",children:u.items.map(y=>{var w,b,S,C,P;return m.jsxs("div",{className:"flex items-center gap-4 p-3 rounded-lg bg-white/5",children:[m.jsx("img",{src:((S=(b=(w=y.track.album)==null?void 0:w.images)==null?void 0:b[0])==null?void 0:S.url)||"/placeholder-album.png",alt:((C=y.track.album)==null?void 0:C.name)||"Album",className:"w-10 h-10 rounded"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("span",{className:"text-white font-medium truncate",children:y.track.name}),u.overlaps.has(y.track.id)&&m.jsx("span",{className:"text-pink-400 text-sm",children:"💕"})]}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(P=y.track.artists)==null?void 0:P.map(j=>j.name).join(", ")})]}),m.jsxs("div",{className:"text-white/50 text-xs w-32 text-right",children:[Pr(new Date(y.played_at).toISOString()),m.jsx("div",{className:"text-white/60",children:y.who==="you"?"You":"Partner"})]})]},y.key)})})]})]})},u6=({imageUrl:e,alt:t,fallbackGradient:n})=>{const[r,s]=k.useState(null),[i,o]=k.useState(!0),[a,l]=k.useState(!1);return k.useEffect(()=>{e.startsWith("http")?(s(e),o(!1)):(async()=>{try{const d=await fetch(`${Br}${e}`);if(d.ok){const f=await d.json();s(f.dataUrl)}else l(!0)}catch{l(!0)}finally{o(!1)}})()},[e]),i?m.jsx("div",{className:"w-full h-full bg-gradient-to-br from-gray-500 to-gray-600 flex items-center justify-center",children:m.jsx(vt,{className:"w-8 h-8 text-white animate-pulse"})}):a||!r?m.jsx("div",{className:`w-full h-full flex items-center justify-center ${n}`,children:m.jsx(vt,{className:"w-8 h-8 text-white"})}):m.jsx("img",{src:r,alt:t,className:"w-full h-full object-cover",onError:()=>l(!0)})};function Vh(e){var r;const t=(r=e.vibe)==null?void 0:r.toLowerCase(),n=e.genres||[];if(t)switch(t){case"energetic":return"bg-gradient-to-br from-red-500 to-orange-500";case"chill":return"bg-gradient-to-br from-blue-500 to-teal-500";case"romantic":return"bg-gradient-to-br from-pink-500 to-rose-500";case"party":return"bg-gradient-to-br from-purple-500 to-pink-500";case"workout":return"bg-gradient-to-br from-green-500 to-lime-500";case"study":return"bg-gradient-to-br from-indigo-500 to-blue-500";case"sad":return"bg-gradient-to-br from-gray-500 to-slate-500";case"happy":return"bg-gradient-to-br from-yellow-500 to-orange-500"}if(n.length>0)switch(n[0].toLowerCase()){case"pop":return"bg-gradient-to-br from-pink-500 to-purple-500";case"rock":return"bg-gradient-to-br from-red-500 to-black";case"hip-hop":case"rap":return"bg-gradient-to-br from-yellow-500 to-red-500";case"electronic":case"edm":return"bg-gradient-to-br from-cyan-500 to-blue-500";case"jazz":return"bg-gradient-to-br from-amber-500 to-orange-500";case"classical":return"bg-gradient-to-br from-slate-500 to-gray-600";case"country":return"bg-gradient-to-br from-green-600 to-yellow-600";case"r&b":return"bg-gradient-to-br from-purple-600 to-pink-600";case"indie":return"bg-gradient-to-br from-teal-500 to-green-500";case"alternative":return"bg-gradient-to-br from-gray-600 to-purple-600"}return"bg-gradient-to-br from-purple-500 to-pink-500"}const c6=()=>{var V,U,R,Q;const{currentUser:e,partnerUser:t,mixedPlaylists:n,addMixedPlaylist:r,removeMixedPlaylist:s,setMixedPlaylists:i,theme:o}=ae(),a=Vr(o),[l,c]=k.useState(!1),[d,f]=k.useState(!1),[u,h]=k.useState(null),[p,g]=k.useState(""),[x,v]=k.useState(""),[y,w]=k.useState(!0),[b,S]=k.useState(!1),C=x.split(",").map(A=>A.trim()).filter(A=>A.length>0);k.useEffect(()=>{(async()=>{if(e!=null&&e.jwt)try{console.log("Loading playlists from database...");const q=await se("/playlists/mixed",e.jwt);console.log("Loaded playlists:",q.playlists);const _=q.playlists.map(N=>{var L;const F=N.track_uris?JSON.parse(N.track_uris):[];return console.log("Processing playlist:",N.name,"track_uris count:",F.length,"raw track_uris:",((L=N.track_uris)==null?void 0:L.substring(0,100))+"..."),{id:N.id,name:N.name,description:N.description,tracks:[],createdAt:new Date(N.created_at),createdBy:"AI Magic ✨",spotifyId:N.creator_spotify_id,spotifyUrl:N.creator_spotify_url,partnerSpotifyId:N.partner_spotify_id,partnerSpotifyUrl:N.partner_spotify_url,vibe:N.vibe,genres:N.genres?JSON.parse(N.genres):[],trackUris:F,spotifyImageUrl:N.creator_spotify_image_url}});i(_)}catch(q){console.error("Failed to load playlists:",q)}})()},[e==null?void 0:e.jwt]);const P=async()=>{var A,q,_,N,F,L;if(!u||!((A=e==null?void 0:e.user)!=null&&A.id)){he.error("Unable to create playlist");return}if(!(e!=null&&e.jwt)){he.error("Please login again");return}f(!0);try{const E={partnerId:((q=t==null?void 0:t.user)==null?void 0:q.id)||e.user.id,createForBoth:!1,includeKnown:!0,name:u.name,description:u.description},W=await Pt("/playlists/mixed",E,e.jwt);r({...u,spotifyId:(N=(_=W==null?void 0:W.createdFor)==null?void 0:_.creator)==null?void 0:N.playlistId,spotifyUrl:(L=(F=W==null?void 0:W.createdFor)==null?void 0:F.creator)==null?void 0:L.url}),he.success("Playlist created on Spotify!"),h(null)}catch(E){console.error("Spotify playlist creation error:",E),he.error("Failed to create playlist on Spotify")}finally{f(!1)}},j=async()=>{var A,q,_,N;if(!((A=e==null?void 0:e.user)!=null&&A.id)||!((q=t==null?void 0:t.user)!=null&&q.id)){he.error("Missing users");return}if(!(e!=null&&e.jwt)){he.error("Please login again");return}f(!0);try{const F={partnerId:t.user.id,createForBoth:b,includeKnown:y,vibe:p||void 0,genres:C.length?C:void 0,description:(u==null?void 0:u.description)||"An AI-blended mix with fresh recommendations"},L=await Pt("/playlists/mixed",F,e.jwt);b&&L.createdFor.partnerError?he.success("Your playlist created! Partner sync failed: "+L.createdFor.partnerError):b&&L.createdFor.partner?he.success("Enhanced playlist created on both accounts!"):he.success("Enhanced playlist created!");const E={id:L.id,name:L.name,description:F.description,tracks:[],createdAt:new Date,createdBy:"AI Magic ✨",spotifyId:L.createdFor.creator.playlistId,spotifyUrl:L.createdFor.creator.url,partnerSpotifyId:(_=L.createdFor.partner)==null?void 0:_.playlistId,partnerSpotifyUrl:(N=L.createdFor.partner)==null?void 0:N.url,vibe:F.vibe,genres:F.genres||[],trackUris:L.trackUris||[],spotifyImageUrl:L.spotifyImageUrl};r(E),h(null)}catch(F){console.error(F),he.error("Failed to create enhanced playlist")}finally{f(!1)}},D=()=>{u&&(r(u),h(null),he.success("Playlist saved locally!"))},T=({playlist:A,isNew:q=!1})=>{var _;return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},whileHover:{scale:1.02},className:`glass rounded-2xl p-6 ${q?"border-spotify-green/50":"border-white/10"}`,children:[m.jsxs("div",{className:"flex items-start justify-between mb-4",children:[m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsxs("div",{className:`w-16 h-16 rounded-xl flex items-center justify-center overflow-hidden ${q?"bg-gradient-to-br from-spotify-green to-green-600":"bg-gradient-to-br from-purple-500 to-pink-500"}`,children:[q?m.jsx(Yn,{className:"w-8 h-8 text-white"}):A.spotifyImageUrl?m.jsx(u6,{imageUrl:A.spotifyImageUrl,alt:A.name,fallbackGradient:Vh(A)}):null,!q&&m.jsx("div",{className:`w-full h-full flex items-center justify-center ${A.spotifyImageUrl?"bg-gradient-to-br from-purple-500 to-pink-500":Vh(A)}`,style:{display:A.spotifyImageUrl?"none":"flex"},children:m.jsx(vt,{className:"w-8 h-8 text-white"})})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-xl font-semibold text-white",children:A.name}),m.jsx("p",{className:"text-white/70 text-sm",children:A.description}),m.jsxs("div",{className:"flex flex-wrap gap-1 mt-1 mb-1",children:[A.vibe&&m.jsx("span",{className:"px-2 py-0.5 bg-blue-500/20 text-blue-300 text-xs rounded-full",children:A.vibe}),A.genres&&A.genres.length>0&&A.genres.slice(0,2).map((N,F)=>m.jsx("span",{className:"px-2 py-0.5 bg-green-500/20 text-green-300 text-xs rounded-full",children:N},F))]}),m.jsxs("p",{className:"text-white/50 text-xs",children:["Created ",q?"just now":new Date(A.createdAt).toLocaleDateString()," • ",A.tracks.length||((_=A.trackUris)==null?void 0:_.length)||0," tracks"]})]})]}),m.jsxs("div",{className:"flex items-center space-x-2",children:[A.spotifyUrl&&m.jsx("a",{href:A.spotifyUrl,target:"_blank",rel:"noopener noreferrer",className:"w-8 h-8 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors",title:"Open in Spotify",children:m.jsx(Bg,{className:"w-4 h-4 text-white"})}),A.partnerSpotifyUrl&&m.jsx("a",{href:A.partnerSpotifyUrl,target:"_blank",rel:"noopener noreferrer",className:"w-8 h-8 rounded-full bg-pink-500/20 hover:bg-pink-500/30 flex items-center justify-center transition-colors",title:"Partner's playlist in Spotify",children:m.jsx(Xe,{className:"w-4 h-4 text-pink-400"})}),!q&&m.jsx("button",{onClick:async()=>{try{e!=null&&e.jwt&&await mb(`/playlists/mixed/${A.id}`,e.jwt),s(A.id),he.success("Playlist deleted successfully")}catch(N){console.error("Failed to delete playlist:",N),he.error("Failed to delete playlist")}},className:"w-8 h-8 rounded-full bg-red-500/20 hover:bg-red-500/30 flex items-center justify-center transition-colors",children:m.jsx(Wg,{className:"w-4 h-4 text-red-400"})})]})]}),m.jsx("div",{className:"space-y-3 max-h-64 overflow-y-auto",children:A.tracks.length>0?m.jsxs(m.Fragment,{children:[A.tracks.slice(0,5).map((N,F)=>{var L,E,W,X,te,G;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:F*.1},className:"flex items-center space-x-3 p-2 rounded-lg hover:bg-white/5 transition-colors",children:[m.jsx("img",{src:((W=(E=(L=N.album)==null?void 0:L.images)==null?void 0:E[0])==null?void 0:W.url)||"/placeholder-album.png",alt:((X=N.album)==null?void 0:X.name)||"Unknown Album",className:"w-10 h-10 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("h4",{className:"text-white font-medium truncate",children:N.name}),m.jsx("p",{className:"text-white/70 text-sm truncate",children:((G=(te=N.artists)==null?void 0:te[0])==null?void 0:G.name)||"Unknown Artist"})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Zg(N.duration_ms)})]},N.id)}),A.tracks.length>5&&m.jsxs("div",{className:"text-center text-white/50 text-sm py-2",children:["+",A.tracks.length-5," more tracks"]})]}):A.trackUris&&A.trackUris.length>0?m.jsx("div",{className:"text-center py-4"}):m.jsx("div",{className:"text-center text-white/50 text-sm py-4",children:"No tracks available"})}),q&&m.jsxs("div",{className:"flex items-center space-x-3 mt-6 pt-4 border-t border-white/10",children:[m.jsx("button",{onClick:P,disabled:d||b,className:"flex-1 bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-4 rounded-lg transition-colors flex items-center justify-center space-x-2 disabled:opacity-50",children:d?m.jsx("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}):m.jsxs(m.Fragment,{children:[m.jsx(Ac,{className:"w-4 h-4"}),m.jsx("span",{children:b?"Disabled (using Create for both)":"Create on Spotify"})]})}),m.jsx("button",{onClick:D,className:"px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors",children:"Save Locally"})]})]})},z=(e==null?void 0:e.topTracks)&&(t==null?void 0:t.topTracks);return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2 flex items-center space-x-3",children:[m.jsx(Yn,{className:"w-10 h-10",style:{color:((V=a.cssVars)==null?void 0:V.primary)||"#1db954"}}),m.jsx("span",{children:"Mixed Playlists"})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"AI-powered playlists that perfectly blend your musical tastes together"})]}),z&&m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.1},className:"mb-8",children:m.jsxs("div",{className:"glass rounded-2xl p-8 text-center",style:{borderColor:`${((U=a.cssVars)==null?void 0:U.primary)||"#1db954"}30`},children:[m.jsx("div",{className:"w-16 h-16 mx-auto mb-4 rounded-full flex items-center justify-center",style:{background:`linear-gradient(135deg, ${((R=a.cssVars)==null?void 0:R.primary)||"#1db954"} 0%, ${((Q=a.cssVars)==null?void 0:Q.secondary)||"#1ed760"} 100%)`},children:m.jsx(vk,{className:"w-8 h-8 text-white"})}),m.jsx("h2",{className:"text-2xl font-bold text-white mb-2",children:"Create Your Perfect Mix"}),m.jsx("p",{className:"text-white/70 mb-6 max-w-2xl mx-auto",children:"Our AI analyzes both your music tastes and creates a playlist that represents your unique musical connection"}),m.jsxs("div",{className:"mt-4 text-white/50 text-sm",children:["Analyzing ",e.topTracks.length+t.topTracks.length," tracks from both users"]}),m.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4 text-left mt-8",children:[m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/80 text-sm mb-1",children:"Vibe"}),m.jsxs("select",{className:"w-full bg-white/10 text-white rounded-lg p-2 appearance-none focus:outline-none focus:ring-2 focus:ring-spotify-green",value:p,onChange:A=>g(A.target.value),children:[m.jsx("option",{value:"",children:"Auto"}),m.jsx("option",{value:"energetic",children:"Energetic"}),m.jsx("option",{value:"chill",children:"Chill"}),m.jsx("option",{value:"happy",children:"Happy"}),m.jsx("option",{value:"sad",children:"Sad"}),m.jsx("option",{value:"party",children:"Party"}),m.jsx("option",{value:"focus",children:"Focus"})]})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/80 text-sm mb-1",children:"Genres (comma-separated)"}),m.jsx("input",{className:"w-full bg-white/10 text-white rounded-lg p-2 placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-spotify-green",placeholder:"pop, rock, edm",value:x,onChange:A=>v(A.target.value)})]}),m.jsxs("label",{className:"flex items-center space-x-2 text-white/80",children:[m.jsx("input",{type:"checkbox",checked:y,onChange:A=>w(A.target.checked)}),m.jsx("span",{children:"Include songs we already know"})]}),m.jsxs("label",{className:"flex items-center space-x-2 text-white/80",children:[m.jsx("input",{type:"checkbox",checked:b,onChange:A=>S(A.target.checked)}),m.jsx("span",{children:"Create playlist on both accounts"}),b&&m.jsx("span",{className:"text-xs text-pink-400 ml-2",children:"✨ Synced"})]})]}),m.jsx("div",{className:"flex items-center justify-center gap-3 mt-6",children:m.jsx("button",{onClick:j,disabled:d,className:"bg-white/10 hover:bg-white/20 text-white font-semibold py-3 px-4 rounded-lg transition-colors disabled:opacity-50",children:"Create Enhanced Playlist"})})]})}),u&&m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},className:"mb-8",children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"✨ Your New Playlist"}),m.jsx(T,{playlist:u,isNew:!0})]}),n.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"Your Mixed Playlists"}),m.jsx("div",{className:"grid gap-6",children:n.map(A=>m.jsx(T,{playlist:A},A.id))})]}),!z&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(Xe,{className:"w-16 h-16 mx-auto mb-4 text-pink-400"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:t?"Loading music data":"Waiting for your partner"}),m.jsx("p",{className:"text-white/70",children:t?"We need to analyze both your music tastes to create the perfect mixed playlist":"Invite your partner to connect their Spotify account to start creating mixed playlists"})]}),n.length===0&&z&&!u&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(vt,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No playlists yet"}),m.jsx("p",{className:"text-white/70",children:"Create your first mixed playlist to start your musical journey together"})]})]})},d6=()=>{const{currentUser:e,partnerUser:t,memoryLane:n,addMemoryLaneItem:r}=ae(),[s,i]=k.useState(!1),[o,a]=k.useState({title:"",description:"",type:"milestone"});k.useEffect(()=>{var u,h,p,g,x,v,y,w,b,S,C,P;e&&t&&n.length===0&&[{id:"1",type:"milestone",title:"First Musical Connection",description:`${(u=e.user)==null?void 0:u.display_name} and ${(h=t.user)==null?void 0:h.display_name} discovered their shared love for music`,date:new Date(Date.now()-6048e5),users:[((p=e.user)==null?void 0:p.id)||"",((g=t.user)==null?void 0:g.id)||""]},{id:"2",type:"shared_track",title:"Shared Love for This Song",description:`Both of you have been listening to "${((v=(x=e.recentlyPlayed)==null?void 0:x[0])==null?void 0:v.track.name)||"Your favorite track"}" recently`,track:(w=(y=e.recentlyPlayed)==null?void 0:y[0])==null?void 0:w.track,date:new Date(Date.now()-2592e5),users:[((b=e.user)==null?void 0:b.id)||"",((S=t.user)==null?void 0:S.id)||""]},{id:"3",type:"playlist_created",title:"Our First Mixed Playlist",description:"Created a beautiful blend of your musical tastes",date:new Date(Date.now()-864e5),users:[((C=e.user)==null?void 0:C.id)||"",((P=t.user)==null?void 0:P.id)||""]}].forEach(D=>{r(D)})},[e,t,n.length,r]);const l=()=>{var h,p;if(!o.title.trim()||!o.description.trim()){he.error("Please fill in both title and description");return}const u={id:Date.now().toString(),...o,date:new Date,users:[((h=e==null?void 0:e.user)==null?void 0:h.id)||"",((p=t==null?void 0:t.user)==null?void 0:p.id)||""]};r(u),a({title:"",description:"",type:"milestone"}),i(!1),he.success("Memory added to your journey!")},c=u=>{switch(u){case"shared_track":return m.jsx(vt,{className:"w-5 h-5"});case"playlist_created":return m.jsx(Yn,{className:"w-5 h-5"});case"milestone":return m.jsx(mk,{className:"w-5 h-5"});default:return m.jsx(Xe,{className:"w-5 h-5"})}},d=u=>{switch(u){case"shared_track":return"from-blue-500 to-cyan-500";case"playlist_created":return"from-purple-500 to-pink-500";case"milestone":return"from-yellow-500 to-orange-500";default:return"from-pink-500 to-red-500"}},f=({memory:u,index:h})=>{var p,g;return m.jsxs(O.div,{initial:{opacity:0,x:-50},animate:{opacity:1,x:0},transition:{delay:h*.1},className:"relative",children:[hi(!0),className:"bg-gradient-to-r from-pink-500 to-red-500 hover:from-pink-600 hover:to-red-600 text-white font-semibold py-3 px-6 rounded-xl transition-all duration-300 flex items-center space-x-2",children:[m.jsx(Ac,{className:"w-5 h-5"}),m.jsx("span",{children:"Add Memory"})]})]})}),s&&m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},className:"fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4",onClick:()=>i(!1),children:m.jsxs(O.div,{initial:{scale:.9,opacity:0},animate:{scale:1,opacity:1},onClick:u=>u.stopPropagation(),className:"glass rounded-2xl p-8 max-w-md w-full",children:[m.jsx("h3",{className:"text-2xl font-bold text-white mb-6",children:"Add a New Memory"}),m.jsxs("div",{className:"space-y-4",children:[m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Title"}),m.jsx("input",{type:"text",value:o.title,onChange:u=>a({...o,title:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-spotify-green",placeholder:"What's this memory about?"})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Description"}),m.jsx("textarea",{value:o.description,onChange:u=>a({...o,description:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-spotify-green h-24 resize-none",placeholder:"Tell the story of this memory..."})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Type"}),m.jsxs("select",{value:o.type,onChange:u=>a({...o,type:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:border-spotify-green",children:[m.jsx("option",{value:"milestone",children:"Milestone"}),m.jsx("option",{value:"shared_track",children:"Shared Track"}),m.jsx("option",{value:"playlist_created",children:"Playlist Created"})]})]})]}),m.jsxs("div",{className:"flex items-center space-x-3 mt-6",children:[m.jsx("button",{onClick:l,className:"flex-1 bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-4 rounded-lg transition-colors",children:"Add Memory"}),m.jsx("button",{onClick:()=>i(!1),className:"px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors",children:"Cancel"})]})]})}),m.jsx("div",{className:"space-y-8",children:n.length>0?n.map((u,h)=>m.jsx(f,{memory:u,index:h},u.id)):m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(ck,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No memories yet"}),m.jsx("p",{className:"text-white/70 mb-6",children:"Start creating beautiful musical memories together"}),m.jsx("button",{onClick:()=>i(!0),className:"bg-gradient-to-r from-pink-500 to-red-500 hover:from-pink-600 hover:to-red-600 text-white font-semibold py-3 px-6 rounded-xl transition-all duration-300",children:"Create First Memory"})]})}),n.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},className:"mt-12 grid grid-cols-1 md:grid-cols-3 gap-6",children:[m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-pink-500 to-red-500 rounded-full flex items-center justify-center",children:m.jsx(Xe,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Memories Created"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-blue-500 to-cyan-500 rounded-full flex items-center justify-center",children:m.jsx(vt,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.filter(u=>u.type==="shared_track").length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Shared Tracks"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-purple-500 to-pink-500 rounded-full flex items-center justify-center",children:m.jsx(Yn,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.filter(u=>u.type==="playlist_created").length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Playlists Created"})]})]})]})};function f6(e,t){if(!e||!t)return 0;const n=["energy","valence"];let r=0,s=0;for(const i of n)typeof e[i]=="number"&&typeof t[i]=="number"&&(r+=1-Math.min(1,Math.abs(e[i]-t[i])),s++);return s?Math.round(r/s*100):0}const h6=()=>{var u,h;const{currentUser:e,partnerUser:t}=ae(),[n,r]=k.useState(null),[s,i]=k.useState(null),[o,a]=k.useState(null),[l,c]=k.useState(null);k.useEffect(()=>{let p;const g=async()=>{var x,v,y,w;try{const b=(x=e==null?void 0:e.user)==null?void 0:x.id;if(b){const C=await se(`/users/${b}/now-playing`);r(C);const P=(v=C==null?void 0:C.item)==null?void 0:v.id;if(P){const j=await se(`/users/${b}/audio-features?ids=${P}`);a(((j==null?void 0:j.audio_features)||[])[0]||null)}}const S=(y=t==null?void 0:t.user)==null?void 0:y.id;if(S){const C=await se(`/users/${S}/now-playing`);i(C);const P=(w=C==null?void 0:C.item)==null?void 0:w.id;if(P){const j=await se(`/users/${S}/audio-features?ids=${P}`);c(((j==null?void 0:j.audio_features)||[])[0]||null)}}}catch{}p=setTimeout(g,8e3)};return g(),()=>clearTimeout(p)},[(u=e==null?void 0:e.user)==null?void 0:u.id,(h=t==null?void 0:t.user)==null?void 0:h.id]);const d=k.useMemo(()=>f6(o,l),[o,l]),f=({data:p,who:g})=>{var v,y,w;if(!(p!=null&&p.is_playing)||!(p!=null&&p.item))return m.jsxs("div",{className:"glass rounded-2xl p-6 text-white/70",children:[g," is not playing"]});const x=p.item;return m.jsxs("div",{className:"glass rounded-2xl p-6 flex items-center gap-4",children:[m.jsx("img",{src:((w=(y=(v=x==null?void 0:x.album)==null?void 0:v.images)==null?void 0:y[0])==null?void 0:w.url)||"/placeholder-album.png",alt:x==null?void 0:x.name,className:"w-16 h-16 rounded"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:x==null?void 0:x.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:((x==null?void 0:x.artists)||[]).map(b=>b.name).join(", ")})]}),m.jsx("div",{className:"flex gap-1",children:[...Array(12)].map((b,S)=>m.jsx("div",{className:"w-1 bg-spotify-green/60 animate-pulse",style:{height:`${(Math.sin(S)*.5+.5)*32+8}px`,animationDelay:`${S*50}ms`}},S))})]})};return m.jsxs("div",{className:"max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-6",children:[m.jsx("h1",{className:"text-3xl font-bold text-white",children:"Live Dashboard"}),m.jsx("p",{className:"text-white/70",children:"See what you are both playing right now"})]}),m.jsxs("div",{className:"grid md:grid-cols-2 gap-6",children:[m.jsx(f,{data:n,who:"You"}),m.jsx(f,{data:s,who:"Partner"})]}),(n==null?void 0:n.is_playing)&&(s==null?void 0:s.is_playing)&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-6 mt-6 text-center",children:[m.jsx("div",{className:"text-white/80",children:"Harmony Match"}),m.jsxs("div",{className:"text-4xl font-extrabold text-white mt-1",children:[d,"%"]})]})]})};function p6(){var o,a;const{currentUser:e,partnerUser:t,isLoading:n,theme:r}=ae(),s=En();console.log("🔍 App - Current location:",s.pathname),k.useEffect(()=>{Vr(r)},[r]),k.useEffect(()=>{const l=localStorage.getItem("spotify-user"),c=localStorage.getItem("spotify-partner");if(l)try{const d=JSON.parse(l);ae.getState().setCurrentUser(d)}catch(d){console.error("Failed to parse stored user data:",d),localStorage.removeItem("spotify-user")}if(c)try{const d=JSON.parse(c);ae.getState().setPartnerUser(d)}catch(d){console.error("Failed to parse stored partner data:",d),localStorage.removeItem("spotify-partner")}},[]),k.useEffect(()=>{(async()=>{var d,f;const c=(f=(d=ae.getState().currentUser)==null?void 0:d.user)==null?void 0:f.id;if(c&&!ae.getState().partnerUser)try{const u=await se(`/partners/partner/${c}`);if(u.partnerId){const[h,p,g]=await Promise.all([se(`/users/${u.partnerId}`),se(`/users/${u.partnerId}/recently-played`),se(`/users/${u.partnerId}/top-tracks?time_range=short_term`)]);ae.getState().setPartnerUser({user:h,accessToken:null,refreshToken:null,isAuthenticated:!0,recentlyPlayed:p,topTracks:g.map(x=>x.track),topArtists:[]})}}catch{}})()},[(o=e==null?void 0:e.user)==null?void 0:o.id]),k.useEffect(()=>{var d,f;const l=(f=(d=ae.getState().currentUser)==null?void 0:d.user)==null?void 0:f.id;if(!l)return;const c=hb(`/partners/events/${l}`);return c.onmessage=async u=>{var h,p;if(u.data)try{const g=JSON.parse(u.data);if((g==null?void 0:g.type)==="partner:connected"||(g==null?void 0:g.type)==="partner:disconnected"){const x=await se(`/partners/partner/${l}`),v=((p=(h=ae.getState().partnerUser)==null?void 0:h.user)==null?void 0:p.id)||null;if(!(x!=null&&x.partnerId)&&v){ae.getState().setPartnerUser(null),localStorage.removeItem("spotify-partner");return}if(x!=null&&x.partnerId&&x.partnerId!==v)try{const[y,w,b]=await Promise.all([se(`/users/${x.partnerId}`),se(`/users/${x.partnerId}/recently-played`),se(`/users/${x.partnerId}/top-tracks?time_range=short_term`)]);ae.getState().setPartnerUser({user:y,accessToken:null,refreshToken:null,isAuthenticated:!0,recentlyPlayed:w,topTracks:b.map(S=>S.track),topArtists:[]})}catch{}}(g==null?void 0:g.type)==="partner:request"||(g==null||g.type)}catch{}},c.onerror=()=>{try{c.close()}catch{}},()=>{try{c.close()}catch{}}},[(a=e==null?void 0:e.user)==null?void 0:a.id]);const i=(e==null?void 0:e.isAuthenticated)||!1;return n?m.jsxs("div",{className:"min-h-screen flex items-center justify-center relative",children:[m.jsx(Eh,{hueShift:ah(r)}),m.jsxs(O.div,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},className:"glass-fluid rounded-3xl p-10 flex flex-col items-center space-y-6 relative z-20",children:[m.jsx("div",{className:"w-16 h-16 border-4 border-t-transparent rounded-full animate-spin",style:{borderColor:"var(--theme-primary) var(--theme-primary) var(--theme-primary) transparent"}}),m.jsx("p",{className:"text-white font-medium text-lg",children:"Loading your musical journey..."})]})]}):m.jsxs("div",{className:"min-h-screen relative overflow-hidden",children:[m.jsx(Eh,{hueShift:ah(r)}),m.jsxs("div",{className:"relative z-20",children:[i&&m.jsx(Jk,{}),m.jsxs(wx,{children:[m.jsx(_t,{path:"/",element:i?m.jsx(a6,{}):m.jsx(o6,{})}),m.jsx(_t,{path:"/callback",element:m.jsx(Rh,{})}),m.jsx(_t,{path:"/callback.html",element:m.jsx(Rh,{})}),i&&m.jsxs(m.Fragment,{children:[m.jsx(_t,{path:"/last-listened",element:m.jsx(l6,{})}),m.jsx(_t,{path:"/mixed-playlist",element:m.jsx(c6,{})}),m.jsx(_t,{path:"/memory-lane",element:m.jsx(d6,{})}),m.jsx(_t,{path:"/live",element:m.jsx(h6,{})})]}),m.jsx(_t,{path:"*",element:m.jsx(vx,{to:"/",replace:!0})})]})]})]})}Ka.createRoot(document.getElementById("root")).render(m.jsx(Gs.StrictMode,{children:m.jsxs(Tx,{children:[m.jsx(p6,{}),m.jsx(w2,{position:"top-right",toastOptions:{duration:4e3,style:{background:"rgba(255, 255, 255, 0.1)",backdropFilter:"blur(20px)",border:"1px solid rgba(255, 255, 255, 0.2)",color:"#fff"}}})]})})); + */const _h=ee("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);function qg(e){var t,n,r="";if(typeof e=="string"||typeof e=="number")r+=e;else if(typeof e=="object")if(Array.isArray(e)){var s=e.length;for(t=0;t{const t=kk(e),{conflictingClassGroups:n,conflictingClassGroupModifiers:r}=e;return{getClassGroupId:o=>{const a=o.split(Lc);return a[0]===""&&a.length!==1&&a.shift(),Gg(a,t)||Sk(o)},getConflictingClassGroupIds:(o,a)=>{const l=n[o]||[];return a&&r[o]?[...l,...r[o]]:l}}},Gg=(e,t)=>{var o;if(e.length===0)return t.classGroupId;const n=e[0],r=t.nextPart.get(n),s=r?Gg(e.slice(1),r):void 0;if(s)return s;if(t.validators.length===0)return;const i=e.join(Lc);return(o=t.validators.find(({validator:a})=>a(i)))==null?void 0:o.classGroupId},Ah=/^\[(.+)\]$/,Sk=e=>{if(Ah.test(e)){const t=Ah.exec(e)[1],n=t==null?void 0:t.substring(0,t.indexOf(":"));if(n)return"arbitrary.."+n}},kk=e=>{const{theme:t,prefix:n}=e,r={nextPart:new Map,validators:[]};return Pk(Object.entries(e.classGroups),n).forEach(([i,o])=>{uu(o,r,i,t)}),r},uu=(e,t,n,r)=>{e.forEach(s=>{if(typeof s=="string"){const i=s===""?t:Lh(t,s);i.classGroupId=n;return}if(typeof s=="function"){if(Ck(s)){uu(s(r),t,n,r);return}t.validators.push({validator:s,classGroupId:n});return}Object.entries(s).forEach(([i,o])=>{uu(o,Lh(t,i),n,r)})})},Lh=(e,t)=>{let n=e;return t.split(Lc).forEach(r=>{n.nextPart.has(r)||n.nextPart.set(r,{nextPart:new Map,validators:[]}),n=n.nextPart.get(r)}),n},Ck=e=>e.isThemeGetter,Pk=(e,t)=>t?e.map(([n,r])=>{const s=r.map(i=>typeof i=="string"?t+i:typeof i=="object"?Object.fromEntries(Object.entries(i).map(([o,a])=>[t+o,a])):i);return[n,s]}):e,jk=e=>{if(e<1)return{get:()=>{},set:()=>{}};let t=0,n=new Map,r=new Map;const s=(i,o)=>{n.set(i,o),t++,t>e&&(t=0,r=n,n=new Map)};return{get(i){let o=n.get(i);if(o!==void 0)return o;if((o=r.get(i))!==void 0)return s(i,o),o},set(i,o){n.has(i)?n.set(i,o):s(i,o)}}},Yg="!",Ek=e=>{const{separator:t,experimentalParseClassName:n}=e,r=t.length===1,s=t[0],i=t.length,o=a=>{const l=[];let c=0,d=0,f;for(let x=0;xd?f-d:void 0;return{modifiers:l,hasImportantModifier:h,baseClassName:p,maybePostfixModifierPosition:g}};return n?a=>n({className:a,parseClassName:o}):o},Tk=e=>{if(e.length<=1)return e;const t=[];let n=[];return e.forEach(r=>{r[0]==="["?(t.push(...n.sort(),r),n=[]):n.push(r)}),t.push(...n.sort()),t},Nk=e=>({cache:jk(e.cacheSize),parseClassName:Ek(e),...bk(e)}),Mk=/\s+/,_k=(e,t)=>{const{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:s}=t,i=[],o=e.trim().split(Mk);let a="";for(let l=o.length-1;l>=0;l-=1){const c=o[l],{modifiers:d,hasImportantModifier:f,baseClassName:u,maybePostfixModifierPosition:h}=n(c);let p=!!h,g=r(p?u.substring(0,h):u);if(!g){if(!p){a=c+(a.length>0?" "+a:a);continue}if(g=r(u),!g){a=c+(a.length>0?" "+a:a);continue}p=!1}const x=Tk(d).join(":"),v=f?x+Yg:x,y=v+g;if(i.includes(y))continue;i.push(y);const w=s(g,p);for(let b=0;b0?" "+a:a)}return a};function Ak(){let e=0,t,n,r="";for(;e{if(typeof e=="string")return e;let t,n="";for(let r=0;rf(d),e());return n=Nk(c),r=n.cache.get,s=n.cache.set,i=a,a(l)}function a(l){const c=r(l);if(c)return c;const d=_k(l,n);return s(l,d),d}return function(){return i(Ak.apply(null,arguments))}}const ne=e=>{const t=n=>n[e]||[];return t.isThemeGetter=!0,t},Xg=/^\[(?:([a-z-]+):)?(.+)\]$/i,Dk=/^\d+\/\d+$/,Rk=new Set(["px","full","screen"]),Vk=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,Fk=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,Ik=/^(rgba?|hsla?|hwb|(ok)?(lab|lch))\(.+\)$/,zk=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,Ok=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,Mt=e=>Cr(e)||Rk.has(e)||Dk.test(e),Kt=e=>Ur(e,"length",Yk),Cr=e=>!!e&&!Number.isNaN(Number(e)),Ya=e=>Ur(e,"number",Cr),ts=e=>!!e&&Number.isInteger(Number(e)),$k=e=>e.endsWith("%")&&Cr(e.slice(0,-1)),H=e=>Xg.test(e),Xt=e=>Vk.test(e),Bk=new Set(["length","size","percentage"]),Uk=e=>Ur(e,Bk,Qg),Wk=e=>Ur(e,"position",Qg),Hk=new Set(["image","url"]),qk=e=>Ur(e,Hk,Xk),Gk=e=>Ur(e,"",Kk),ns=()=>!0,Ur=(e,t,n)=>{const r=Xg.exec(e);return r?r[1]?typeof t=="string"?r[1]===t:t.has(r[1]):n(r[2]):!1},Yk=e=>Fk.test(e)&&!Ik.test(e),Qg=()=>!1,Kk=e=>zk.test(e),Xk=e=>Ok.test(e),Qk=()=>{const e=ne("colors"),t=ne("spacing"),n=ne("blur"),r=ne("brightness"),s=ne("borderColor"),i=ne("borderRadius"),o=ne("borderSpacing"),a=ne("borderWidth"),l=ne("contrast"),c=ne("grayscale"),d=ne("hueRotate"),f=ne("invert"),u=ne("gap"),h=ne("gradientColorStops"),p=ne("gradientColorStopPositions"),g=ne("inset"),x=ne("margin"),v=ne("opacity"),y=ne("padding"),w=ne("saturate"),b=ne("scale"),S=ne("sepia"),C=ne("skew"),P=ne("space"),j=ne("translate"),D=()=>["auto","contain","none"],T=()=>["auto","hidden","clip","visible","scroll"],z=()=>["auto",H,t],V=()=>[H,t],U=()=>["",Mt,Kt],R=()=>["auto",Cr,H],Q=()=>["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],A=()=>["solid","dashed","dotted","double","none"],q=()=>["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"],_=()=>["start","end","center","between","around","evenly","stretch"],N=()=>["","0",H],F=()=>["auto","avoid","all","avoid-page","page","left","right","column"],L=()=>[Cr,H];return{cacheSize:500,separator:":",theme:{colors:[ns],spacing:[Mt,Kt],blur:["none","",Xt,H],brightness:L(),borderColor:[e],borderRadius:["none","","full",Xt,H],borderSpacing:V(),borderWidth:U(),contrast:L(),grayscale:N(),hueRotate:L(),invert:N(),gap:V(),gradientColorStops:[e],gradientColorStopPositions:[$k,Kt],inset:z(),margin:z(),opacity:L(),padding:V(),saturate:L(),scale:L(),sepia:N(),skew:L(),space:V(),translate:V()},classGroups:{aspect:[{aspect:["auto","square","video",H]}],container:["container"],columns:[{columns:[Xt]}],"break-after":[{"break-after":F()}],"break-before":[{"break-before":F()}],"break-inside":[{"break-inside":["auto","avoid","avoid-page","avoid-column"]}],"box-decoration":[{"box-decoration":["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none","start","end"]}],clear:[{clear:["left","right","both","none","start","end"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:[...Q(),H]}],overflow:[{overflow:T()}],"overflow-x":[{"overflow-x":T()}],"overflow-y":[{"overflow-y":T()}],overscroll:[{overscroll:D()}],"overscroll-x":[{"overscroll-x":D()}],"overscroll-y":[{"overscroll-y":D()}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:[g]}],"inset-x":[{"inset-x":[g]}],"inset-y":[{"inset-y":[g]}],start:[{start:[g]}],end:[{end:[g]}],top:[{top:[g]}],right:[{right:[g]}],bottom:[{bottom:[g]}],left:[{left:[g]}],visibility:["visible","invisible","collapse"],z:[{z:["auto",ts,H]}],basis:[{basis:z()}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",H]}],grow:[{grow:N()}],shrink:[{shrink:N()}],order:[{order:["first","last","none",ts,H]}],"grid-cols":[{"grid-cols":[ns]}],"col-start-end":[{col:["auto",{span:["full",ts,H]},H]}],"col-start":[{"col-start":R()}],"col-end":[{"col-end":R()}],"grid-rows":[{"grid-rows":[ns]}],"row-start-end":[{row:["auto",{span:[ts,H]},H]}],"row-start":[{"row-start":R()}],"row-end":[{"row-end":R()}],"grid-flow":[{"grid-flow":["row","col","dense","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr",H]}],"auto-rows":[{"auto-rows":["auto","min","max","fr",H]}],gap:[{gap:[u]}],"gap-x":[{"gap-x":[u]}],"gap-y":[{"gap-y":[u]}],"justify-content":[{justify:["normal",..._()]}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:["normal",..._(),"baseline"]}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[..._(),"baseline"]}],"place-items":[{"place-items":["start","end","center","baseline","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:[y]}],px:[{px:[y]}],py:[{py:[y]}],ps:[{ps:[y]}],pe:[{pe:[y]}],pt:[{pt:[y]}],pr:[{pr:[y]}],pb:[{pb:[y]}],pl:[{pl:[y]}],m:[{m:[x]}],mx:[{mx:[x]}],my:[{my:[x]}],ms:[{ms:[x]}],me:[{me:[x]}],mt:[{mt:[x]}],mr:[{mr:[x]}],mb:[{mb:[x]}],ml:[{ml:[x]}],"space-x":[{"space-x":[P]}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":[P]}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max","fit","svw","lvw","dvw",H,t]}],"min-w":[{"min-w":[H,t,"min","max","fit"]}],"max-w":[{"max-w":[H,t,"none","full","min","max","fit","prose",{screen:[Xt]},Xt]}],h:[{h:[H,t,"auto","min","max","fit","svh","lvh","dvh"]}],"min-h":[{"min-h":[H,t,"min","max","fit","svh","lvh","dvh"]}],"max-h":[{"max-h":[H,t,"min","max","fit","svh","lvh","dvh"]}],size:[{size:[H,t,"auto","min","max","fit"]}],"font-size":[{text:["base",Xt,Kt]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black",Ya]}],"font-family":[{font:[ns]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractions"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",H]}],"line-clamp":[{"line-clamp":["none",Cr,Ya]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",Mt,H]}],"list-image":[{"list-image":["none",H]}],"list-style-type":[{list:["none","disc","decimal",H]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:[e]}],"placeholder-opacity":[{"placeholder-opacity":[v]}],"text-alignment":[{text:["left","center","right","justify","start","end"]}],"text-color":[{text:[e]}],"text-opacity":[{"text-opacity":[v]}],"text-decoration":["underline","overline","line-through","no-underline"],"text-decoration-style":[{decoration:[...A(),"wavy"]}],"text-decoration-thickness":[{decoration:["auto","from-font",Mt,Kt]}],"underline-offset":[{"underline-offset":["auto",Mt,H]}],"text-decoration-color":[{decoration:[e]}],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","text-ellipsis","text-clip"],"text-wrap":[{text:["wrap","nowrap","balance","pretty"]}],indent:[{indent:V()}],"vertical-align":[{align:["baseline","top","middle","bottom","text-top","text-bottom","sub","super",H]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap","break-spaces"]}],break:[{break:["normal","words","all","keep"]}],hyphens:[{hyphens:["none","manual","auto"]}],content:[{content:["none",H]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":[v]}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:[...Q(),Wk]}],"bg-repeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain",Uk]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]},qk]}],"bg-color":[{bg:[e]}],"gradient-from-pos":[{from:[p]}],"gradient-via-pos":[{via:[p]}],"gradient-to-pos":[{to:[p]}],"gradient-from":[{from:[h]}],"gradient-via":[{via:[h]}],"gradient-to":[{to:[h]}],rounded:[{rounded:[i]}],"rounded-s":[{"rounded-s":[i]}],"rounded-e":[{"rounded-e":[i]}],"rounded-t":[{"rounded-t":[i]}],"rounded-r":[{"rounded-r":[i]}],"rounded-b":[{"rounded-b":[i]}],"rounded-l":[{"rounded-l":[i]}],"rounded-ss":[{"rounded-ss":[i]}],"rounded-se":[{"rounded-se":[i]}],"rounded-ee":[{"rounded-ee":[i]}],"rounded-es":[{"rounded-es":[i]}],"rounded-tl":[{"rounded-tl":[i]}],"rounded-tr":[{"rounded-tr":[i]}],"rounded-br":[{"rounded-br":[i]}],"rounded-bl":[{"rounded-bl":[i]}],"border-w":[{border:[a]}],"border-w-x":[{"border-x":[a]}],"border-w-y":[{"border-y":[a]}],"border-w-s":[{"border-s":[a]}],"border-w-e":[{"border-e":[a]}],"border-w-t":[{"border-t":[a]}],"border-w-r":[{"border-r":[a]}],"border-w-b":[{"border-b":[a]}],"border-w-l":[{"border-l":[a]}],"border-opacity":[{"border-opacity":[v]}],"border-style":[{border:[...A(),"hidden"]}],"divide-x":[{"divide-x":[a]}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":[a]}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":[v]}],"divide-style":[{divide:A()}],"border-color":[{border:[s]}],"border-color-x":[{"border-x":[s]}],"border-color-y":[{"border-y":[s]}],"border-color-s":[{"border-s":[s]}],"border-color-e":[{"border-e":[s]}],"border-color-t":[{"border-t":[s]}],"border-color-r":[{"border-r":[s]}],"border-color-b":[{"border-b":[s]}],"border-color-l":[{"border-l":[s]}],"divide-color":[{divide:[s]}],"outline-style":[{outline:["",...A()]}],"outline-offset":[{"outline-offset":[Mt,H]}],"outline-w":[{outline:[Mt,Kt]}],"outline-color":[{outline:[e]}],"ring-w":[{ring:U()}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:[e]}],"ring-opacity":[{"ring-opacity":[v]}],"ring-offset-w":[{"ring-offset":[Mt,Kt]}],"ring-offset-color":[{"ring-offset":[e]}],shadow:[{shadow:["","inner","none",Xt,Gk]}],"shadow-color":[{shadow:[ns]}],opacity:[{opacity:[v]}],"mix-blend":[{"mix-blend":[...q(),"plus-lighter","plus-darker"]}],"bg-blend":[{"bg-blend":q()}],filter:[{filter:["","none"]}],blur:[{blur:[n]}],brightness:[{brightness:[r]}],contrast:[{contrast:[l]}],"drop-shadow":[{"drop-shadow":["","none",Xt,H]}],grayscale:[{grayscale:[c]}],"hue-rotate":[{"hue-rotate":[d]}],invert:[{invert:[f]}],saturate:[{saturate:[w]}],sepia:[{sepia:[S]}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":[n]}],"backdrop-brightness":[{"backdrop-brightness":[r]}],"backdrop-contrast":[{"backdrop-contrast":[l]}],"backdrop-grayscale":[{"backdrop-grayscale":[c]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[d]}],"backdrop-invert":[{"backdrop-invert":[f]}],"backdrop-opacity":[{"backdrop-opacity":[v]}],"backdrop-saturate":[{"backdrop-saturate":[w]}],"backdrop-sepia":[{"backdrop-sepia":[S]}],"border-collapse":[{border:["collapse","separate"]}],"border-spacing":[{"border-spacing":[o]}],"border-spacing-x":[{"border-spacing-x":[o]}],"border-spacing-y":[{"border-spacing-y":[o]}],"table-layout":[{table:["auto","fixed"]}],caption:[{caption:["top","bottom"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform",H]}],duration:[{duration:L()}],ease:[{ease:["linear","in","out","in-out",H]}],delay:[{delay:L()}],animate:[{animate:["none","spin","ping","pulse","bounce",H]}],transform:[{transform:["","gpu","none"]}],scale:[{scale:[b]}],"scale-x":[{"scale-x":[b]}],"scale-y":[{"scale-y":[b]}],rotate:[{rotate:[ts,H]}],"translate-x":[{"translate-x":[j]}],"translate-y":[{"translate-y":[j]}],"skew-x":[{"skew-x":[C]}],"skew-y":[{"skew-y":[C]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left",H]}],accent:[{accent:["auto",e]}],appearance:[{appearance:["none","auto"]}],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed","none","context-menu","progress","cell","crosshair","vertical-text","alias","copy","no-drop","grab","grabbing","all-scroll","col-resize","row-resize","n-resize","e-resize","s-resize","w-resize","ne-resize","nw-resize","se-resize","sw-resize","ew-resize","ns-resize","nesw-resize","nwse-resize","zoom-in","zoom-out",H]}],"caret-color":[{caret:[e]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],"scroll-behavior":[{scroll:["auto","smooth"]}],"scroll-m":[{"scroll-m":V()}],"scroll-mx":[{"scroll-mx":V()}],"scroll-my":[{"scroll-my":V()}],"scroll-ms":[{"scroll-ms":V()}],"scroll-me":[{"scroll-me":V()}],"scroll-mt":[{"scroll-mt":V()}],"scroll-mr":[{"scroll-mr":V()}],"scroll-mb":[{"scroll-mb":V()}],"scroll-ml":[{"scroll-ml":V()}],"scroll-p":[{"scroll-p":V()}],"scroll-px":[{"scroll-px":V()}],"scroll-py":[{"scroll-py":V()}],"scroll-ps":[{"scroll-ps":V()}],"scroll-pe":[{"scroll-pe":V()}],"scroll-pt":[{"scroll-pt":V()}],"scroll-pr":[{"scroll-pr":V()}],"scroll-pb":[{"scroll-pb":V()}],"scroll-pl":[{"scroll-pl":V()}],"snap-align":[{snap:["start","end","center","align-none"]}],"snap-stop":[{snap:["normal","always"]}],"snap-type":[{snap:["none","x","y","both"]}],"snap-strictness":[{snap:["mandatory","proximity"]}],touch:[{touch:["auto","none","manipulation"]}],"touch-x":[{"touch-pan":["x","left","right"]}],"touch-y":[{"touch-pan":["y","up","down"]}],"touch-pz":["touch-pinch-zoom"],select:[{select:["none","text","all","auto"]}],"will-change":[{"will-change":["auto","scroll","contents","transform",H]}],fill:[{fill:[e,"none"]}],"stroke-w":[{stroke:[Mt,Kt,Ya]}],stroke:[{stroke:[e,"none"]}],sr:["sr-only","not-sr-only"],"forced-color-adjust":[{"forced-color-adjust":["auto","none"]}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","start","end","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["basis","grow","shrink"],gap:["gap-x","gap-y"],p:["px","py","ps","pe","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","ms","me","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],size:["w","h"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],"line-clamp":["display","overflow"],rounded:["rounded-s","rounded-e","rounded-t","rounded-r","rounded-b","rounded-l","rounded-ss","rounded-se","rounded-ee","rounded-es","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-s":["rounded-ss","rounded-es"],"rounded-e":["rounded-se","rounded-ee"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-spacing":["border-spacing-x","border-spacing-y"],"border-w":["border-w-s","border-w-e","border-w-t","border-w-r","border-w-b","border-w-l"],"border-w-x":["border-w-r","border-w-l"],"border-w-y":["border-w-t","border-w-b"],"border-color":["border-color-s","border-color-e","border-color-t","border-color-r","border-color-b","border-color-l"],"border-color-x":["border-color-r","border-color-l"],"border-color-y":["border-color-t","border-color-b"],"scroll-m":["scroll-mx","scroll-my","scroll-ms","scroll-me","scroll-mt","scroll-mr","scroll-mb","scroll-ml"],"scroll-mx":["scroll-mr","scroll-ml"],"scroll-my":["scroll-mt","scroll-mb"],"scroll-p":["scroll-px","scroll-py","scroll-ps","scroll-pe","scroll-pt","scroll-pr","scroll-pb","scroll-pl"],"scroll-px":["scroll-pr","scroll-pl"],"scroll-py":["scroll-pt","scroll-pb"],touch:["touch-x","touch-y","touch-pz"],"touch-x":["touch"],"touch-y":["touch"],"touch-pz":["touch"]},conflictingClassGroupModifiers:{"font-size":["leading"]}}},Zk=Lk(Qk);function Dh(...e){return Zk(wk(e))}function Zg(e){const t=Math.floor(e/6e4),n=Math.floor(e%6e4/1e3);return`${t}:${n.toString().padStart(2,"0")}`}function Pr(e){const t=new Date(e),r=(new Date().getTime()-t.getTime())/(1e3*60*60);return r<1?`${Math.floor(r*60)}m ago`:r<24?`${Math.floor(r)}h ago`:`${Math.floor(r/24)}d ago`}const Jk=()=>{var V,U,R,Q,A,q,_,N,F,L;const[e,t]=k.useState(!1),[n,r]=k.useState(!1),[s,i]=k.useState({x:0,y:0}),[o,a]=k.useState(!1),[l,c]=k.useState({x:0,y:0}),{currentUser:d,partnerUser:f,logout:u,theme:h,setTheme:p,setPartnerUser:g}=ae(),[x,v]=k.useState(""),[y,w]=k.useState(!1),[b,S]=k.useState(!1),C=En(),P=[{name:"Dashboard",href:"/",icon:Xe},{name:"Last Listened",href:"/last-listened",icon:vt},{name:"Mixed Playlist",href:"/mixed-playlist",icon:Ug},{name:"Memory Lane",href:"/memory-lane",icon:Yn}],j=()=>{u(),localStorage.removeItem("spotify-user"),localStorage.removeItem("spotify-partner")},D=async()=>{var E,W;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!((W=f==null?void 0:f.user)!=null&&W.id))&&confirm(`Are you sure you want to remove ${f.user.display_name} as your partner?`)){S(!0);try{await Pt("/partners/remove",{partnerId:f.user.id})}catch(X){try{await Pt("/partners/clear",{userId:d.user.id})}catch(te){console.error("Failed to remove partner:",X,te)}}finally{g(null),localStorage.removeItem("spotify-partner"),S(!1)}}},T=Vr(h);k.useEffect(()=>{Vr(h)},[h]),k.useEffect(()=>{if(n){const E=Math.min(600,window.innerWidth-40),W=Math.min(window.innerHeight*.9,800),X=(window.innerWidth-E)/2,te=(window.innerHeight-W)/2;i({x:X,y:te})}},[n]),k.useEffect(()=>{const E=X=>{o&&i({x:X.clientX-l.x,y:X.clientY-l.y})},W=()=>{a(!1)};return o&&(document.addEventListener("mousemove",E),document.addEventListener("mouseup",W)),()=>{document.removeEventListener("mousemove",E),document.removeEventListener("mouseup",W)}},[o,l]);const z=E=>{a(!0),c({x:E.clientX-s.x,y:E.clientY-s.y})};return m.jsxs(O.nav,{initial:{y:-100,opacity:0},animate:{y:0,opacity:1},className:"sticky top-0 z-50",style:{background:"rgba(0, 0, 0, 0.8)",backdropFilter:"blur(20px)",borderBottom:"1px solid rgba(255, 255, 255, 0.05)"},children:[m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:[m.jsxs("div",{className:"flex justify-between items-center h-16",children:[m.jsxs(zi,{to:"/",className:"flex items-center space-x-2",children:[m.jsx(O.div,{whileHover:{scale:1.1,rotate:5},className:"w-8 h-8 rounded-full flex items-center justify-center",style:{background:`linear-gradient(135deg, ${((V=T.cssVars)==null?void 0:V.primary)||"#1db954"} 0%, ${((U=T.cssVars)==null?void 0:U.secondary)||"#1ed760"} 100%)`},children:m.jsx(Xe,{className:"w-5 h-5 text-white"})}),m.jsx("span",{className:"text-xl font-bold gradient-text",children:"Our Musical Journey"})]}),m.jsx("div",{className:"hidden md:flex items-center space-x-1",children:P.map(E=>{var X,te,G,be;const W=C.pathname===E.href;return m.jsxs(zi,{to:E.href,className:Dh("flex items-center space-x-2 px-4 py-2 rounded-xl transition-all duration-300",W?"text-white":"text-white/60 hover:text-white hover:bg-white/5"),style:W?{background:`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`,border:`1px solid ${((G=T.cssVars)==null?void 0:G.primary)||"#1db954"}30`}:{},children:[m.jsx(E.icon,{className:"w-4 h-4",style:{color:W?(be=T.cssVars)==null?void 0:be.primary:void 0}}),m.jsx("span",{className:"font-medium",children:E.name})]},E.name)})}),m.jsxs("div",{className:"hidden md:flex items-center space-x-4",children:[!f&&m.jsxs("div",{className:"flex items-center space-x-2",children:[m.jsx("input",{value:x,onChange:E=>v(E.target.value),placeholder:"Partner Spotify ID",className:"bg-white/10 text-white text-sm px-2 py-1 rounded"}),m.jsx("button",{disabled:y||!x,onClick:async()=>{var E;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!x)){w(!0);try{await Pt("/partners/request",{toUid:x})}finally{w(!1)}}},className:`${T.primary} ${T.hover} text-white px-3 py-1 rounded text-sm disabled:opacity-50`,children:y?"Sending...":"Send Request"})]}),f&&m.jsxs(O.div,{initial:{scale:0},animate:{scale:1},className:"flex items-center space-x-2 text-sm text-white/70",children:[m.jsx(Ss,{className:"w-4 h-4"}),m.jsxs("span",{children:["+ ",(R=f.user)==null?void 0:R.display_name]})]}),m.jsxs(O.button,{whileHover:{scale:1.05},whileTap:{scale:.95},onClick:()=>r(!0),className:"flex items-center space-x-2 px-3 py-2 rounded-xl text-white/60 hover:text-white transition-all duration-300",style:{color:(Q=T.cssVars)==null?void 0:Q.primary},onMouseEnter:E=>{E.currentTarget.style.background="rgba(255, 255, 255, 0.05)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Mh,{className:"w-4 h-4"}),m.jsx("span",{className:"hidden lg:block",children:"Settings"})]}),m.jsxs(O.button,{whileHover:{scale:1.05},whileTap:{scale:.95},onClick:j,className:"flex items-center space-x-2 px-3 py-2 rounded-xl text-white/60 hover:text-white transition-all duration-300",onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Th,{className:"w-4 h-4"}),m.jsx("span",{className:"hidden lg:block",children:"Logout"})]})]}),m.jsx("button",{onClick:()=>t(!e),className:"md:hidden p-2 rounded-lg text-white/70 hover:text-white hover:bg-white/10 transition-all duration-300",children:e?m.jsx(_h,{className:"w-6 h-6"}):m.jsx(hk,{className:"w-6 h-6"})})]}),e&&m.jsx(O.div,{initial:{opacity:0,height:0},animate:{opacity:1,height:"auto"},exit:{opacity:0,height:0},className:"md:hidden py-4 border-t border-white/10",children:m.jsxs("div",{className:"space-y-2",children:[P.map(E=>{var X,te,G,be;const W=C.pathname===E.href;return m.jsxs(zi,{to:E.href,onClick:()=>t(!1),className:Dh("flex items-center space-x-3 px-4 py-3 rounded-xl transition-all duration-300",W?"text-white":"text-white/60 hover:text-white hover:bg-white/5"),style:W?{background:`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`,border:`1px solid ${((G=T.cssVars)==null?void 0:G.primary)||"#1db954"}30`}:{},children:[m.jsx(E.icon,{className:"w-5 h-5",style:{color:W?(be=T.cssVars)==null?void 0:be.primary:void 0}}),m.jsx("span",{className:"font-medium",children:E.name})]},E.name)}),m.jsxs("div",{className:"pt-4 border-t border-white/10",children:[f&&m.jsxs("div",{className:"flex items-center space-x-3 px-4 py-2 text-sm text-white/70",children:[m.jsx(Ss,{className:"w-4 h-4"}),m.jsxs("span",{children:["Connected with ",(A=f.user)==null?void 0:A.display_name]})]}),m.jsxs("button",{onClick:()=>{r(!0),t(!1)},className:"w-full flex items-center space-x-3 px-4 py-3 rounded-xl text-white/60 hover:text-white transition-all duration-300",style:{color:(q=T.cssVars)==null?void 0:q.primary},onMouseEnter:E=>{E.currentTarget.style.background="rgba(255, 255, 255, 0.05)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Mh,{className:"w-5 h-5"}),m.jsx("span",{className:"font-medium",children:"Settings"})]}),m.jsxs("button",{onClick:j,className:"w-full flex items-center space-x-3 px-4 py-3 rounded-xl text-white/60 hover:text-white transition-all duration-300",onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},onMouseLeave:E=>{E.currentTarget.style.background="transparent"},children:[m.jsx(Th,{className:"w-5 h-5"}),m.jsx("span",{className:"font-medium",children:"Logout"})]})]})]})})]}),n&&m.jsxs(m.Fragment,{children:[m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:"fixed inset-0 bg-black/50 backdrop-blur-md z-40",onClick:()=>r(!1)}),m.jsxs(O.div,{initial:{opacity:0,scale:.8,y:30},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.8,y:30},className:"fixed z-50 overflow-hidden",style:{left:s.x,top:s.y,width:Math.min(600,window.innerWidth-40),height:Math.min(window.innerHeight*.9,800),background:"linear-gradient(135deg, rgba(0,0,0,0.9) 0%, rgba(20,20,20,0.95) 50%, rgba(0,0,0,0.9) 100%)",backdropFilter:"blur(24px) saturate(180%)",WebkitBackdropFilter:"blur(24px) saturate(180%)",border:"1px solid rgba(255,255,255,0.2)",borderRadius:"16px",boxShadow:"0 25px 50px rgba(0,0,0,0.5)",cursor:o?"grabbing":"default"},children:[m.jsxs("div",{className:"flex items-center justify-between p-4 border-b border-white/20 cursor-grab active:cursor-grabbing select-none",onMouseDown:z,style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsxs("div",{className:"flex items-center space-x-3",children:[m.jsxs("div",{className:"flex space-x-2",children:[m.jsx("div",{className:"w-3 h-3 rounded-full bg-red-500"}),m.jsx("div",{className:"w-3 h-3 rounded-full bg-yellow-500"}),m.jsx("div",{className:"w-3 h-3 rounded-full bg-green-500"})]}),m.jsx("h2",{className:"text-lg font-semibold text-white",children:"Settings"})]}),m.jsx("button",{onClick:()=>r(!1),className:"text-white/70 hover:text-white hover:bg-white/10 p-2 rounded-lg transition-all duration-200",children:m.jsx(_h,{className:"w-5 h-5"})})]}),m.jsx("div",{className:"overflow-y-auto p-4 sm:p-6",style:{height:"calc(100% - 60px)"},children:m.jsxs("div",{className:"space-y-4 sm:space-y-6",children:[(d==null?void 0:d.user)&&m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Your Account"}),m.jsxs("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsx("div",{className:"text-sm text-white/70 mb-2 font-medium",children:"Spotify ID"}),m.jsx("div",{className:"text-white font-mono text-sm break-all rounded-lg p-3 mb-3",style:{background:"rgba(0,0,0,0.4)",border:"1px solid rgba(255,255,255,0.1)"},children:d.user.id}),m.jsxs("div",{className:"text-sm text-white/80",children:["Display Name: ",m.jsx("span",{className:"text-white font-medium",children:d.user.display_name})]})]})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Partner"}),f?m.jsx("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:m.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between space-y-3 sm:space-y-0",children:[m.jsxs("div",{className:"flex items-center space-x-3 sm:space-x-4",children:[m.jsx("div",{className:"w-10 h-10 sm:w-12 sm:h-12 bg-gradient-to-br from-purple-500 to-pink-500 rounded-full flex items-center justify-center shadow-lg",children:m.jsx(Ss,{className:"w-5 h-5 sm:w-6 sm:h-6 text-white"})}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("div",{className:"text-white font-semibold text-base sm:text-lg truncate",children:(_=f.user)==null?void 0:_.display_name}),m.jsx("div",{className:"text-xs text-white/70 break-all rounded px-2 py-1 mt-1 inline-block",style:{background:"rgba(0,0,0,0.3)",border:"1px solid rgba(255,255,255,0.1)"},children:(N=f.user)==null?void 0:N.id}),m.jsx("div",{className:"text-sm text-green-400 font-medium mt-2",children:"✓ Connected"})]})]}),m.jsxs("button",{onClick:D,disabled:b,className:"flex items-center space-x-2 p-2 sm:p-3 text-red-400 hover:text-red-300 rounded-xl transition-all duration-200 disabled:opacity-50 self-start sm:self-auto",style:{background:"rgba(239, 68, 68, 0.1)"},onMouseEnter:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.2)"},onMouseLeave:E=>{E.currentTarget.style.background="rgba(239, 68, 68, 0.1)"},children:[m.jsx(Wg,{className:"w-4 h-4 sm:w-5 sm:h-5"}),m.jsx("span",{className:"text-sm sm:hidden",children:"Remove"})]})]})}):m.jsxs("div",{className:"rounded-xl p-4 border border-white/20 space-y-4 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:[m.jsxs("div",{children:[m.jsx("label",{className:"text-sm text-white/70 mb-2 block font-medium",children:"Partner Spotify ID"}),m.jsx("input",{value:x,onChange:E=>v(E.target.value),placeholder:"Enter partner's Spotify ID...",className:"w-full text-white text-sm px-4 py-3 rounded-xl placeholder-white/50 border focus:outline-none transition-all",style:{background:"rgba(0,0,0,0.4)",border:"1px solid rgba(255,255,255,0.2)"},onFocus:E=>{E.target.style.border="1px solid rgba(255,255,255,0.4)"},onBlur:E=>{E.target.style.border="1px solid rgba(255,255,255,0.2)"}})]}),m.jsx("button",{disabled:y||!x,onClick:async()=>{var E;if(!(!((E=d==null?void 0:d.user)!=null&&E.id)||!x)){w(!0);try{await Pt("/partners/request",{toUid:x}),v("")}finally{w(!1)}}},className:"w-full text-white px-4 py-3 rounded-xl text-sm disabled:opacity-50 transition-all duration-200 font-medium",style:{background:`linear-gradient(135deg, ${((F=T.cssVars)==null?void 0:F.primary)||"#1db954"} 0%, ${((L=T.cssVars)==null?void 0:L.secondary)||"#1ed760"} 100%)`},onMouseEnter:E=>{var W;E.currentTarget.style.transform="translateY(-1px)",E.currentTarget.style.boxShadow=`0 8px 25px ${((W=T.cssVars)==null?void 0:W.primary)||"#1db954"}40`},onMouseLeave:E=>{E.currentTarget.style.transform="translateY(0)",E.currentTarget.style.boxShadow="none"},children:y?"Sending...":"Send Partner Request"})]})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-lg font-semibold text-white mb-4 drop-shadow-md",children:"Color Theme"}),m.jsx("div",{className:"rounded-xl p-4 border border-white/20 transition-all duration-300 hover:border-white/30 hover:shadow-lg hover:shadow-white/5",style:{background:"linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)",backdropFilter:"blur(12px)",WebkitBackdropFilter:"blur(12px)"},onMouseEnter:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.04) 100%)"},onMouseLeave:E=>{E.currentTarget.style.background="linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)"},children:m.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-3",children:[{name:"Green",value:"green",color:"from-green-500 to-emerald-500"},{name:"Pink",value:"pink",color:"from-pink-500 to-rose-500"},{name:"Blue",value:"blue",color:"from-blue-400 to-cyan-400"},{name:"Red",value:"red",color:"from-red-600 to-red-800"},{name:"Purple",value:"purple",color:"from-purple-500 to-violet-600"},{name:"Yellow",value:"yellow",color:"from-yellow-400 to-orange-500"},{name:"Turquoise",value:"turquoise",color:"from-cyan-400 to-blue-500"}].map(E=>{var W,X,te;return m.jsxs("button",{onClick:()=>p(E.value),className:"flex items-center space-x-3 p-3 rounded-xl border transition-all duration-200",style:{border:h===E.value?`2px solid ${((W=T.cssVars)==null?void 0:W.primary)||"#1db954"}`:"1px solid rgba(255,255,255,0.2)",background:h===E.value?`linear-gradient(135deg, ${((X=T.cssVars)==null?void 0:X.primary)||"#1db954"}15 0%, ${((te=T.cssVars)==null?void 0:te.secondary)||"#1ed760"}10 100%)`:"rgba(255,255,255,0.02)"},onMouseEnter:G=>{var be;h!==E.value?(G.currentTarget.style.background="rgba(255,255,255,0.08)",G.currentTarget.style.border="1px solid rgba(255,255,255,0.4)",G.currentTarget.style.transform="translateY(-2px)",G.currentTarget.style.boxShadow="0 4px 12px rgba(0,0,0,0.3)"):(G.currentTarget.style.transform="translateY(-1px)",G.currentTarget.style.boxShadow=`0 6px 20px ${((be=T.cssVars)==null?void 0:be.primary)||"#1db954"}30`)},onMouseLeave:G=>{h!==E.value?(G.currentTarget.style.background="rgba(255,255,255,0.02)",G.currentTarget.style.border="1px solid rgba(255,255,255,0.2)",G.currentTarget.style.transform="translateY(0)",G.currentTarget.style.boxShadow="none"):(G.currentTarget.style.transform="translateY(0)",G.currentTarget.style.boxShadow="none")},children:[m.jsx("div",{className:`w-5 h-5 rounded-full bg-gradient-to-r ${E.color} shadow-sm`}),m.jsx("span",{className:"text-white text-sm font-medium",children:E.name})]},E.value)})})})]})]})})]})]})]})};var Jg={exports:{}};(function(e){var t=function(){var n="https://api.spotify.com/v1",r=null,s=null,i=function(u,h){return u.abort=h,u},o=function(u,h){var p;if(s!==null){var g=s.defer();u(function(x){g.resolve(x)},function(x){g.reject(x)}),p=g.promise}else window.Promise&&(p=new window.Promise(u));return p?new i(p,h):null},a=function(){var u=Array.prototype.slice.call(arguments),h=u[0],p=u.slice(1);return h=h||{},p.forEach(function(g){for(var x in g)g.hasOwnProperty(x)&&(h[x]=g[x])}),h},l=function(u,h){var p="";for(var g in h)if(h.hasOwnProperty(g)){var x=h[g];p+=encodeURIComponent(g)+"="+encodeURIComponent(x)+"&"}return p.length>0&&(p=p.substring(0,p.length-1),u=u+"?"+p),u},c=function(u,h){var p=new XMLHttpRequest,g=function(x,v){function y(C){x&&x(C),h&&h(null,C)}function w(){v&&v(p),h&&h(p,null)}var b=u.type||"GET";if(p.open(b,l(u.url,u.params)),r&&p.setRequestHeader("Authorization","Bearer "+r),p.onreadystatechange=function(){if(p.readyState===4){var C=null;try{C=p.responseText?JSON.parse(p.responseText):""}catch(P){console.error(P)}p.status>=200&&p.status<300?y(C):w()}},b==="GET")p.send(null);else{var S=null;u.postData&&(u.contentType==="image/jpeg"?(S=u.postData,p.setRequestHeader("Content-Type",u.contentType)):(S=JSON.stringify(u.postData),p.setRequestHeader("Content-Type","application/json"))),p.send(S)}};return h?(g(),null):o(g,function(){p.abort()})},d=function(u,h,p,g){var x={},v=null;typeof h=="object"?(x=h,v=p):typeof h=="function"&&(v=h);var y=u.type||"GET";return y!=="GET"&&u.postData&&!g?u.postData=a(u.postData,x):u.params=a(u.params,x),c(u,v)},f=function(){};return f.prototype={constructor:t},f.prototype.getGeneric=function(u,h){var p={url:u};return d(p,h)},f.prototype.getMe=function(u,h){var p={url:n+"/me"};return d(p,u,h)},f.prototype.getMySavedTracks=function(u,h){var p={url:n+"/me/tracks"};return d(p,u,h)},f.prototype.addToMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedTracks=function(u,h,p){var g={url:n+"/me/tracks/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMySavedAlbums=function(u,h){var p={url:n+"/me/albums"};return d(p,u,h)},f.prototype.addToMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedAlbums=function(u,h,p){var g={url:n+"/me/albums/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMyTopArtists=function(u,h){var p={url:n+"/me/top/artists"};return d(p,u,h)},f.prototype.getMyTopTracks=function(u,h){var p={url:n+"/me/top/tracks"};return d(p,u,h)},f.prototype.getMyRecentlyPlayedTracks=function(u,h){var p={url:n+"/me/player/recently-played"};return d(p,u,h)},f.prototype.followUsers=function(u,h){var p={url:n+"/me/following/",type:"PUT",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.followArtists=function(u,h){var p={url:n+"/me/following/",type:"PUT",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.followPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/followers",type:"PUT",postData:{}};return d(g,h,p)},f.prototype.unfollowUsers=function(u,h){var p={url:n+"/me/following/",type:"DELETE",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.unfollowArtists=function(u,h){var p={url:n+"/me/following/",type:"DELETE",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.unfollowPlaylist=function(u,h){var p={url:n+"/playlists/"+u+"/followers",type:"DELETE"};return d(p,h)},f.prototype.isFollowingUsers=function(u,h){var p={url:n+"/me/following/contains",type:"GET",params:{ids:u.join(","),type:"user"}};return d(p,h)},f.prototype.isFollowingArtists=function(u,h){var p={url:n+"/me/following/contains",type:"GET",params:{ids:u.join(","),type:"artist"}};return d(p,h)},f.prototype.areFollowingPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/followers/contains",type:"GET",params:{ids:h.join(",")}};return d(g,p)},f.prototype.getFollowedArtists=function(u,h){var p={url:n+"/me/following",type:"GET",params:{type:"artist"}};return d(p,u,h)},f.prototype.getUser=function(u,h,p){var g={url:n+"/users/"+encodeURIComponent(u)};return d(g,h,p)},f.prototype.getUserPlaylists=function(u,h,p){var g;return typeof u=="string"?g={url:n+"/users/"+encodeURIComponent(u)+"/playlists"}:(g={url:n+"/me/playlists"},p=h,h=u),d(g,h,p)},f.prototype.getPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u};return d(g,h,p)},f.prototype.getPlaylistTracks=function(u,h,p){var g={url:n+"/playlists/"+u+"/tracks"};return d(g,h,p)},f.prototype.getPlaylistCoverImage=function(u,h){var p={url:n+"/playlists/"+u+"/images"};return d(p,h)},f.prototype.createPlaylist=function(u,h,p){var g={url:n+"/users/"+encodeURIComponent(u)+"/playlists",type:"POST",postData:h};return d(g,h,p)},f.prototype.changePlaylistDetails=function(u,h,p){var g={url:n+"/playlists/"+u,type:"PUT",postData:h};return d(g,h,p)},f.prototype.addTracksToPlaylist=function(u,h,p,g){var x={url:n+"/playlists/"+u+"/tracks",type:"POST",postData:{uris:h}};return d(x,p,g,!0)},f.prototype.replaceTracksInPlaylist=function(u,h,p){var g={url:n+"/playlists/"+u+"/tracks",type:"PUT",postData:{uris:h}};return d(g,{},p)},f.prototype.reorderTracksInPlaylist=function(u,h,p,g,x){var v={url:n+"/playlists/"+u+"/tracks",type:"PUT",postData:{range_start:h,insert_before:p}};return d(v,g,x)},f.prototype.removeTracksFromPlaylist=function(u,h,p){var g=h.map(function(v){return typeof v=="string"?{uri:v}:v}),x={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{tracks:g}};return d(x,{},p)},f.prototype.removeTracksFromPlaylistWithSnapshotId=function(u,h,p,g){var x=h.map(function(y){return typeof y=="string"?{uri:y}:y}),v={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{tracks:x,snapshot_id:p}};return d(v,{},g)},f.prototype.removeTracksFromPlaylistInPositions=function(u,h,p,g){var x={url:n+"/playlists/"+u+"/tracks",type:"DELETE",postData:{positions:h,snapshot_id:p}};return d(x,{},g)},f.prototype.uploadCustomPlaylistCoverImage=function(u,h,p){var g={url:n+"/playlists/"+u+"/images",type:"PUT",postData:h.replace(/^data:image\/jpeg;base64,/,""),contentType:"image/jpeg"};return d(g,{},p)},f.prototype.getAlbum=function(u,h,p){var g={url:n+"/albums/"+u};return d(g,h,p)},f.prototype.getAlbumTracks=function(u,h,p){var g={url:n+"/albums/"+u+"/tracks"};return d(g,h,p)},f.prototype.getAlbums=function(u,h,p){var g={url:n+"/albums/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getTrack=function(u,h,p){var g={};return g.url=n+"/tracks/"+u,d(g,h,p)},f.prototype.getTracks=function(u,h,p){var g={url:n+"/tracks/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getArtist=function(u,h,p){var g={url:n+"/artists/"+u};return d(g,h,p)},f.prototype.getArtists=function(u,h,p){var g={url:n+"/artists/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getArtistAlbums=function(u,h,p){var g={url:n+"/artists/"+u+"/albums"};return d(g,h,p)},f.prototype.getArtistTopTracks=function(u,h,p,g){var x={url:n+"/artists/"+u+"/top-tracks",params:{country:h}};return d(x,p,g)},f.prototype.getArtistRelatedArtists=function(u,h,p){var g={url:n+"/artists/"+u+"/related-artists"};return d(g,h,p)},f.prototype.getFeaturedPlaylists=function(u,h){var p={url:n+"/browse/featured-playlists"};return d(p,u,h)},f.prototype.getNewReleases=function(u,h){var p={url:n+"/browse/new-releases"};return d(p,u,h)},f.prototype.getCategories=function(u,h){var p={url:n+"/browse/categories"};return d(p,u,h)},f.prototype.getCategory=function(u,h,p){var g={url:n+"/browse/categories/"+u};return d(g,h,p)},f.prototype.getCategoryPlaylists=function(u,h,p){var g={url:n+"/browse/categories/"+u+"/playlists"};return d(g,h,p)},f.prototype.search=function(u,h,p,g){var x={url:n+"/search/",params:{q:u,type:h.join(",")}};return d(x,p,g)},f.prototype.searchAlbums=function(u,h,p){return this.search(u,["album"],h,p)},f.prototype.searchArtists=function(u,h,p){return this.search(u,["artist"],h,p)},f.prototype.searchTracks=function(u,h,p){return this.search(u,["track"],h,p)},f.prototype.searchPlaylists=function(u,h,p){return this.search(u,["playlist"],h,p)},f.prototype.searchShows=function(u,h,p){return this.search(u,["show"],h,p)},f.prototype.searchEpisodes=function(u,h,p){return this.search(u,["episode"],h,p)},f.prototype.getAudioFeaturesForTrack=function(u,h){var p={};return p.url=n+"/audio-features/"+u,d(p,{},h)},f.prototype.getAudioFeaturesForTracks=function(u,h){var p={url:n+"/audio-features",params:{ids:u}};return d(p,{},h)},f.prototype.getAudioAnalysisForTrack=function(u,h){var p={};return p.url=n+"/audio-analysis/"+u,d(p,{},h)},f.prototype.getRecommendations=function(u,h){var p={url:n+"/recommendations"};return d(p,u,h)},f.prototype.getAvailableGenreSeeds=function(u){var h={url:n+"/recommendations/available-genre-seeds"};return d(h,{},u)},f.prototype.getMyDevices=function(u){var h={url:n+"/me/player/devices"};return d(h,{},u)},f.prototype.getMyCurrentPlaybackState=function(u,h){var p={url:n+"/me/player"};return d(p,u,h)},f.prototype.getMyCurrentPlayingTrack=function(u,h){var p={url:n+"/me/player/currently-playing"};return d(p,u,h)},f.prototype.transferMyPlayback=function(u,h,p){var g=h||{};g.device_ids=u;var x={type:"PUT",url:n+"/me/player",postData:g};return d(x,h,p)},f.prototype.play=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={};["context_uri","uris","offset","position_ms"].forEach(function(y){y in u&&(g[y]=u[y])});var x={type:"PUT",url:n+"/me/player/play",params:p,postData:g},v=typeof u=="function"?u:{};return d(x,v,h)},f.prototype.queue=function(u,h,p){h=h||{};var g="device_id"in h?{uri:u,device_id:h.device_id}:{uri:u},x={type:"POST",url:n+"/me/player/queue",params:g};return d(x,h,p)},f.prototype.pause=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"PUT",url:n+"/me/player/pause",params:p};return d(g,u,h)},f.prototype.skipToNext=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"POST",url:n+"/me/player/next",params:p};return d(g,u,h)},f.prototype.skipToPrevious=function(u,h){u=u||{};var p="device_id"in u?{device_id:u.device_id}:null,g={type:"POST",url:n+"/me/player/previous",params:p};return d(g,u,h)},f.prototype.seek=function(u,h,p){h=h||{};var g={position_ms:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/seek",params:g};return d(x,h,p)},f.prototype.setRepeat=function(u,h,p){h=h||{};var g={state:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/repeat",params:g};return d(x,h,p)},f.prototype.setVolume=function(u,h,p){h=h||{};var g={volume_percent:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/volume",params:g};return d(x,h,p)},f.prototype.setShuffle=function(u,h,p){h=h||{};var g={state:u};"device_id"in h&&(g.device_id=h.device_id);var x={type:"PUT",url:n+"/me/player/shuffle",params:g};return d(x,h,p)},f.prototype.getShow=function(u,h,p){var g={};return g.url=n+"/shows/"+u,d(g,h,p)},f.prototype.getShows=function(u,h,p){var g={url:n+"/shows/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getMySavedShows=function(u,h){var p={url:n+"/me/shows"};return d(p,u,h)},f.prototype.addToMySavedShows=function(u,h,p){var g={url:n+"/me/shows",type:"PUT",postData:u};return d(g,h,p)},f.prototype.removeFromMySavedShows=function(u,h,p){var g={url:n+"/me/shows",type:"DELETE",postData:u};return d(g,h,p)},f.prototype.containsMySavedShows=function(u,h,p){var g={url:n+"/me/shows/contains",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getShowEpisodes=function(u,h,p){var g={url:n+"/shows/"+u+"/episodes"};return d(g,h,p)},f.prototype.getEpisode=function(u,h,p){var g={};return g.url=n+"/episodes/"+u,d(g,h,p)},f.prototype.getEpisodes=function(u,h,p){var g={url:n+"/episodes/",params:{ids:u.join(",")}};return d(g,h,p)},f.prototype.getAccessToken=function(){return r},f.prototype.setAccessToken=function(u){r=u},f.prototype.setPromiseImplementation=function(u){var h=!1;try{var p=new u(function(g){g()});typeof p.then=="function"&&typeof p.catch=="function"&&(h=!0)}catch(g){console.error(g)}if(h)s=u;else throw new Error("Unsupported implementation of Promises/A+")},f}();e.exports=t})(Jg);var e6=Jg.exports;const t6=cu(e6),n6="7cab80d02df44a5bb96725be60a45875",ey="https://159.195.9.107:3443/callback.html";console.log("🔍 Debug - Current redirect URI:",ey);console.log("🔍 Debug - Environment VITE_REDIRECT_URI:","https://159.195.9.107:3443/callback.html");const jo=new t6,r6=()=>{const e=["user-read-private","user-read-email","user-read-recently-played","user-top-read","playlist-read-private","playlist-read-collaborative","playlist-modify-public","playlist-modify-private","user-read-playback-state","user-modify-playback-state","user-read-currently-playing","ugc-image-upload"].join(" "),n=`https://accounts.spotify.com/authorize?${new URLSearchParams({client_id:n6,response_type:"code",redirect_uri:ey,scope:e,show_dialog:"true"}).toString()}`;return console.log("🔍 Debug - Generated Spotify Auth URL:",n),n},s6=async(e,t)=>{jo.setAccessToken(e),await jo.play({uris:[t]})},i6=async e=>{jo.setAccessToken(e),await jo.pause()},o6=()=>{const[e,t]=k.useState(!1),n=()=>{t(!0),window.location.href=r6()},r=[{icon:vt,title:"Last Listened",description:"Discover what your partner is listening to right now and play it instantly"},{icon:Yn,title:"Mixed Playlist",description:"AI-powered playlists that blend your musical tastes perfectly"},{icon:Xe,title:"Memory Lane",description:"Create beautiful musical memories and shared experiences together"}];return m.jsx("div",{className:"min-h-screen flex items-center justify-center px-4 bg-black",children:m.jsxs("div",{className:"max-w-4xl w-full relative",children:[m.jsxs(O.div,{initial:{opacity:0,y:50},animate:{opacity:1,y:0},transition:{duration:.8},className:"text-center mb-12",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:.2,type:"spring",stiffness:200},className:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-pink-500 to-red-500 rounded-full flex items-center justify-center",children:m.jsx(Xe,{className:"w-10 h-10 text-white"})}),m.jsxs("h1",{className:"text-5xl md:text-6xl font-bold mb-4",children:[m.jsx("span",{className:"gradient-text",children:"Our Musical"}),m.jsx("br",{}),m.jsx("span",{className:"text-white",children:"Journey"})]}),m.jsx("p",{className:"text-xl text-white/70 max-w-2xl mx-auto leading-relaxed",children:"A private space where two hearts connect through music. Discover, share, and create beautiful musical memories together."})]}),m.jsx(O.div,{initial:{opacity:0,y:30},animate:{opacity:1,y:0},transition:{delay:.4,duration:.8},className:"grid md:grid-cols-3 gap-6 mb-12",children:r.map((s,i)=>m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5+i*.1},whileHover:{y:-8,scale:1.03},className:"glass-bubble rounded-3xl p-8 text-center group cursor-pointer",children:[m.jsx(O.div,{whileHover:{rotate:15,scale:1.15},className:"w-16 h-16 mx-auto mb-6 bg-gradient-to-br from-purple-500/30 via-blue-500/30 to-pink-500/30 rounded-2xl flex items-center justify-center backdrop-blur-sm",children:m.jsx(s.icon,{className:"w-8 h-8 text-white"})}),m.jsx("h3",{className:"text-2xl font-bold text-white mb-3",children:s.title}),m.jsx("p",{className:"text-white/70 text-sm leading-relaxed",children:s.description})]},s.title))}),m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},transition:{delay:.8,duration:.6},className:"glass-fluid rounded-3xl p-10 max-w-lg mx-auto",children:[m.jsxs("div",{className:"text-center mb-8",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:1,type:"spring",stiffness:200},className:"w-20 h-20 mx-auto mb-6 bg-gradient-to-br from-purple-500/30 via-blue-500/30 to-pink-500/30 rounded-2xl flex items-center justify-center backdrop-blur-sm",children:m.jsx(Hg,{className:"w-10 h-10 text-white"})}),m.jsx("h2",{className:"text-3xl font-bold text-white mb-3",children:"Begin Your Journey"}),m.jsx("p",{className:"text-white/70 text-lg",children:"Connect your Spotify account to start your musical love story"})]}),m.jsx(O.button,{whileHover:{scale:1.05,boxShadow:"0 15px 40px rgba(147, 51, 234, 0.4)"},whileTap:{scale:.95},onClick:n,disabled:e,className:"w-full bg-gradient-to-r from-purple-600 via-blue-600 to-pink-600 hover:from-purple-700 hover:via-blue-700 hover:to-pink-700 text-white font-bold py-5 px-8 rounded-2xl transition-all duration-300 flex items-center justify-center space-x-3 disabled:opacity-50 shadow-2xl",children:e?m.jsx("div",{className:"w-6 h-6 border-2 border-white border-t-transparent rounded-full animate-spin"}):m.jsxs(m.Fragment,{children:[m.jsx("span",{className:"text-lg",children:"Connect with Spotify"}),m.jsx(lk,{className:"w-6 h-6"})]})}),m.jsx("p",{className:"text-sm text-white/60 text-center mt-6 leading-relaxed",children:"We'll only access your listening history and playlist data to create your personalized musical journey"})]}),m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},transition:{delay:1,duration:.6},className:"text-center mt-12",children:m.jsx("p",{className:"text-white/40 text-sm",children:"Made with 💕 for a special someone"})})]})})},a6=()=>{var P,j,D,T,z,V,U,R,Q,A,q,_,N,F,L,E,W,X,te,G,be,ri,Jn,Mn,wt,ta,Dc;const{currentUser:e,partnerUser:t,theme:n}=ae(),r=Vr(n),[s,i]=k.useState([]),[o,a]=k.useState(!1),[l,c]=k.useState(null),[d,f]=k.useState(""),[u,h]=k.useState(!1),[p,g]=k.useState(null),[x,v]=k.useState(null);k.useEffect(()=>{let $;const me=async()=>{var Pe,Te,nt;try{const er=(Pe=e==null?void 0:e.user)==null?void 0:Pe.id;if(er){const na=await se(`/users/${er}/recently-played`),Wr=ae.getState().currentUser;Wr&&ae.getState().setCurrentUser({...Wr,recentlyPlayed:na})}const Rc=(nt=(Te=ae.getState().partnerUser)==null?void 0:Te.user)==null?void 0:nt.id;if(Rc){const na=await se(`/users/${Rc}/recently-played`),Wr=ae.getState().partnerUser;Wr&&ae.getState().setPartnerUser({...Wr,recentlyPlayed:na})}}catch{}$=setTimeout(me,3e4)};return me(),()=>clearTimeout($)},[(P=e==null?void 0:e.user)==null?void 0:P.id,(j=t==null?void 0:t.user)==null?void 0:j.id]),k.useEffect(()=>{(async()=>{var me;if((me=e==null?void 0:e.user)!=null&&me.id){a(!0);try{const Pe=await se(`/partners/requests/${e.user.id}`);i(Pe)}catch{i([])}finally{a(!1)}}})()},[(D=e==null?void 0:e.user)==null?void 0:D.id]),k.useEffect(()=>{let $;const me=async()=>{var Te;if((Te=e==null?void 0:e.user)!=null&&Te.id)try{const nt=await se(`/users/${e.user.id}/status`);c(nt)}catch{}},Pe=()=>{if(!(l!=null&&l.nextSyncAt)){f("");return}const Te=l.nextSyncAt-Date.now();if(Te<=0){f("now");return}const nt=Math.floor(Te/6e4),er=Math.floor(Te%6e4/1e3);f(`${nt}m ${er}s`)};return me(),$=setInterval(()=>{Pe()},1e3),()=>clearInterval($)},[(T=e==null?void 0:e.user)==null?void 0:T.id,l==null?void 0:l.nextSyncAt]),k.useEffect(()=>{let $;const me=async()=>{var Pe,Te;try{const nt=(Pe=e==null?void 0:e.user)==null?void 0:Pe.id;nt&&(g(await se(`/users/${nt}/now-playing`)),(Te=t==null?void 0:t.user)!=null&&Te.id?v(await se(`/users/${t.user.id}/now-playing`)):v(null))}catch{}$=setTimeout(me,8e3)};return me(),()=>clearTimeout($)},[(z=e==null?void 0:e.user)==null?void 0:z.id,(V=t==null?void 0:t.user)==null?void 0:V.id]);const y=async()=>{var $;if(($=e==null?void 0:e.user)!=null&&$.id){h(!0);try{await Pt(`/users/${e.user.id}/sync`);const me=await se(`/users/${e.user.id}/status`);c(me);const[Pe,Te]=await Promise.all([se(`/users/${e.user.id}/recently-played`),se(`/users/${e.user.id}/top-tracks?time_range=short_term`)]),nt=ae.getState().currentUser;nt&&ae.getState().setCurrentUser({...nt,recentlyPlayed:Pe,topTracks:Te.map(er=>er.track)}),he.success("Synced latest data")}catch{he.error("Failed to sync")}finally{h(!1)}}},w=async $=>{await Pt(`/partners/requests/${$}/accept`),i(me=>me.filter(Pe=>Pe.id!==$))},b=async $=>{await Pt(`/partners/requests/${$}/decline`),i(me=>me.filter(Pe=>Pe.id!==$))},S=[{title:"Last Listened",description:"See what your partner is listening to right now",icon:vt,href:"/last-listened",primaryColor:((U=r.cssVars)==null?void 0:U.primary)||"#1db954",secondaryColor:((R=r.cssVars)==null?void 0:R.secondary)||"#1ed760",accentColor:((Q=r.cssVars)==null?void 0:Q.accent)||"#00e676"},{title:"Mixed Playlist",description:"Create AI-powered playlists blending both your tastes",icon:Ug,href:"/mixed-playlist",primaryColor:((A=r.cssVars)==null?void 0:A.secondary)||"#1ed760",secondaryColor:((q=r.cssVars)==null?void 0:q.accent)||"#00e676",accentColor:((_=r.cssVars)==null?void 0:_.primary)||"#1db954"},{title:"Memory Lane",description:"Your shared musical journey and memories",icon:Yn,href:"/memory-lane",primaryColor:((N=r.cssVars)==null?void 0:N.accent)||"#00e676",secondaryColor:((F=r.cssVars)==null?void 0:F.primary)||"#1db954",accentColor:((L=r.cssVars)==null?void 0:L.secondary)||"#1ed760"}],C=()=>{var $;return($=e==null?void 0:e.recentlyPlayed)!=null&&$[0]?Pr(e.recentlyPlayed[0].played_at):null};return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2",children:["Welcome back, ",m.jsx("span",{className:"gradient-text",children:(E=e==null?void 0:e.user)==null?void 0:E.display_name})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"Ready to explore your musical connection together?"})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"grid md:grid-cols-2 gap-6 mb-8",children:[m.jsxs("div",{className:"glass rounded-2xl p-6",children:[m.jsx("div",{className:"text-white/70 mb-2",children:"You"}),p!=null&&p.is_playing&&(p!=null&&p.item)?m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("img",{src:((te=(X=(W=p.item.album)==null?void 0:W.images)==null?void 0:X[0])==null?void 0:te.url)||"/placeholder-album.png",className:"w-14 h-14 rounded"}),m.jsxs("div",{className:"min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:p.item.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(G=p.item.artists)==null?void 0:G.map($=>$.name).join(", ")})]})]}):m.jsx("div",{className:"text-white/50",children:"Not playing"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6",children:[m.jsx("div",{className:"text-white/70 mb-2",children:"Partner"}),x!=null&&x.is_playing&&(x!=null&&x.item)?m.jsxs("div",{className:"flex items-center gap-4",children:[m.jsx("img",{src:((Jn=(ri=(be=x.item.album)==null?void 0:be.images)==null?void 0:ri[0])==null?void 0:Jn.url)||"/placeholder-album.png",className:"w-14 h-14 rounded"}),m.jsxs("div",{className:"min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:x.item.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(Mn=x.item.artists)==null?void 0:Mn.map($=>$.name).join(", ")})]})]}):m.jsx("div",{className:"text-white/50",children:"Not playing"})]})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.1},className:"mb-8",children:[m.jsxs("div",{className:"flex items-center justify-between mb-4",children:[m.jsx("div",{className:"text-white/70 text-sm",children:(l==null?void 0:l.lastSyncedAt)&&m.jsxs("span",{children:["Last sync: ",new Date(l.lastSyncedAt).toLocaleTimeString()," • Next in: ",d||"—"]})}),m.jsx("button",{onClick:y,disabled:u,className:"bg-white/10 hover:bg-white/20 text-white px-4 py-2 rounded-lg text-sm disabled:opacity-50",children:u?"Refreshing…":"Hard Refresh"})]}),t?m.jsx("div",{className:"glass-bubble rounded-3xl p-8 border border-spotify-green/30 glow",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsx("div",{className:"w-16 h-16 bg-gradient-to-br from-spotify-green to-green-600 rounded-2xl flex items-center justify-center",children:m.jsx(Xe,{className:"w-8 h-8 text-white"})}),m.jsxs("div",{children:[m.jsxs("h3",{className:"text-xl font-semibold text-white",children:["Connected with ",(wt=t.user)==null?void 0:wt.display_name]}),m.jsx("p",{className:"text-white/70",children:"Your musical journey is ready to begin! 💕"})]})]})}):m.jsx("div",{className:"glass-bubble rounded-3xl p-8 border border-orange-500/30",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsx("div",{className:"w-16 h-16 bg-gradient-to-br from-orange-500 to-red-500 rounded-2xl flex items-center justify-center",children:m.jsx(Ac,{className:"w-8 h-8 text-white"})}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-xl font-semibold text-white",children:"Invite your partner"}),m.jsx("p",{className:"text-white/70 mb-2",children:"Ask your partner to search you in the app and send a request."}),o?m.jsx("div",{className:"text-white/60",children:"Loading requests..."}):s.length>0?m.jsx("div",{className:"space-y-3",children:s.map($=>m.jsxs("div",{className:"flex items-center justify-between bg-white/5 rounded-lg p-3",children:[m.jsxs("div",{className:"text-white/80 text-sm",children:["Request from ",$.from_user_id]}),m.jsxs("div",{className:"space-x-2",children:[m.jsx("button",{onClick:()=>w($.id),className:"bg-spotify-green hover:bg-spotify-green/90 text-white px-3 py-1 rounded-md text-sm",children:"Accept"}),m.jsx("button",{onClick:()=>b($.id),className:"bg-white/10 hover:bg-white/20 text-white px-3 py-1 rounded-md text-sm",children:"Decline"})]})]},$.id))}):m.jsx("div",{className:"text-white/60 text-sm",children:"No incoming requests yet"})]})]})})]}),m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.2},className:"grid grid-cols-1 md:grid-cols-3 gap-6 mb-8",children:[m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-blue-500/30 to-cyan-500/30 rounded-xl flex items-center justify-center",children:m.jsx(Po,{className:"w-6 h-6 text-blue-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Your last played"}),m.jsx("p",{className:"text-white font-semibold",children:C()||"No recent plays"})]})]})}),m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-green-500/30 to-emerald-500/30 rounded-xl flex items-center justify-center",children:m.jsx(gk,{className:"w-6 h-6 text-green-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Top tracks analyzed"}),m.jsxs("p",{className:"text-white font-semibold",children:[((ta=e==null?void 0:e.topTracks)==null?void 0:ta.length)||0," songs"]})]})]})}),m.jsx("div",{className:"glass-bubble rounded-2xl p-6",children:m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsx("div",{className:"w-12 h-12 bg-gradient-to-br from-purple-500/30 to-pink-500/30 rounded-xl flex items-center justify-center",children:m.jsx(Ss,{className:"w-6 h-6 text-purple-400"})}),m.jsxs("div",{children:[m.jsx("p",{className:"text-white/70 text-sm",children:"Recently played"}),m.jsxs("p",{className:"text-white font-semibold",children:[((Dc=e==null?void 0:e.recentlyPlayed)==null?void 0:Dc.length)||0," tracks"]})]})]})})]}),m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},className:"grid md:grid-cols-3 gap-6",children:S.map(($,me)=>m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.4+me*.1},whileHover:{y:-5,scale:1.02},children:m.jsx(zi,{to:$.href,children:m.jsxs("div",{className:`glass rounded-2xl p-6 h-full border ${$.borderColor} group cursor-pointer transition-all duration-300 hover:shadow-xl`,children:[m.jsx("div",{className:"w-12 h-12 rounded-xl flex items-center justify-center mb-4 group-hover:scale-110 transition-transform duration-300",style:{background:`linear-gradient(135deg, ${$.primaryColor}20 0%, ${$.secondaryColor}10 100%)`,border:`1px solid ${$.primaryColor}30`},children:m.jsx($.icon,{className:"w-6 h-6",style:{color:$.primaryColor}})}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:$.title}),m.jsx("p",{className:"text-white/70 text-sm leading-relaxed mb-4",children:$.description}),m.jsx("div",{className:"w-full h-1 rounded-full opacity-0 group-hover:opacity-100 transition-opacity duration-300",style:{background:`linear-gradient(90deg, ${$.primaryColor} 0%, ${$.secondaryColor} 100%)`}})]})})},$.title))}),(e==null?void 0:e.recentlyPlayed)&&e.recentlyPlayed.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.6},className:"mt-8",children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"Your Recent Activity"}),m.jsx("div",{className:"glass rounded-2xl p-6",children:m.jsx("div",{className:"space-y-4",children:e.recentlyPlayed.slice(0,3).map(($,me)=>{var Pe,Te;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:.7+me*.1},className:"flex items-center space-x-4 p-3 rounded-lg hover:bg-white/5 transition-colors",children:[m.jsx("img",{src:((Pe=$.track.album.images[0])==null?void 0:Pe.url)||"/placeholder-album.png",alt:$.track.album.name,className:"w-12 h-12 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h4",{className:"text-white font-medium",children:$.track.name}),m.jsx("p",{className:"text-white/70 text-sm",children:(Te=$.track.artists[0])==null?void 0:Te.name})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Pr($.played_at)})]},$.track.id)})})})]})]})};let ji=!1;const Rh=()=>{const[e]=Ax(),t=Wo(),{setCurrentUser:n,setPartnerUser:r,currentUser:s}=ae(),[i,o]=k.useState("loading"),[a,l]=k.useState("");k.useEffect(()=>{(async()=>{if(ji){console.log("🔍 CallbackPage - Already processing globally, skipping...");return}ji=!0,console.log("🔍 CallbackPage - Global processing flag set to TRUE");try{const u=e.get("code"),h=e.get("error");if(console.log("🔍 CallbackPage - Code:",u),console.log("🔍 CallbackPage - Error:",h),h)throw new Error("Spotify authorization was denied");if(!u)throw new Error("No authorization code received");l("Exchanging authorization code..."),console.log("🔍 CallbackPage - Exchanging code with backend...");const p=await pb("/auth/exchange",{code:u});l("Syncing your music data..."),await Pt(`/users/${p.uid}/sync`,void 0,p.token),l("Loading your profile...");const[g,x,v]=await Promise.all([se(`/users/${p.uid}`),se(`/users/${p.uid}/recently-played`),se(`/users/${p.uid}/top-tracks?time_range=short_term`)]),y={user:g,accessToken:p.access_token,refreshToken:p.refresh_token,isAuthenticated:!0,recentlyPlayed:x,topTracks:v.map(w=>w.track),topArtists:[],jwt:p.token};localStorage.setItem("spotify-user",JSON.stringify(y)),s?(r(y),localStorage.setItem("spotify-partner",JSON.stringify(y)),l("Partner connected! Your musical journey begins...")):(n(y),l("Welcome! Setting up your musical journey...")),o("success"),he.success(s?"Partner connected successfully!":"Successfully connected to Spotify!",{duration:3e3}),setTimeout(()=>{t("/"),setTimeout(()=>{ji=!1,console.log("🔍 CallbackPage - Global processing flag set to FALSE (after success)")},1e3)},2e3)}catch(u){console.error("🔍 CallbackPage - ERROR:",u),console.error("🔍 CallbackPage - Error details:",{message:u instanceof Error?u.message:"Unknown error",stack:u instanceof Error?u.stack:void 0}),o("error"),l(u instanceof Error?u.message:"An unexpected error occurred"),he.error("Failed to connect to Spotify. Please try again."),setTimeout(()=>{t("/"),setTimeout(()=>{ji=!1,console.log("🔍 CallbackPage - Global processing flag set to FALSE (after error)")},1e3)},3e3)}})()},[e,t,n,r,s]);const c=()=>{switch(i){case"loading":return m.jsx(fk,{className:"w-12 h-12 text-spotify-green animate-spin"});case"success":return m.jsx(dk,{className:"w-12 h-12 text-green-400"});case"error":return m.jsx(xk,{className:"w-12 h-12 text-red-400"})}},d=()=>{switch(i){case"loading":return"border-spotify-green/30";case"success":return"border-green-400/30";case"error":return"border-red-400/30"}};return m.jsx("div",{className:"min-h-screen flex items-center justify-center px-4 bg-black",children:m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},className:"glass-fluid rounded-3xl p-10 max-w-md w-full text-center",children:[m.jsx(O.div,{initial:{scale:0},animate:{scale:1},transition:{delay:.2,type:"spring",stiffness:200},className:`w-20 h-20 mx-auto mb-6 rounded-full border-2 flex items-center justify-center ${d()}`,children:c()}),m.jsxs(O.h2,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},className:"text-2xl font-bold text-white mb-4",children:[i==="loading"&&"Connecting...",i==="success"&&"Success!",i==="error"&&"Connection Failed"]}),m.jsx(O.p,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.4},className:"text-white/70 mb-6",children:a}),i==="loading"&&m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},transition:{delay:.5},className:"w-full bg-white/10 rounded-full h-2 mb-4",children:m.jsx(O.div,{className:"bg-spotify-green h-2 rounded-full",initial:{width:0},animate:{width:"100%"},transition:{duration:3,ease:"easeInOut"}})}),i==="error"&&m.jsx(O.button,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},whileHover:{scale:1.05},whileTap:{scale:.95},onClick:()=>t("/"),className:"bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-300",children:"Try Again"}),i==="success"&&m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},className:"text-spotify-green text-sm",children:"Redirecting you to your musical journey..."})]})})},l6=()=>{var g,x,v;const{currentUser:e,partnerUser:t,currentTrack:n,isPlaying:r,setCurrentTrack:s,setIsPlaying:i,theme:o}=ae(),a=Vr(o),[l,c]=k.useState(!1),[d,f]=k.useState(null),u=k.useMemo(()=>{const y=((e==null?void 0:e.recentlyPlayed)||[]).map(P=>({who:"you",played_at:new Date(P.played_at).getTime(),track:P.track,key:`you-${P.track.id}-${P.played_at}`})),w=((t==null?void 0:t.recentlyPlayed)||[]).map(P=>({who:"partner",played_at:new Date(P.played_at).getTime(),track:P.track,key:`partner-${P.track.id}-${P.played_at}`})),b=[...y,...w].sort((P,j)=>j.played_at-P.played_at).slice(0,30),S=new Set,C=new Set;return b.forEach(P=>{const j=P.track.id;S.has(j)?C.add(j):S.add(j)}),{items:b,overlaps:C}},[e==null?void 0:e.recentlyPlayed,t==null?void 0:t.recentlyPlayed]),h=async(y,w)=>{var b,S;if(!(e!=null&&e.accessToken)){he.error("Not authenticated with Spotify");return}try{c(!0),f(w),r&&d===w?(await i6(e.accessToken),i(!1),s(null),f(null)):(await s6(e.accessToken,y),i(!0),s(((S=(b=e.recentlyPlayed)==null?void 0:b.find(C=>C.track.id===w))==null?void 0:S.track)||null)),he.success(r&&d===w?"Paused":"Now playing")}catch(C){console.error("Playback error:",C),he.error("Failed to play track. Make sure Spotify is open on your device.")}finally{c(!1)}},p=({user:y,title:w,isPartner:b=!1})=>{var C,P,j,D,T;if(!((C=y==null?void 0:y.recentlyPlayed)!=null&&C.length))return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 text-center",children:[m.jsx(vt,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No recent activity"}),m.jsxs("p",{className:"text-white/70",children:[b?"Your partner":"You"," haven't played any music recently"]})]});const S=y.recentlyPlayed[0];return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-6",children:[m.jsxs("div",{className:"flex items-center space-x-4 mb-6",children:[m.jsx("div",{className:`w-12 h-12 rounded-full flex items-center justify-center ${b?"bg-gradient-to-br from-pink-500 to-purple-600":"bg-gradient-to-br from-blue-500 to-cyan-600"}`,children:m.jsx(Ss,{className:"w-6 h-6 text-white"})}),m.jsxs("div",{children:[m.jsx("h2",{className:"text-2xl font-bold text-white",children:w}),m.jsxs("p",{className:"text-white/70",children:["Last played: ",Pr(S.played_at)]})]})]}),m.jsx(O.div,{whileHover:{scale:1.02},className:"bg-white/5 rounded-xl p-6 mb-6 border border-white/10",children:m.jsxs("div",{className:"flex items-center space-x-6",children:[m.jsxs("div",{className:"relative",children:[m.jsx("img",{src:((P=S.track.album.images[0])==null?void 0:P.url)||"/placeholder-album.png",alt:S.track.album.name,className:"w-20 h-20 rounded-lg object-cover"}),r&&d===S.track.id&&m.jsx("div",{className:"absolute inset-0 rounded-lg flex items-center justify-center",style:{backgroundColor:`${((j=a.cssVars)==null?void 0:j.primary)||"#1db954"}20`},children:m.jsx(yk,{className:"w-6 h-6",style:{color:((D=a.cssVars)==null?void 0:D.primary)||"#1db954"}})})]}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h3",{className:"text-xl font-semibold text-white mb-1",children:S.track.name}),m.jsx("p",{className:"text-white/70 mb-2",children:S.track.artists.map(z=>z.name).join(", ")}),m.jsxs("p",{className:"text-white/50 text-sm",children:[S.track.album.name," • ",Zg(S.track.duration_ms)]})]}),m.jsxs("div",{className:"flex items-center space-x-3",children:[m.jsx("button",{onClick:()=>h(S.track.external_urls.spotify,S.track.id),disabled:l,className:"w-12 h-12 rounded-full flex items-center justify-center transition-all duration-300 text-white disabled:opacity-50",style:{backgroundColor:r&&d===S.track.id?"#ef4444":((T=a.cssVars)==null?void 0:T.primary)||"#1db954"},onMouseEnter:z=>{l||(z.currentTarget.style.opacity="0.9")},onMouseLeave:z=>{l||(z.currentTarget.style.opacity="1")},children:l&&d===S.track.id?m.jsx("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}):r&&d===S.track.id?m.jsx(pk,{className:"w-5 h-5"}):m.jsx(Nh,{className:"w-5 h-5 ml-0.5"})}),m.jsx("a",{href:S.track.external_urls.spotify,target:"_blank",rel:"noopener noreferrer",className:"w-10 h-10 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors",children:m.jsx(Bg,{className:"w-4 h-4 text-white"})})]})]})}),m.jsxs("div",{children:[m.jsxs("h3",{className:"text-lg font-semibold text-white mb-4 flex items-center space-x-2",children:[m.jsx(Po,{className:"w-5 h-5"}),m.jsx("span",{children:"Recent History"})]}),m.jsx("div",{className:"space-y-3",children:y.recentlyPlayed.slice(0,5).map((z,V)=>{var U,R,Q;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:V*.1},className:"flex items-center space-x-4 p-3 rounded-lg hover:bg-white/5 transition-colors group",children:[m.jsx("img",{src:((U=z.track.album.images[0])==null?void 0:U.url)||"/placeholder-album.png",alt:z.track.album.name,className:"w-12 h-12 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1",children:[m.jsx("h4",{className:"text-white font-medium group-hover:text-spotify-green transition-colors",children:z.track.name}),m.jsx("p",{className:"text-white/70 text-sm",children:(R=z.track.artists[0])==null?void 0:R.name})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Pr(z.played_at)}),m.jsx("button",{onClick:()=>h(z.track.external_urls.spotify,z.track.id),disabled:l,className:"opacity-0 group-hover:opacity-100 w-8 h-8 rounded-full flex items-center justify-center transition-all disabled:opacity-50",style:{backgroundColor:((Q=a.cssVars)==null?void 0:Q.primary)||"#1db954"},onMouseEnter:A=>{l||(A.currentTarget.style.opacity="0.9")},onMouseLeave:A=>{l||(A.currentTarget.style.opacity="1")},children:m.jsx(Nh,{className:"w-4 h-4 text-white ml-0.5"})})]},z.track.id)})})]})]})};return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2 flex items-center space-x-3",children:[m.jsx(Xe,{className:"w-10 h-10",style:{color:((g=a.cssVars)==null?void 0:g.primary)||"#1db954"}}),m.jsx("span",{children:"What's Playing"})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"Discover what you and your partner are listening to right now"})]}),m.jsxs("div",{className:"grid lg:grid-cols-2 gap-8",children:[e&&m.jsx(p,{user:e,title:`${(x=e.user)==null?void 0:x.display_name}'s Music`,isPartner:!1}),t&&m.jsx(p,{user:t,title:`${(v=t.user)==null?void 0:v.display_name}'s Music`,isPartner:!0}),!t&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 text-center",children:[m.jsx(Xe,{className:"w-16 h-16 mx-auto mb-4 text-pink-400"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"Waiting for your partner"}),m.jsx("p",{className:"text-white/70 mb-4",children:"Invite your partner to connect their Spotify account to see their music"}),m.jsx("button",{className:"bg-pink-500 hover:bg-pink-600 text-white px-6 py-3 rounded-lg transition-colors",children:"Send Invitation"})]})]}),e&&t&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-8 mt-8",children:[m.jsxs("h3",{className:"text-lg font-semibold text-white mb-4 flex items-center space-x-2",children:[m.jsx(Po,{className:"w-5 h-5"}),m.jsx("span",{children:"Shared Timeline"})]}),m.jsx("div",{className:"space-y-3",children:u.items.map(y=>{var w,b,S,C,P;return m.jsxs("div",{className:"flex items-center gap-4 p-3 rounded-lg bg-white/5",children:[m.jsx("img",{src:((S=(b=(w=y.track.album)==null?void 0:w.images)==null?void 0:b[0])==null?void 0:S.url)||"/placeholder-album.png",alt:((C=y.track.album)==null?void 0:C.name)||"Album",className:"w-10 h-10 rounded"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsxs("div",{className:"flex items-center gap-2",children:[m.jsx("span",{className:"text-white font-medium truncate",children:y.track.name}),u.overlaps.has(y.track.id)&&m.jsx("span",{className:"text-pink-400 text-sm",children:"💕"})]}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:(P=y.track.artists)==null?void 0:P.map(j=>j.name).join(", ")})]}),m.jsxs("div",{className:"text-white/50 text-xs w-32 text-right",children:[Pr(new Date(y.played_at).toISOString()),m.jsx("div",{className:"text-white/60",children:y.who==="you"?"You":"Partner"})]})]},y.key)})})]})]})},u6=({imageUrl:e,alt:t,fallbackGradient:n})=>{const[r,s]=k.useState(null),[i,o]=k.useState(!0),[a,l]=k.useState(!1);return k.useEffect(()=>{e.startsWith("http")?(s(e),o(!1)):(async()=>{try{const d=await fetch(`${Br}${e}`);if(d.ok){const f=await d.json();s(f.dataUrl)}else l(!0)}catch{l(!0)}finally{o(!1)}})()},[e]),i?m.jsx("div",{className:"w-full h-full bg-gradient-to-br from-gray-500 to-gray-600 flex items-center justify-center",children:m.jsx(vt,{className:"w-8 h-8 text-white animate-pulse"})}):a||!r?m.jsx("div",{className:`w-full h-full flex items-center justify-center ${n}`,children:m.jsx(vt,{className:"w-8 h-8 text-white"})}):m.jsx("img",{src:r,alt:t,className:"w-full h-full object-cover",onError:()=>l(!0)})};function Vh(e){var r;const t=(r=e.vibe)==null?void 0:r.toLowerCase(),n=e.genres||[];if(t)switch(t){case"energetic":return"bg-gradient-to-br from-red-500 to-orange-500";case"chill":return"bg-gradient-to-br from-blue-500 to-teal-500";case"romantic":return"bg-gradient-to-br from-pink-500 to-rose-500";case"party":return"bg-gradient-to-br from-purple-500 to-pink-500";case"workout":return"bg-gradient-to-br from-green-500 to-lime-500";case"study":return"bg-gradient-to-br from-indigo-500 to-blue-500";case"sad":return"bg-gradient-to-br from-gray-500 to-slate-500";case"happy":return"bg-gradient-to-br from-yellow-500 to-orange-500"}if(n.length>0)switch(n[0].toLowerCase()){case"pop":return"bg-gradient-to-br from-pink-500 to-purple-500";case"rock":return"bg-gradient-to-br from-red-500 to-black";case"hip-hop":case"rap":return"bg-gradient-to-br from-yellow-500 to-red-500";case"electronic":case"edm":return"bg-gradient-to-br from-cyan-500 to-blue-500";case"jazz":return"bg-gradient-to-br from-amber-500 to-orange-500";case"classical":return"bg-gradient-to-br from-slate-500 to-gray-600";case"country":return"bg-gradient-to-br from-green-600 to-yellow-600";case"r&b":return"bg-gradient-to-br from-purple-600 to-pink-600";case"indie":return"bg-gradient-to-br from-teal-500 to-green-500";case"alternative":return"bg-gradient-to-br from-gray-600 to-purple-600"}return"bg-gradient-to-br from-purple-500 to-pink-500"}const c6=()=>{var V,U,R,Q;const{currentUser:e,partnerUser:t,mixedPlaylists:n,addMixedPlaylist:r,removeMixedPlaylist:s,setMixedPlaylists:i,theme:o}=ae(),a=Vr(o),[l,c]=k.useState(!1),[d,f]=k.useState(!1),[u,h]=k.useState(null),[p,g]=k.useState(""),[x,v]=k.useState(""),[y,w]=k.useState(!0),[b,S]=k.useState(!1),C=x.split(",").map(A=>A.trim()).filter(A=>A.length>0);k.useEffect(()=>{(async()=>{if(e!=null&&e.jwt)try{console.log("Loading playlists from database...");const q=await se("/playlists/mixed",e.jwt);console.log("Loaded playlists:",q.playlists);const _=q.playlists.map(N=>{var L;const F=N.track_uris?JSON.parse(N.track_uris):[];return console.log("Processing playlist:",N.name,"track_uris count:",F.length,"raw track_uris:",((L=N.track_uris)==null?void 0:L.substring(0,100))+"..."),{id:N.id,name:N.name,description:N.description,tracks:[],createdAt:new Date(N.created_at),createdBy:"AI Magic ✨",spotifyId:N.creator_spotify_id,spotifyUrl:N.creator_spotify_url,partnerSpotifyId:N.partner_spotify_id,partnerSpotifyUrl:N.partner_spotify_url,vibe:N.vibe,genres:N.genres?JSON.parse(N.genres):[],trackUris:F,spotifyImageUrl:N.creator_spotify_image_url}});i(_)}catch(q){console.error("Failed to load playlists:",q)}})()},[e==null?void 0:e.jwt]);const P=async()=>{var A,q,_,N,F,L;if(!u||!((A=e==null?void 0:e.user)!=null&&A.id)){he.error("Unable to create playlist");return}if(!(e!=null&&e.jwt)){he.error("Please login again");return}f(!0);try{const E={partnerId:((q=t==null?void 0:t.user)==null?void 0:q.id)||e.user.id,createForBoth:!1,includeKnown:!0,name:u.name,description:u.description},W=await Pt("/playlists/mixed",E,e.jwt);r({...u,spotifyId:(N=(_=W==null?void 0:W.createdFor)==null?void 0:_.creator)==null?void 0:N.playlistId,spotifyUrl:(L=(F=W==null?void 0:W.createdFor)==null?void 0:F.creator)==null?void 0:L.url}),he.success("Playlist created on Spotify!"),h(null)}catch(E){console.error("Spotify playlist creation error:",E),he.error("Failed to create playlist on Spotify")}finally{f(!1)}},j=async()=>{var A,q,_,N;if(!((A=e==null?void 0:e.user)!=null&&A.id)||!((q=t==null?void 0:t.user)!=null&&q.id)){he.error("Missing users");return}if(!(e!=null&&e.jwt)){he.error("Please login again");return}f(!0);try{const F={partnerId:t.user.id,createForBoth:b,includeKnown:y,vibe:p||void 0,genres:C.length?C:void 0,description:(u==null?void 0:u.description)||"An AI-blended mix with fresh recommendations"},L=await Pt("/playlists/mixed",F,e.jwt);b&&L.createdFor.partnerError?he.success("Your playlist created! Partner sync failed: "+L.createdFor.partnerError):b&&L.createdFor.partner?he.success("Enhanced playlist created on both accounts!"):he.success("Enhanced playlist created!");const E={id:L.id,name:L.name,description:F.description,tracks:[],createdAt:new Date,createdBy:"AI Magic ✨",spotifyId:L.createdFor.creator.playlistId,spotifyUrl:L.createdFor.creator.url,partnerSpotifyId:(_=L.createdFor.partner)==null?void 0:_.playlistId,partnerSpotifyUrl:(N=L.createdFor.partner)==null?void 0:N.url,vibe:F.vibe,genres:F.genres||[],trackUris:L.trackUris||[],spotifyImageUrl:L.spotifyImageUrl};r(E),h(null)}catch(F){console.error(F),he.error("Failed to create enhanced playlist")}finally{f(!1)}},D=()=>{u&&(r(u),h(null),he.success("Playlist saved locally!"))},T=({playlist:A,isNew:q=!1})=>{var _;return m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},whileHover:{scale:1.02},className:`glass rounded-2xl p-6 ${q?"border-spotify-green/50":"border-white/10"}`,children:[m.jsxs("div",{className:"flex items-start justify-between mb-4",children:[m.jsxs("div",{className:"flex items-center space-x-4",children:[m.jsxs("div",{className:`w-16 h-16 rounded-xl flex items-center justify-center overflow-hidden ${q?"bg-gradient-to-br from-spotify-green to-green-600":"bg-gradient-to-br from-purple-500 to-pink-500"}`,children:[q?m.jsx(Yn,{className:"w-8 h-8 text-white"}):A.spotifyImageUrl?m.jsx(u6,{imageUrl:A.spotifyImageUrl,alt:A.name,fallbackGradient:Vh(A)}):null,!q&&m.jsx("div",{className:`w-full h-full flex items-center justify-center ${A.spotifyImageUrl?"bg-gradient-to-br from-purple-500 to-pink-500":Vh(A)}`,style:{display:A.spotifyImageUrl?"none":"flex"},children:m.jsx(vt,{className:"w-8 h-8 text-white"})})]}),m.jsxs("div",{children:[m.jsx("h3",{className:"text-xl font-semibold text-white",children:A.name}),m.jsx("p",{className:"text-white/70 text-sm",children:A.description}),m.jsxs("div",{className:"flex flex-wrap gap-1 mt-1 mb-1",children:[A.vibe&&m.jsx("span",{className:"px-2 py-0.5 bg-blue-500/20 text-blue-300 text-xs rounded-full",children:A.vibe}),A.genres&&A.genres.length>0&&A.genres.slice(0,2).map((N,F)=>m.jsx("span",{className:"px-2 py-0.5 bg-green-500/20 text-green-300 text-xs rounded-full",children:N},F))]}),m.jsxs("p",{className:"text-white/50 text-xs",children:["Created ",q?"just now":new Date(A.createdAt).toLocaleDateString()," • ",A.tracks.length||((_=A.trackUris)==null?void 0:_.length)||0," tracks"]})]})]}),m.jsxs("div",{className:"flex items-center space-x-2",children:[A.spotifyUrl&&m.jsx("a",{href:A.spotifyUrl,target:"_blank",rel:"noopener noreferrer",className:"w-8 h-8 rounded-full bg-white/10 hover:bg-white/20 flex items-center justify-center transition-colors",title:"Open in Spotify",children:m.jsx(Bg,{className:"w-4 h-4 text-white"})}),A.partnerSpotifyUrl&&m.jsx("a",{href:A.partnerSpotifyUrl,target:"_blank",rel:"noopener noreferrer",className:"w-8 h-8 rounded-full bg-pink-500/20 hover:bg-pink-500/30 flex items-center justify-center transition-colors",title:"Partner's playlist in Spotify",children:m.jsx(Xe,{className:"w-4 h-4 text-pink-400"})}),!q&&m.jsx("button",{onClick:async()=>{try{e!=null&&e.jwt&&await mb(`/playlists/mixed/${A.id}`,e.jwt),s(A.id),he.success("Playlist deleted successfully")}catch(N){console.error("Failed to delete playlist:",N),he.error("Failed to delete playlist")}},className:"w-8 h-8 rounded-full bg-red-500/20 hover:bg-red-500/30 flex items-center justify-center transition-colors",children:m.jsx(Wg,{className:"w-4 h-4 text-red-400"})})]})]}),m.jsx("div",{className:"space-y-3 max-h-64 overflow-y-auto",children:A.tracks.length>0?m.jsxs(m.Fragment,{children:[A.tracks.slice(0,5).map((N,F)=>{var L,E,W,X,te,G;return m.jsxs(O.div,{initial:{opacity:0,x:-20},animate:{opacity:1,x:0},transition:{delay:F*.1},className:"flex items-center space-x-3 p-2 rounded-lg hover:bg-white/5 transition-colors",children:[m.jsx("img",{src:((W=(E=(L=N.album)==null?void 0:L.images)==null?void 0:E[0])==null?void 0:W.url)||"/placeholder-album.png",alt:((X=N.album)==null?void 0:X.name)||"Unknown Album",className:"w-10 h-10 rounded-lg object-cover"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("h4",{className:"text-white font-medium truncate",children:N.name}),m.jsx("p",{className:"text-white/70 text-sm truncate",children:((G=(te=N.artists)==null?void 0:te[0])==null?void 0:G.name)||"Unknown Artist"})]}),m.jsx("div",{className:"text-white/50 text-sm",children:Zg(N.duration_ms)})]},N.id)}),A.tracks.length>5&&m.jsxs("div",{className:"text-center text-white/50 text-sm py-2",children:["+",A.tracks.length-5," more tracks"]})]}):A.trackUris&&A.trackUris.length>0?m.jsx("div",{className:"text-center py-4"}):m.jsx("div",{className:"text-center text-white/50 text-sm py-4",children:"No tracks available"})}),q&&m.jsxs("div",{className:"flex items-center space-x-3 mt-6 pt-4 border-t border-white/10",children:[m.jsx("button",{onClick:P,disabled:d||b,className:"flex-1 bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-4 rounded-lg transition-colors flex items-center justify-center space-x-2 disabled:opacity-50",children:d?m.jsx("div",{className:"w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"}):m.jsxs(m.Fragment,{children:[m.jsx(Ac,{className:"w-4 h-4"}),m.jsx("span",{children:b?"Disabled (using Create for both)":"Create on Spotify"})]})}),m.jsx("button",{onClick:D,className:"px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors",children:"Save Locally"})]})]})},z=(e==null?void 0:e.topTracks)&&(t==null?void 0:t.topTracks);return m.jsxs("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-8",children:[m.jsxs("h1",{className:"text-4xl font-bold text-white mb-2 flex items-center space-x-3",children:[m.jsx(Yn,{className:"w-10 h-10",style:{color:((V=a.cssVars)==null?void 0:V.primary)||"#1db954"}}),m.jsx("span",{children:"Mixed Playlists"})]}),m.jsx("p",{className:"text-white/70 text-lg",children:"AI-powered playlists that perfectly blend your musical tastes together"})]}),z&&m.jsx(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.1},className:"mb-8",children:m.jsxs("div",{className:"glass rounded-2xl p-8 text-center",style:{borderColor:`${((U=a.cssVars)==null?void 0:U.primary)||"#1db954"}30`},children:[m.jsx("div",{className:"w-16 h-16 mx-auto mb-4 rounded-full flex items-center justify-center",style:{background:`linear-gradient(135deg, ${((R=a.cssVars)==null?void 0:R.primary)||"#1db954"} 0%, ${((Q=a.cssVars)==null?void 0:Q.secondary)||"#1ed760"} 100%)`},children:m.jsx(vk,{className:"w-8 h-8 text-white"})}),m.jsx("h2",{className:"text-2xl font-bold text-white mb-2",children:"Create Your Perfect Mix"}),m.jsx("p",{className:"text-white/70 mb-6 max-w-2xl mx-auto",children:"Our AI analyzes both your music tastes and creates a playlist that represents your unique musical connection"}),m.jsxs("div",{className:"mt-4 text-white/50 text-sm",children:["Analyzing ",e.topTracks.length+t.topTracks.length," tracks from both users"]}),m.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4 text-left mt-8",children:[m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/80 text-sm mb-1",children:"Vibe"}),m.jsxs("select",{className:"w-full bg-white/10 text-white rounded-lg p-2 appearance-none focus:outline-none focus:ring-2 focus:ring-spotify-green",value:p,onChange:A=>g(A.target.value),children:[m.jsx("option",{value:"",children:"Auto"}),m.jsx("option",{value:"energetic",children:"Energetic"}),m.jsx("option",{value:"chill",children:"Chill"}),m.jsx("option",{value:"happy",children:"Happy"}),m.jsx("option",{value:"sad",children:"Sad"}),m.jsx("option",{value:"party",children:"Party"}),m.jsx("option",{value:"focus",children:"Focus"})]})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/80 text-sm mb-1",children:"Genres (comma-separated)"}),m.jsx("input",{className:"w-full bg-white/10 text-white rounded-lg p-2 placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-spotify-green",placeholder:"pop, rock, edm",value:x,onChange:A=>v(A.target.value)})]}),m.jsxs("label",{className:"flex items-center space-x-2 text-white/80",children:[m.jsx("input",{type:"checkbox",checked:y,onChange:A=>w(A.target.checked)}),m.jsx("span",{children:"Include songs we already know"})]}),m.jsxs("label",{className:"flex items-center space-x-2 text-white/80",children:[m.jsx("input",{type:"checkbox",checked:b,onChange:A=>S(A.target.checked)}),m.jsx("span",{children:"Create playlist on both accounts"}),b&&m.jsx("span",{className:"text-xs text-pink-400 ml-2",children:"✨ Synced"})]})]}),m.jsx("div",{className:"flex items-center justify-center gap-3 mt-6",children:m.jsx("button",{onClick:j,disabled:d,className:"bg-white/10 hover:bg-white/20 text-white font-semibold py-3 px-4 rounded-lg transition-colors disabled:opacity-50",children:"Create Enhanced Playlist"})})]})}),u&&m.jsxs(O.div,{initial:{opacity:0,scale:.9},animate:{opacity:1,scale:1},className:"mb-8",children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"✨ Your New Playlist"}),m.jsx(T,{playlist:u,isNew:!0})]}),n.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.3},children:[m.jsx("h2",{className:"text-2xl font-bold text-white mb-4",children:"Your Mixed Playlists"}),m.jsx("div",{className:"grid gap-6",children:n.map(A=>m.jsx(T,{playlist:A},A.id))})]}),!z&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(Xe,{className:"w-16 h-16 mx-auto mb-4 text-pink-400"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:t?"Loading music data":"Waiting for your partner"}),m.jsx("p",{className:"text-white/70",children:t?"We need to analyze both your music tastes to create the perfect mixed playlist":"Invite your partner to connect their Spotify account to start creating mixed playlists"})]}),n.length===0&&z&&!u&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(vt,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No playlists yet"}),m.jsx("p",{className:"text-white/70",children:"Create your first mixed playlist to start your musical journey together"})]})]})},d6=()=>{const{currentUser:e,partnerUser:t,memoryLane:n,addMemoryLaneItem:r}=ae(),[s,i]=k.useState(!1),[o,a]=k.useState({title:"",description:"",type:"milestone"});k.useEffect(()=>{var u,h,p,g,x,v,y,w,b,S,C,P;e&&t&&n.length===0&&[{id:"1",type:"milestone",title:"First Musical Connection",description:`${(u=e.user)==null?void 0:u.display_name} and ${(h=t.user)==null?void 0:h.display_name} discovered their shared love for music`,date:new Date(Date.now()-6048e5),users:[((p=e.user)==null?void 0:p.id)||"",((g=t.user)==null?void 0:g.id)||""]},{id:"2",type:"shared_track",title:"Shared Love for This Song",description:`Both of you have been listening to "${((v=(x=e.recentlyPlayed)==null?void 0:x[0])==null?void 0:v.track.name)||"Your favorite track"}" recently`,track:(w=(y=e.recentlyPlayed)==null?void 0:y[0])==null?void 0:w.track,date:new Date(Date.now()-2592e5),users:[((b=e.user)==null?void 0:b.id)||"",((S=t.user)==null?void 0:S.id)||""]},{id:"3",type:"playlist_created",title:"Our First Mixed Playlist",description:"Created a beautiful blend of your musical tastes",date:new Date(Date.now()-864e5),users:[((C=e.user)==null?void 0:C.id)||"",((P=t.user)==null?void 0:P.id)||""]}].forEach(D=>{r(D)})},[e,t,n.length,r]);const l=()=>{var h,p;if(!o.title.trim()||!o.description.trim()){he.error("Please fill in both title and description");return}const u={id:Date.now().toString(),...o,date:new Date,users:[((h=e==null?void 0:e.user)==null?void 0:h.id)||"",((p=t==null?void 0:t.user)==null?void 0:p.id)||""]};r(u),a({title:"",description:"",type:"milestone"}),i(!1),he.success("Memory added to your journey!")},c=u=>{switch(u){case"shared_track":return m.jsx(vt,{className:"w-5 h-5"});case"playlist_created":return m.jsx(Yn,{className:"w-5 h-5"});case"milestone":return m.jsx(mk,{className:"w-5 h-5"});default:return m.jsx(Xe,{className:"w-5 h-5"})}},d=u=>{switch(u){case"shared_track":return"from-blue-500 to-cyan-500";case"playlist_created":return"from-purple-500 to-pink-500";case"milestone":return"from-yellow-500 to-orange-500";default:return"from-pink-500 to-red-500"}},f=({memory:u,index:h})=>{var p,g;return m.jsxs(O.div,{initial:{opacity:0,x:-50},animate:{opacity:1,x:0},transition:{delay:h*.1},className:"relative",children:[hi(!0),className:"bg-gradient-to-r from-pink-500 to-red-500 hover:from-pink-600 hover:to-red-600 text-white font-semibold py-3 px-6 rounded-xl transition-all duration-300 flex items-center space-x-2",children:[m.jsx(Ac,{className:"w-5 h-5"}),m.jsx("span",{children:"Add Memory"})]})]})}),s&&m.jsx(O.div,{initial:{opacity:0},animate:{opacity:1},className:"fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4",onClick:()=>i(!1),children:m.jsxs(O.div,{initial:{scale:.9,opacity:0},animate:{scale:1,opacity:1},onClick:u=>u.stopPropagation(),className:"glass rounded-2xl p-8 max-w-md w-full",children:[m.jsx("h3",{className:"text-2xl font-bold text-white mb-6",children:"Add a New Memory"}),m.jsxs("div",{className:"space-y-4",children:[m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Title"}),m.jsx("input",{type:"text",value:o.title,onChange:u=>a({...o,title:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-spotify-green",placeholder:"What's this memory about?"})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Description"}),m.jsx("textarea",{value:o.description,onChange:u=>a({...o,description:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white placeholder-white/50 focus:outline-none focus:border-spotify-green h-24 resize-none",placeholder:"Tell the story of this memory..."})]}),m.jsxs("div",{children:[m.jsx("label",{className:"block text-white/70 text-sm font-medium mb-2",children:"Type"}),m.jsxs("select",{value:o.type,onChange:u=>a({...o,type:u.target.value}),className:"w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:border-spotify-green",children:[m.jsx("option",{value:"milestone",children:"Milestone"}),m.jsx("option",{value:"shared_track",children:"Shared Track"}),m.jsx("option",{value:"playlist_created",children:"Playlist Created"})]})]})]}),m.jsxs("div",{className:"flex items-center space-x-3 mt-6",children:[m.jsx("button",{onClick:l,className:"flex-1 bg-spotify-green hover:bg-spotify-green/90 text-white font-semibold py-3 px-4 rounded-lg transition-colors",children:"Add Memory"}),m.jsx("button",{onClick:()=>i(!1),className:"px-4 py-3 bg-white/10 hover:bg-white/20 text-white rounded-lg transition-colors",children:"Cancel"})]})]})}),m.jsx("div",{className:"space-y-8",children:n.length>0?n.map((u,h)=>m.jsx(f,{memory:u,index:h},u.id)):m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-12 text-center",children:[m.jsx(ck,{className:"w-16 h-16 mx-auto mb-4 text-white/30"}),m.jsx("h3",{className:"text-xl font-semibold text-white mb-2",children:"No memories yet"}),m.jsx("p",{className:"text-white/70 mb-6",children:"Start creating beautiful musical memories together"}),m.jsx("button",{onClick:()=>i(!0),className:"bg-gradient-to-r from-pink-500 to-red-500 hover:from-pink-600 hover:to-red-600 text-white font-semibold py-3 px-6 rounded-xl transition-all duration-300",children:"Create First Memory"})]})}),n.length>0&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},transition:{delay:.5},className:"mt-12 grid grid-cols-1 md:grid-cols-3 gap-6",children:[m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-pink-500 to-red-500 rounded-full flex items-center justify-center",children:m.jsx(Xe,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Memories Created"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-blue-500 to-cyan-500 rounded-full flex items-center justify-center",children:m.jsx(vt,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.filter(u=>u.type==="shared_track").length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Shared Tracks"})]}),m.jsxs("div",{className:"glass rounded-2xl p-6 text-center",children:[m.jsx("div",{className:"w-12 h-12 mx-auto mb-3 bg-gradient-to-br from-purple-500 to-pink-500 rounded-full flex items-center justify-center",children:m.jsx(Yn,{className:"w-6 h-6 text-white"})}),m.jsx("h4",{className:"text-2xl font-bold text-white mb-1",children:n.filter(u=>u.type==="playlist_created").length}),m.jsx("p",{className:"text-white/70 text-sm",children:"Playlists Created"})]})]})]})};function f6(e,t){if(!e||!t)return 0;const n=["energy","valence"];let r=0,s=0;for(const i of n)typeof e[i]=="number"&&typeof t[i]=="number"&&(r+=1-Math.min(1,Math.abs(e[i]-t[i])),s++);return s?Math.round(r/s*100):0}const h6=()=>{var u,h;const{currentUser:e,partnerUser:t}=ae(),[n,r]=k.useState(null),[s,i]=k.useState(null),[o,a]=k.useState(null),[l,c]=k.useState(null);k.useEffect(()=>{let p;const g=async()=>{var x,v,y,w;try{const b=(x=e==null?void 0:e.user)==null?void 0:x.id;if(b){const C=await se(`/users/${b}/now-playing`);r(C);const P=(v=C==null?void 0:C.item)==null?void 0:v.id;if(P){const j=await se(`/users/${b}/audio-features?ids=${P}`);a(((j==null?void 0:j.audio_features)||[])[0]||null)}}const S=(y=t==null?void 0:t.user)==null?void 0:y.id;if(S){const C=await se(`/users/${S}/now-playing`);i(C);const P=(w=C==null?void 0:C.item)==null?void 0:w.id;if(P){const j=await se(`/users/${S}/audio-features?ids=${P}`);c(((j==null?void 0:j.audio_features)||[])[0]||null)}}}catch{}p=setTimeout(g,8e3)};return g(),()=>clearTimeout(p)},[(u=e==null?void 0:e.user)==null?void 0:u.id,(h=t==null?void 0:t.user)==null?void 0:h.id]);const d=k.useMemo(()=>f6(o,l),[o,l]),f=({data:p,who:g})=>{var v,y,w;if(!(p!=null&&p.is_playing)||!(p!=null&&p.item))return m.jsxs("div",{className:"glass rounded-2xl p-6 text-white/70",children:[g," is not playing"]});const x=p.item;return m.jsxs("div",{className:"glass rounded-2xl p-6 flex items-center gap-4",children:[m.jsx("img",{src:((w=(y=(v=x==null?void 0:x.album)==null?void 0:v.images)==null?void 0:y[0])==null?void 0:w.url)||"/placeholder-album.png",alt:x==null?void 0:x.name,className:"w-16 h-16 rounded"}),m.jsxs("div",{className:"flex-1 min-w-0",children:[m.jsx("div",{className:"text-white font-semibold truncate",children:x==null?void 0:x.name}),m.jsx("div",{className:"text-white/70 text-sm truncate",children:((x==null?void 0:x.artists)||[]).map(b=>b.name).join(", ")})]}),m.jsx("div",{className:"flex gap-1",children:[...Array(12)].map((b,S)=>m.jsx("div",{className:"w-1 bg-spotify-green/60 animate-pulse",style:{height:`${(Math.sin(S)*.5+.5)*32+8}px`,animationDelay:`${S*50}ms`}},S))})]})};return m.jsxs("div",{className:"max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 py-8",children:[m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"mb-6",children:[m.jsx("h1",{className:"text-3xl font-bold text-white",children:"Live Dashboard"}),m.jsx("p",{className:"text-white/70",children:"See what you are both playing right now"})]}),m.jsxs("div",{className:"grid md:grid-cols-2 gap-6",children:[m.jsx(f,{data:n,who:"You"}),m.jsx(f,{data:s,who:"Partner"})]}),(n==null?void 0:n.is_playing)&&(s==null?void 0:s.is_playing)&&m.jsxs(O.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:"glass rounded-2xl p-6 mt-6 text-center",children:[m.jsx("div",{className:"text-white/80",children:"Harmony Match"}),m.jsxs("div",{className:"text-4xl font-extrabold text-white mt-1",children:[d,"%"]})]})]})};function p6(){var o,a;const{currentUser:e,partnerUser:t,isLoading:n,theme:r}=ae(),s=En();console.log("🔍 App - Current location:",s.pathname),k.useEffect(()=>{Vr(r)},[r]),k.useEffect(()=>{const l=localStorage.getItem("spotify-user"),c=localStorage.getItem("spotify-partner");if(l)try{const d=JSON.parse(l);ae.getState().setCurrentUser(d)}catch(d){console.error("Failed to parse stored user data:",d),localStorage.removeItem("spotify-user")}if(c)try{const d=JSON.parse(c);ae.getState().setPartnerUser(d)}catch(d){console.error("Failed to parse stored partner data:",d),localStorage.removeItem("spotify-partner")}},[]),k.useEffect(()=>{(async()=>{var d,f;const c=(f=(d=ae.getState().currentUser)==null?void 0:d.user)==null?void 0:f.id;if(c&&!ae.getState().partnerUser)try{const u=await se(`/partners/partner/${c}`);if(u.partnerId){const[h,p,g]=await Promise.all([se(`/users/${u.partnerId}`),se(`/users/${u.partnerId}/recently-played`),se(`/users/${u.partnerId}/top-tracks?time_range=short_term`)]);ae.getState().setPartnerUser({user:h,accessToken:null,refreshToken:null,isAuthenticated:!0,recentlyPlayed:p,topTracks:g.map(x=>x.track),topArtists:[]})}}catch{}})()},[(o=e==null?void 0:e.user)==null?void 0:o.id]),k.useEffect(()=>{var d,f;const l=(f=(d=ae.getState().currentUser)==null?void 0:d.user)==null?void 0:f.id;if(!l)return;const c=hb(`/partners/events/${l}`);return c.onmessage=async u=>{var h,p;if(u.data)try{const g=JSON.parse(u.data);if((g==null?void 0:g.type)==="partner:connected"||(g==null?void 0:g.type)==="partner:disconnected"){const x=await se(`/partners/partner/${l}`),v=((p=(h=ae.getState().partnerUser)==null?void 0:h.user)==null?void 0:p.id)||null;if(!(x!=null&&x.partnerId)&&v){ae.getState().setPartnerUser(null),localStorage.removeItem("spotify-partner");return}if(x!=null&&x.partnerId&&x.partnerId!==v)try{const[y,w,b]=await Promise.all([se(`/users/${x.partnerId}`),se(`/users/${x.partnerId}/recently-played`),se(`/users/${x.partnerId}/top-tracks?time_range=short_term`)]);ae.getState().setPartnerUser({user:y,accessToken:null,refreshToken:null,isAuthenticated:!0,recentlyPlayed:w,topTracks:b.map(S=>S.track),topArtists:[]})}catch{}}(g==null?void 0:g.type)==="partner:request"||(g==null||g.type)}catch{}},c.onerror=()=>{try{c.close()}catch{}},()=>{try{c.close()}catch{}}},[(a=e==null?void 0:e.user)==null?void 0:a.id]);const i=(e==null?void 0:e.isAuthenticated)||!1;return n?m.jsxs("div",{className:"min-h-screen flex items-center justify-center relative",children:[m.jsx(Eh,{hueShift:ah(r)}),m.jsxs(O.div,{initial:{opacity:0,scale:.8},animate:{opacity:1,scale:1},className:"glass-fluid rounded-3xl p-10 flex flex-col items-center space-y-6 relative z-20",children:[m.jsx("div",{className:"w-16 h-16 border-4 border-t-transparent rounded-full animate-spin",style:{borderColor:"var(--theme-primary) var(--theme-primary) var(--theme-primary) transparent"}}),m.jsx("p",{className:"text-white font-medium text-lg",children:"Loading your musical journey..."})]})]}):m.jsxs("div",{className:"min-h-screen relative overflow-hidden",children:[m.jsx(Eh,{hueShift:ah(r)}),m.jsxs("div",{className:"relative z-20",children:[i&&m.jsx(Jk,{}),m.jsxs(wx,{children:[m.jsx(_t,{path:"/",element:i?m.jsx(a6,{}):m.jsx(o6,{})}),m.jsx(_t,{path:"/callback",element:m.jsx(Rh,{})}),m.jsx(_t,{path:"/callback.html",element:m.jsx(Rh,{})}),i&&m.jsxs(m.Fragment,{children:[m.jsx(_t,{path:"/last-listened",element:m.jsx(l6,{})}),m.jsx(_t,{path:"/mixed-playlist",element:m.jsx(c6,{})}),m.jsx(_t,{path:"/memory-lane",element:m.jsx(d6,{})}),m.jsx(_t,{path:"/live",element:m.jsx(h6,{})})]}),m.jsx(_t,{path:"*",element:m.jsx(vx,{to:"/",replace:!0})})]})]})]})}Ka.createRoot(document.getElementById("root")).render(m.jsx(Gs.StrictMode,{children:m.jsxs(Tx,{children:[m.jsx(p6,{}),m.jsx(w2,{position:"top-right",toastOptions:{duration:4e3,style:{background:"rgba(255, 255, 255, 0.1)",backdropFilter:"blur(20px)",border:"1px solid rgba(255, 255, 255, 0.2)",color:"#fff"}}})]})})); diff --git a/dist/index.html b/dist/index.html index ad0342d..b71c8f3 100644 --- a/dist/index.html +++ b/dist/index.html @@ -6,7 +6,7 @@ 💕 Our Musical Journey - + diff --git a/frontend-dev.out b/frontend-dev.out index 97aec69..387a82f 100644 Binary files a/frontend-dev.out and b/frontend-dev.out differ diff --git a/preview-3443.out b/preview-3443.out new file mode 100644 index 0000000..753c56a --- /dev/null +++ b/preview-3443.out @@ -0,0 +1,2 @@ +(node:612693) [DEP0066] DeprecationWarning: OutgoingMessage.prototype._headers is deprecated +(Use `node --trace-deprecation ...` to show where the warning was created) diff --git a/prod.out b/prod.out new file mode 100644 index 0000000..892d018 Binary files /dev/null and b/prod.out differ diff --git a/prod.pid b/prod.pid new file mode 100644 index 0000000..c14ea8a --- /dev/null +++ b/prod.pid @@ -0,0 +1 @@ +631996 diff --git a/server-dev.out b/server-dev.out index 9396826..be73fac 100644 --- a/server-dev.out +++ b/server-dev.out @@ -4,412 +4,879 @@ API server (HTTP) listening on http://0.0.0.0:8081 API server (HTTPS) listening on https://0.0.0.0:8082 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 122.661 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 124.347 ms - 20 -11:46:14 AM [tsx] change in ./src/lib/spotify.ts Restarting... -cAPI server (HTTP) listening on http://0.0.0.0:8081 -API server (HTTPS) listening on https://0.0.0.0:8082 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 116.462 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 84.068 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.734 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 50.038 ms - 20 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.182 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.866 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.901 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.281 ms - 133957 -Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(1).jpeg -Failed to upload playlist image to Spotify: Request failed with status code 401 -Saving playlist to database: { - id: '402571a8-b5a8-4acd-ab3d-c95bf20ade4d', - name: 'Urban Harmony - Oct 16', - trackCount: 25, - trackUris: [ - 'spotify:track:6ls9KAHhzEoAZwniwREz4Y', - 'spotify:track:7ewUS7XNAWNmeVDtfGMkYS', - 'spotify:track:4cts1NKuolCnAx6EyUvXMp' - ] -} -POST /playlists/mixed 200 1833.840 ms - 1355 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.733 ms - 133957 -GET /api/placeholder-playlist-cover 200 3.367 ms - 563 -GET /api/placeholder-playlist-cover 200 0.903 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.933 ms - 133957 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 38.746 ms - 20 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.649 ms - 133957 -GET /api/placeholder-playlist-cover 200 2.809 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.022 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.779 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.753 ms - 133957 -GET /api/placeholder-playlist-cover 200 3.241 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.699 ms - 133957 -GET /api/placeholder-playlist-cover 200 3.093 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 5.518 ms - 133957 -GET /api/placeholder-playlist-cover 200 6.247 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.515 ms - 133957 -GET /api/placeholder-playlist-cover 200 3.173 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.225 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.443 ms - 563 -GET /api/placeholder-playlist-cover 200 1.314 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.308 ms - 133957 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.695 ms - 20 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.366 ms - 133957 -GET /api/placeholder-playlist-cover 200 2.061 ms - 563 +POST /auth/exchange 200 144.220 ms - 749 +POST /users/91416peucsefexd7z3q9875hw/sync 200 349.388 ms - 11 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 12.725 ms - 156666 +GET /users/91416peucsefexd7z3q9875hw 200 1.174 ms - 232 +GET /users/91416peucsefexd7z3q9875hw/top-tracks?time_range=short_term 200 4.523 ms - 73042 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 3.006 ms - 44 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.816 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 7.860 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.907 ms - 61623 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 9.232 ms - 156666 +GET /partners/requests/91416peucsefexd7z3q9875hw 200 11.611 ms - 2 +GET /users/91416peucsefexd7z3q9875hw/status 200 1.466 ms - 57 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.873 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 8.504 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 35.615 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 3.749 ms - 20 +GET /playlists/mixed 200 2.786 ms - 5029 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 3.610 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 2.557 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 2.834 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 5.850 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 3.053 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 3.028 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 6.302 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 9.533 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 12.364 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 5.427 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 9.141 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 2.173 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 3.012 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 3.370 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 2.712 ms - 204401 Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg -Failed to upload playlist image to Spotify: Request failed with status code 401 Saving playlist to database: { - id: 'f8ec78d4-61fd-4ca6-ac89-7a68ca220707', - name: 'Energetic Vibes - Oct 16', + id: '008255d7-98e8-493d-8bfd-659b0bdcbd09', + name: 'Chill Melody - Oct 16', trackCount: 25, trackUris: [ - 'spotify:track:3Iq8XToI0I9KSnqovkv1AV', - 'spotify:track:05od2qm2MTSKCHxy1GBp5W', - 'spotify:track:2ihCaVdNZmnHZWt0fvAM7B' + 'spotify:track:1FywSVKhuVzqVyuJrqDo2E', + 'spotify:track:5WwhpsQ9ARJEyCEZqyP15E', + 'spotify:track:0BVQNP096tuY7s9ggvtEOo' ] } -POST /playlists/mixed 200 1598.434 ms - 1357 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.428 ms - 133957 -GET /api/placeholder-playlist-cover 200 3.715 ms - 563 -GET /api/placeholder-playlist-cover 200 0.455 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.955 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.449 ms - 563 -GET /api/placeholder-playlist-cover 200 0.435 ms - 563 -DELETE /playlists/mixed/402571a8-b5a8-4acd-ab3d-c95bf20ade4d 200 2.092 ms - 16 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.152 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.487 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.115 ms - 20 -DELETE /playlists/mixed/f8ec78d4-61fd-4ca6-ac89-7a68ca220707 200 2.102 ms - 16 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.068 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.375 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.782 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.706 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.041 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.221 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.811 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.701 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.402 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.820 ms - 133957 -Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg -Failed to upload playlist image to Spotify: Request failed with status code 401 -Saving playlist to database: { - id: '8499a09c-65fb-4cc9-be27-8a4d124cf9b7', - name: 'Cosmic Rhythm - Oct 16', - trackCount: 25, - trackUris: [ - 'spotify:track:5IdsAZE15cZzXRG8sc5odK', - 'spotify:track:1tuQuawWDXfoc33NJdwvkd', - 'spotify:track:0xCmn4DDvatL81myxErTcR' - ] -} -POST /playlists/mixed 200 1429.947 ms - 1355 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.933 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.484 ms - 563 -GET /api/placeholder-playlist-cover 200 0.377 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.697 ms - 133957 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 74.662 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.461 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.903 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.336 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 84.966 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.583 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 49.930 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.645 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.998 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.312 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 37.621 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.736 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 60.872 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.101 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.628 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 34.661 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 93.374 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.185 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.281 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 87.633 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 86.173 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.098 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 38.095 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.413 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 57.037 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.259 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 86.496 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.286 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.538 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 86.311 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.530 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 113.127 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 45.480 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 46.395 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 56.122 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 109.522 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 80.657 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 35.693 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 94.003 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 45.205 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 46.407 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 93.980 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.058 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.262 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.547 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.242 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.258 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 57.022 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 87.483 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 46.228 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 84.729 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 37.597 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.872 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.307 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.058 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.571 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 59.094 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.266 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.166 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.000 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 47.374 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 80.154 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 49.615 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 99.950 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.954 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.544 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.140 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 82.217 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.072 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 56.040 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 104.363 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.945 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 86.977 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.330 ms - 20 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.273 ms - 44 -GET /playlists/mixed 200 2.253 ms - 3317 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 1.678 ms - 44 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.919 ms - 156666 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.981 ms - 57 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.824 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.895 ms - 61623 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 7.728 ms - 156852 -GET /partners/requests/91416peucsefexd7z3q9875hw 200 2.900 ms - 2 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.973 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.326 ms - 61623 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.822 ms - 156852 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.621 ms - 57 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.765 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 6.333 ms - 156666 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.316 ms - 20 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.281 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 1.790 ms - 20 -GET /api/placeholder-playlist-cover 200 0.592 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.319 ms - 133957 -GET /playlists/mixed 200 1.825 ms - 3317 -GET /api/placeholder-playlist-cover 200 1.095 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.954 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.566 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.067 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.854 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 4.463 ms - 133957 -GET /api/placeholder-playlist-cover 200 4.161 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.532 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.069 ms - 133957 -GET /api/placeholder-playlist-cover 200 1.154 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.546 ms - 20 -Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg -Failed to upload playlist image to Spotify: Request failed with status code 401 -Saving playlist to database: { - id: 'a1d4d7d6-4cd0-4491-a0a3-9a00d79c1a67', - name: 'Dynamic Journey - Oct 16', - trackCount: 25, - trackUris: [ - 'spotify:track:04a44cx2PJthIbN2aLMXhl', - 'spotify:track:7ne4VBA60CxGM75vw0EYad', - 'spotify:track:3siwsiaEoU4Kuuc9WKMUy5' - ] -} -POST /playlists/mixed 200 1344.283 ms - 1357 -GET /api/placeholder-playlist-cover 200 0.697 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.052 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.485 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.895 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.446 ms - 563 -GET /api/placeholder-playlist-cover 200 0.597 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 36.743 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 57.805 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.784 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 116.291 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 68.737 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.825 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 82.917 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.735 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.209 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.340 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.658 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.279 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 46.485 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.319 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 60.172 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 57.074 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.420 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.737 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.118 ms - 20 -POST /auth/exchange 200 169.914 ms - 749 -POST /users/91416peucsefexd7z3q9875hw/sync 200 333.677 ms - 11 -GET /users/91416peucsefexd7z3q9875hw 200 1.782 ms - 232 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 9.057 ms - 156666 -GET /users/91416peucsefexd7z3q9875hw/top-tracks?time_range=short_term 200 3.977 ms - 73042 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.235 ms - 44 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.883 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 6.558 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 4.078 ms - 61623 -GET /playlists/mixed 200 2.564 ms - 4947 -GET /api/placeholder-playlist-cover 200 0.613 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.389 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.578 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.697 ms - 156666 -GET /partners/requests/91416peucsefexd7z3q9875hw 200 2.920 ms - 2 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.912 ms - 57 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.730 ms - 57 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 35.508 ms - 20 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 6.000 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 1.662 ms - 20 -GET /api/placeholder-playlist-cover 200 0.685 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.455 ms - 133957 -GET /playlists/mixed 200 2.862 ms - 4947 -GET /api/placeholder-playlist-cover 200 0.631 ms - 563 -GET /api/placeholder-playlist-cover 200 0.459 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.043 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.562 ms - 563 -GET /api/placeholder-playlist-cover 200 0.526 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.909 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.513 ms - 563 -GET /api/placeholder-playlist-cover 200 0.470 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.081 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.445 ms - 563 -GET /api/placeholder-playlist-cover 200 0.966 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.980 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.598 ms - 563 -GET /api/placeholder-playlist-cover 200 0.660 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.422 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.597 ms - 563 -Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg -Failed to upload playlist image to Spotify: Request failed with status code 401 -Saving playlist to database: { - id: '018d648c-4bc5-4b77-a0d7-65ce22bd83c8', - name: 'Ethereal Journey - Oct 16', - trackCount: 25, - trackUris: [ - 'spotify:track:1I37Zz2g3hk9eWxaNkj031', - 'spotify:track:3siwsiaEoU4Kuuc9WKMUy5', - 'spotify:track:14F1zH9ZynOh2SuHCOskCO' - ] -} -POST /playlists/mixed 200 1501.613 ms - 1358 -GET /api/placeholder-playlist-cover 200 0.482 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.104 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.631 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.841 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.410 ms - 563 -GET /api/placeholder-playlist-cover 200 0.456 ms - 563 -GET /api/placeholder-playlist-cover 200 0.372 ms - 563 -GET /api/placeholder-playlist-cover 200 0.401 ms - 563 -GET / 404 1.896 ms - 139 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 3.051 ms - 44 -GET /playlists/mixed 200 1.902 ms - 6578 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 1.363 ms - 44 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.273 ms - 156666 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 46.904 ms - 20 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.157 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.537 ms - 61623 -GET /partners/requests/91416peucsefexd7z3q9875hw 200 2.761 ms - 2 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.689 ms - 57 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.847 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 1.964 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 7.561 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 9.130 ms - 61623 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.681 ms - 57 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.229 ms - 156666 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.413 ms - 156852 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 40.378 ms - 20 -GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 2.133 ms - 20 -GET /api/placeholder-playlist-cover 200 0.514 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 1.947 ms - 133957 -GET /playlists/mixed 200 1.735 ms - 6578 -GET /api/placeholder-playlist-cover 200 0.391 ms - 563 -GET /api/placeholder-playlist-cover 200 0.516 ms - 563 -GET /api/placeholder-playlist-cover 200 0.420 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.071 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.439 ms - 563 -GET /api/placeholder-playlist-cover 200 0.375 ms - 563 -1:05:52 PM [tsx] change in ./src/lib/spotify.ts Restarting... +POST /playlists/mixed 200 1772.528 ms - 1400 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 6.630 ms - 264761 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 11.088 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 12.794 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 6.741 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 3.646 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.497 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 6.103 ms - 144313 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29.jpeg 200 4.945 ms - 264761 +DELETE /playlists/mixed/a8580fac-781a-472e-94ce-ac88e7f67cb4 200 2.750 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 3.500 ms - 204401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.855 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(4).jpeg 200 5.074 ms - 144313 +DELETE /playlists/mixed/ac740cb2-3d6b-4a03-94d1-7c5bbb4514fa 200 2.122 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.704 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 6.880 ms - 204401 +DELETE /playlists/mixed/21f99970-416e-474a-8819-aaab31afa649 200 2.111 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.857 ms - 132357 +DELETE /playlists/mixed/008255d7-98e8-493d-8bfd-659b0bdcbd09 200 1.747 ms - 16 +2:06:12 PM [tsx] change in ./src/lib/spotify.ts Restarting... cAPI server (HTTP) listening on http://0.0.0.0:8081 API server (HTTPS) listening on https://0.0.0.0:8082 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 7.651 ms - 44 -GET /playlists/mixed 200 2.752 ms - 6578 -GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.748 ms - 44 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 6.800 ms - 156666 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 1.442 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.926 ms - 61623 -GET /partners/requests/91416peucsefexd7z3q9875hw 200 5.612 ms - 2 -GET /users/91416peucsefexd7z3q9875hw/status 200 1.290 ms - 57 -GET /users/31at7552nbs34vogjfzmasypv6vy 200 1.832 ms - 238 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 6.098 ms - 156852 -GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.316 ms - 61623 -GET /users/91416peucsefexd7z3q9875hw/status 200 0.869 ms - 57 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.840 ms - 156852 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 96.801 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/recently-played 200 7.880 ms - 156666 -GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.679 ms - 156852 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 50.219 ms - 20 -GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 1.817 ms - 20 -GET /api/placeholder-playlist-cover 200 0.678 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.330 ms - 133957 -GET /playlists/mixed 200 2.275 ms - 6578 -GET /api/placeholder-playlist-cover 200 0.564 ms - 563 -GET /api/placeholder-playlist-cover 200 0.467 ms - 563 -GET /api/placeholder-playlist-cover 200 0.496 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.922 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.408 ms - 563 -GET /api/placeholder-playlist-cover 200 0.479 ms - 563 -GET /api/placeholder-playlist-cover 200 0.893 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.588 ms - 133957 -GET /api/placeholder-playlist-cover 200 1.053 ms - 563 -GET /api/placeholder-playlist-cover 200 0.609 ms - 563 -GET /api/placeholder-playlist-cover 200 0.981 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.881 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.573 ms - 563 -GET /api/placeholder-playlist-cover 200 0.568 ms - 563 -GET /api/placeholder-playlist-cover 200 0.651 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.128 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.565 ms - 563 -GET /api/placeholder-playlist-cover 200 0.872 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 94.920 ms - 20 -GET /api/placeholder-playlist-cover 200 0.541 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.378 ms - 133957 -GET /api/placeholder-playlist-cover 200 0.580 ms - 563 -GET /api/placeholder-playlist-cover 200 0.515 ms - 563 -Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg -Saving playlist to database: { - id: '4bed041d-6933-433a-9cb1-e7dd0bbff3f1', - name: 'Dynamic Wave - Oct 16', +2:06:30 PM [tsx] change in ./src/lib/spotify.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:06:49 PM [tsx] change in ./src/lib/spotify.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:06:54 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:07:04 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:07:18 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:07:33 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:07:50 PM [tsx] change in ./src/lib/spotify.ts Restarting... +c2:07:51 PM [tsx] change in ./src/routes/playlists.ts Restarting... +API server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:00 PM [tsx] change in ./src/routes/playlists.ts Restarting... +c2:08:00 PM [tsx] change in ./src/routes/playlists.ts Restarting... +API server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:11 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:15 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:25 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:42 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:08:56 PM [tsx] change in ./src/lib/spotify.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +2:10:23 PM [tsx] change in ./src/routes/playlists.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +GET / 404 4.074 ms - 139 +2:10:52 PM [tsx] change in ./src/lib/spotify.ts Restarting... +cAPI server (HTTP) listening on http://0.0.0.0:8081 +API server (HTTPS) listening on https://0.0.0.0:8082 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 10.347 ms - 44 +GET /playlists/mixed 200 3.149 ms - 16 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.377 ms - 44 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 7.331 ms - 156666 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.987 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.810 ms - 61623 +GET /partners/requests/91416peucsefexd7z3q9875hw 200 2.445 ms - 2 +GET /users/91416peucsefexd7z3q9875hw/status 200 1.295 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 2.151 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 7.602 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.906 ms - 61623 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 98.682 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/status 200 7.454 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 1.046 ms - 238 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.938 ms - 156666 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 7.101 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.738 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 2.759 ms - 20 +GET /playlists/mixed 200 2.235 ms - 16 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'pop' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Ethereal Symphony - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Ethereal Symphony - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 0aUuc9FNcFaIFMuQm2tXdZ +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 14 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/cover1.svg (from file: cover1.svg) +[PLAYLIST COVER] Looking for file: cover1.svg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/cover1.svg +[PLAYLIST COVER] Attempting to upload cover image for playlist 0aUuc9FNcFaIFMuQm2tXdZ from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/cover1.svg +[PLAYLIST COVER] Image file size: 520 bytes (0.51 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 0aUuc9FNcFaIFMuQm2tXdZ: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 0aUuc9FNcFaIFMuQm2tXdZ, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 0aUuc9FNcFaIFMuQm2tXdZ +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: 'f9d6bf45-4b8f-472a-b482-e66fd88a3e16', + name: 'Ethereal Symphony - Oct 16', trackCount: 25, + creatorPlaylistId: '0aUuc9FNcFaIFMuQm2tXdZ', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/cover1.svg', trackUris: [ - 'spotify:track:7tXyps7cXLdb9zhoA0PMHs', - 'spotify:track:4SejSRZpC6hsrhqchmyfzk', - 'spotify:track:4vGvTtEHVl1orcHzSbqeYm' + 'spotify:track:2374M0fQpWi3dLnB54qaLX', + 'spotify:track:3siwsiaEoU4Kuuc9WKMUy5', + 'spotify:track:5DxDLsW6PsLz5gkwC7Mk5S' ] } -POST /playlists/mixed 200 1361.987 ms - 1400 -GET /api/placeholder-playlist-cover 200 0.722 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.676 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 6.924 ms - 204401 -GET /api/placeholder-playlist-cover 200 0.607 ms - 563 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.759 ms - 133957 -GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(5).jpeg 200 7.878 ms - 204401 -GET /api/placeholder-playlist-cover 200 0.460 ms - 563 -GET /api/placeholder-playlist-cover 200 0.413 ms - 563 -GET /api/placeholder-playlist-cover 200 0.396 ms - 563 -GET /api/placeholder-playlist-cover 200 0.402 ms - 563 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 87.092 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.905 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.070 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 80.755 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.340 ms - 20 -GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.713 ms - 20 -GET /partners/events/91416peucsefexd7z3q9875hw?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI5MTQxNnBldWNzZWZleGQ3ejNxOTg3NWh3IiwiaWF0IjoxNzYwNjA4ODMzLCJleHAiOjE3NjMyMDA4MzN9.WSdmfrirUCT-EqTtfisnlU3CdP1d8CMcGx52tNa5zSY 200 3.451 ms - - +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: 'f9d6bf45-4b8f-472a-b482-e66fd88a3e16', + name: 'Ethereal Symphony - Oct 16', + creatorPlaylistId: '0aUuc9FNcFaIFMuQm2tXdZ', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/cover1.svg' +} +POST /playlists/mixed 200 1429.828 ms - 1359 +GET /api/playlist-covers/cover1.svg 200 3.533 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.969 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.872 ms - 736 +GET /api/playlist-covers/cover1.svg 200 1.197 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.691 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.926 ms - 736 +GET /api/playlist-covers/cover1.svg 200 1.094 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.750 ms - 736 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'edm' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +GET /api/playlist-covers/cover1.svg 200 0.638 ms - 736 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Electric Sound - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Electric Sound - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 2PSoapi3TkMSQxQeJ1wEfy +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 14 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/cover1.svg (from file: cover1.svg) +[PLAYLIST COVER] Looking for file: cover1.svg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/cover1.svg +[PLAYLIST COVER] Attempting to upload cover image for playlist 2PSoapi3TkMSQxQeJ1wEfy from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/cover1.svg +[PLAYLIST COVER] Image file size: 520 bytes (0.51 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 2PSoapi3TkMSQxQeJ1wEfy: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 2PSoapi3TkMSQxQeJ1wEfy, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 2PSoapi3TkMSQxQeJ1wEfy +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: '8ec2d0d9-de93-4ee7-ab76-69dc6ea6b432', + name: 'Electric Sound - Oct 16', + trackCount: 25, + creatorPlaylistId: '2PSoapi3TkMSQxQeJ1wEfy', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/cover1.svg', + trackUris: [ + 'spotify:track:5WwhpsQ9ARJEyCEZqyP15E', + 'spotify:track:6jDJVFA6A77yJNKR6UJvZo', + 'spotify:track:2GgE1PFCZGjViqHjQUpYkz' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: '8ec2d0d9-de93-4ee7-ab76-69dc6ea6b432', + name: 'Electric Sound - Oct 16', + creatorPlaylistId: '2PSoapi3TkMSQxQeJ1wEfy', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/cover1.svg' +} +POST /playlists/mixed 200 1239.488 ms - 1356 +GET /api/playlist-covers/cover1.svg 200 0.613 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.759 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.689 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.667 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.969 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.757 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.999 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.927 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.763 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.873 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.677 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.809 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.867 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.766 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.803 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.678 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.800 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.764 ms - 736 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'rock' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +GET /api/playlist-covers/cover1.svg 200 0.874 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.756 ms - 736 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Harmonic Tune - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Harmonic Tune - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 53jyCWUlxwsRgl7v6gCmzo +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 14 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg (from file: WhatsApp Image 2025-10-16 at 11.12.30.jpeg) +[PLAYLIST COVER] Looking for file: WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg', + 'cover1.svg', + 'cover2.svg', + 'cover3.svg', + 'cover4.svg', + 'cover5.svg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.30.jpeg +[PLAYLIST COVER] Attempting to upload cover image for playlist 53jyCWUlxwsRgl7v6gCmzo from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.30.jpeg +[PLAYLIST COVER] Image file size: 98769 bytes (96.45 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 53jyCWUlxwsRgl7v6gCmzo: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 53jyCWUlxwsRgl7v6gCmzo, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 53jyCWUlxwsRgl7v6gCmzo +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: '8791c148-a234-4e08-8ff2-04f54f4348a1', + name: 'Harmonic Tune - Oct 16', + trackCount: 25, + creatorPlaylistId: '53jyCWUlxwsRgl7v6gCmzo', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg', + trackUris: [ + 'spotify:track:2zYzyRzz6pRmhPzyfMEC8s', + 'spotify:track:6QAsrXPnMSXIbV0yEJHlEX', + 'spotify:track:4Yf5bqU3NK4kNOypcrLYwU' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: '8791c148-a234-4e08-8ff2-04f54f4348a1', + name: 'Harmonic Tune - Oct 16', + creatorPlaylistId: '53jyCWUlxwsRgl7v6gCmzo', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg' +} +POST /playlists/mixed 200 1497.571 ms - 1395 +GET /api/playlist-covers/cover1.svg 200 1.352 ms - 736 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 5.426 ms - 131729 +GET /api/playlist-covers/cover1.svg 200 0.694 ms - 736 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.116 ms - 131729 +GET /api/playlist-covers/cover1.svg 200 0.757 ms - 736 +GET /api/playlist-covers/cover1.svg 200 0.685 ms - 736 +GET /api/playlist-covers/cover1.svg 404 0.725 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.131 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.736 ms - 27 +GET /api/playlist-covers/cover1.svg 404 0.627 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.331 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.537 ms - 27 +GET /api/playlist-covers/cover1.svg 404 0.683 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 1.895 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.571 ms - 27 +GET /api/playlist-covers/cover1.svg 404 1.176 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.786 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.588 ms - 27 +GET /api/playlist-covers/cover1.svg 404 1.487 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 3.403 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.698 ms - 27 +GET /api/playlist-covers/cover1.svg 404 0.659 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 3.457 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.695 ms - 27 +GET /api/playlist-covers/cover1.svg 404 1.205 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 3.829 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.572 ms - 27 +GET /api/playlist-covers/cover1.svg 404 0.953 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.118 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.782 ms - 27 +GET /api/playlist-covers/cover1.svg 404 1.583 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 4.709 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.857 ms - 27 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'indie' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +GET /api/playlist-covers/cover1.svg 404 1.120 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 3.859 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 1.464 ms - 27 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Dreamy Blend - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Dreamy Blend - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 3cNxtBOsaZdJyWo2DGytkJ +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 9 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg (from file: WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg) +[PLAYLIST COVER] Looking for file: WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg +[PLAYLIST COVER] Attempting to upload cover image for playlist 3cNxtBOsaZdJyWo2DGytkJ from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg +[PLAYLIST COVER] Image file size: 99239 bytes (96.91 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 3cNxtBOsaZdJyWo2DGytkJ: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 3cNxtBOsaZdJyWo2DGytkJ, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 3cNxtBOsaZdJyWo2DGytkJ +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: 'f66b57ab-0baa-4740-9303-fedbc5b90df6', + name: 'Dreamy Blend - Oct 16', + trackCount: 25, + creatorPlaylistId: '3cNxtBOsaZdJyWo2DGytkJ', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg', + trackUris: [ + 'spotify:track:0BxE4FqsDD1Ot4YuBXwAPp', + 'spotify:track:20B2I2t11yceg5v6CSdF2C', + 'spotify:track:1v1cijv1qjMJ5o9OvMWACS' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: 'f66b57ab-0baa-4740-9303-fedbc5b90df6', + name: 'Dreamy Blend - Oct 16', + creatorPlaylistId: '3cNxtBOsaZdJyWo2DGytkJ', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg' +} +POST /playlists/mixed 200 1488.677 ms - 1400 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.880 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 3.061 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 1.993 ms - 132357 +GET /api/playlist-covers/cover1.svg 404 0.668 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 1.960 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.936 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 1.543 ms - 132357 +GET /api/playlist-covers/cover1.svg 404 0.644 ms - 27 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.126 ms - 44 +GET /playlists/mixed 200 2.656 ms - 6620 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 2.145 ms - 44 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.171 ms - 156666 +GET /partners/requests/91416peucsefexd7z3q9875hw 200 3.568 ms - 2 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.821 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.420 ms - 61623 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.760 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.684 ms - 238 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.511 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.954 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 4.000 ms - 61623 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 4.409 ms - 238 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 6.305 ms - 156666 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.941 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 331.408 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 386.557 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 2.108 ms - 20 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 4.406 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 6.255 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 6.573 ms - 27 +GET /playlists/mixed 200 2.180 ms - 6620 +GET /api/playlist-covers/cover1.svg 404 0.499 ms - 27 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.759 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 5.424 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 0.527 ms - 27 +GET /api/playlist-covers/cover1.svg 404 0.985 ms - 27 +DELETE /playlists/mixed/8ec2d0d9-de93-4ee7-ab76-69dc6ea6b432 200 1.857 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.592 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.204 ms - 131729 +GET /api/playlist-covers/cover1.svg 404 2.529 ms - 27 +DELETE /playlists/mixed/f9d6bf45-4b8f-472a-b482-e66fd88a3e16 200 1.599 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.167 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 5.011 ms - 131729 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 1.746 ms - 44 +GET /playlists/mixed 200 2.243 ms - 3359 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 3.642 ms - 44 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 7.241 ms - 156666 +GET /partners/requests/91416peucsefexd7z3q9875hw 200 1.888 ms - 2 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.669 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.909 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 6.056 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.810 ms - 61623 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.602 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.725 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.653 ms - 61623 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 6.048 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.730 ms - 57 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.416 ms - 156666 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.647 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.441 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 2.167 ms - 20 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.594 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 4.424 ms - 131729 +GET /playlists/mixed 200 5.963 ms - 3359 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.812 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 1.637 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 1.989 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.290 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.188 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.014 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.943 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 6.145 ms - 131729 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'pop' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.525 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.561 ms - 132357 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Rhythmic Sound - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Rhythmic Sound - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 0st3z31nDWsY5T4oRMsZwF +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 9 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg (from file: WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg) +[PLAYLIST COVER] Looking for file: WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg +[PLAYLIST COVER] Attempting to upload cover image for playlist 0st3z31nDWsY5T4oRMsZwF from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg +[PLAYLIST COVER] Image file size: 203140 bytes (198.38 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 0st3z31nDWsY5T4oRMsZwF: Request failed with status code 413 +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 0st3z31nDWsY5T4oRMsZwF, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 0st3z31nDWsY5T4oRMsZwF +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: '8bba02a1-389e-46e8-b4a2-efbb016647a3', + name: 'Rhythmic Sound - Oct 16', + trackCount: 25, + creatorPlaylistId: '0st3z31nDWsY5T4oRMsZwF', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg', + trackUris: [ + 'spotify:track:6MrLkXsMmHaYt680fhJUAq', + 'spotify:track:5BZsQlgw21vDOAjoqkNgKb', + 'spotify:track:6dOtVTDdiauQNBQEDOtlAB' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: '8bba02a1-389e-46e8-b4a2-efbb016647a3', + name: 'Rhythmic Sound - Oct 16', + creatorPlaylistId: '0st3z31nDWsY5T4oRMsZwF', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg' +} +POST /playlists/mixed 200 1309.712 ms - 1402 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 4.178 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 6.168 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 4.953 ms - 270893 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.447 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 1.672 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 4.397 ms - 270893 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: [ 'pop' ], + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.961 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 6.393 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 9.415 ms - 270893 +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Vibrant Fusion - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Vibrant Fusion - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 0b7yrULu6aaBvXpeEUA4nR +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 9 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg (from file: WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg) +[PLAYLIST COVER] Looking for file: WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg +[PLAYLIST COVER] Attempting to upload cover image for playlist 0b7yrULu6aaBvXpeEUA4nR from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg +[PLAYLIST COVER] Image file size: 100438 bytes (98.08 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 0b7yrULu6aaBvXpeEUA4nR: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 0b7yrULu6aaBvXpeEUA4nR, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 0b7yrULu6aaBvXpeEUA4nR +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: 'bc5de7f1-f91c-45e8-9549-ff411e05f47d', + name: 'Vibrant Fusion - Oct 16', + trackCount: 25, + creatorPlaylistId: '0b7yrULu6aaBvXpeEUA4nR', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg', + trackUris: [ + 'spotify:track:5sBDrrtLGbV64QJnEqfjer', + 'spotify:track:05od2qm2MTSKCHxy1GBp5W', + 'spotify:track:62HoDY1Km6lm47haFpUn9c' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: 'bc5de7f1-f91c-45e8-9549-ff411e05f47d', + name: 'Vibrant Fusion - Oct 16', + creatorPlaylistId: '0b7yrULu6aaBvXpeEUA4nR', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg' +} +POST /playlists/mixed 200 1604.637 ms - 1402 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 2.817 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 4.009 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 3.588 ms - 270893 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 6.224 ms - 133957 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 1.734 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.503 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 3.109 ms - 270893 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.680 ms - 133957 +GET /partners/events/91416peucsefexd7z3q9875hw?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI5MTQxNnBldWNzZWZleGQ3ejNxOTg3NWh3IiwiaWF0IjoxNzYwNjE2MDA3LCJleHAiOjE3NjMyMDgwMDd9.E5NRRqWPxfauImmWE0zi1eQlckg6cPN1i-ojwyXnYuI 200 1.312 ms - - +GET /partners/events/91416peucsefexd7z3q9875hw?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI5MTQxNnBldWNzZWZleGQ3ejNxOTg3NWh3IiwiaWF0IjoxNzYwNjE2MDA3LCJleHAiOjE3NjMyMDgwMDd9.E5NRRqWPxfauImmWE0zi1eQlckg6cPN1i-ojwyXnYuI 200 2.337 ms - - +GET /partners/events/91416peucsefexd7z3q9875hw?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOiI5MTQxNnBldWNzZWZleGQ3ejNxOTg3NWh3IiwiaWF0IjoxNzYwNjE2MDA3LCJleHAiOjE3NjMyMDgwMDd9.E5NRRqWPxfauImmWE0zi1eQlckg6cPN1i-ojwyXnYuI 200 1.647 ms - - +GET /health 200 0.661 ms - 11 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 1.623 ms - 44 +GET /playlists/mixed 200 2.029 ms - 6709 +GET /partners/partner/91416peucsefexd7z3q9875hw 200 1.555 ms - 44 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 5.543 ms - 156666 +GET /partners/requests/91416peucsefexd7z3q9875hw 200 1.618 ms - 2 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.735 ms - 57 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 4.746 ms - 156852 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 0.913 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 2.492 ms - 61623 +GET /users/31at7552nbs34vogjfzmasypv6vy 200 2.921 ms - 238 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.500 ms - 156852 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 34.610 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/top-tracks?time_range=short_term 200 3.567 ms - 61623 +GET /users/91416peucsefexd7z3q9875hw/status 200 0.847 ms - 57 +GET /users/91416peucsefexd7z3q9875hw/recently-played 200 6.017 ms - 156666 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 32.753 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/now-playing 200 2.014 ms - 20 +GET /users/31at7552nbs34vogjfzmasypv6vy/recently-played 200 5.002 ms - 156852 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.188 ms - 133957 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 6.106 ms - 270893 +GET /playlists/mixed 200 2.215 ms - 6709 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 4.627 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 1.706 ms - 131729 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 3.480 ms - 133957 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 3.911 ms - 270893 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 5.660 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.253 ms - 131729 +DELETE /playlists/mixed/bc5de7f1-f91c-45e8-9549-ff411e05f47d 200 1.912 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30%20(2).jpeg 200 4.191 ms - 270893 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.256 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 4.664 ms - 131729 +DELETE /playlists/mixed/8bba02a1-389e-46e8-b4a2-efbb016647a3 200 1.718 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(3).jpeg 200 3.657 ms - 132357 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 5.127 ms - 131729 +DELETE /playlists/mixed/f66b57ab-0baa-4740-9303-fedbc5b90df6 200 1.900 ms - 16 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.30.jpeg 200 2.258 ms - 131729 +DELETE /playlists/mixed/8791c148-a234-4e08-8ff2-04f54f4348a1 200 2.063 ms - 16 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.599 ms - 20 +[MIXED PLAYLIST] Starting playlist creation process for creator: 91416peucsefexd7z3q9875hw, partner: 31at7552nbs34vogjfzmasypv6vy +[MIXED PLAYLIST] Request parameters: { + name: undefined, + description: 'An AI-blended mix with fresh recommendations', + vibe: undefined, + genres: undefined, + includeKnown: true, + createForBoth: false, + limit: 25 +} +[MIXED PLAYLIST] Collecting seed tracks from creator (91416peucsefexd7z3q9875hw) and partner (31at7552nbs34vogjfzmasypv6vy) +[MIXED PLAYLIST] Found 20 tracks from creator, 16 tracks from partner +[MIXED PLAYLIST] Total seed track URIs: 36 +Using fallback genres: [ 'pop', 'rock', 'indie', 'alternative' ] based on track analysis +[MIXED PLAYLIST] Creating Spotify playlist for creator: "Rhythmic Tune - Oct 16" +[PLAYLIST CREATION] Creating Spotify playlist: "Rhythmic Tune - Oct 16" for user: 91416peucsefexd7z3q9875hw +[PLAYLIST CREATION] Spotify playlist created successfully with ID: 3soGn0w8lRVvJrg26j4MFp +[PLAYLIST COVER] Looking for images in directory: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers +[PLAYLIST COVER] Found 9 image files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Selected random playlist cover: /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg (from file: WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg) +[PLAYLIST COVER] Looking for file: WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg in files: [ + 'WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (3).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (4).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29 (5).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.29.jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (1).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30 (2).jpeg', + 'WhatsApp Image 2025-10-16 at 11.12.30.jpeg' +] +[PLAYLIST COVER] Attempting to upload cover image: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg +[PLAYLIST COVER] Attempting to upload cover image for playlist 3soGn0w8lRVvJrg26j4MFp from path: /home/pschneid/Gulfslab/projects/spotify/server/public/playlist-covers/WhatsApp Image 2025-10-16 at 11.12.29 (1).jpeg +[PLAYLIST COVER] Image file size: 100438 bytes (98.08 KB) +[PLAYLIST COVER] Failed to upload cover image for playlist 3soGn0w8lRVvJrg26j4MFp: { error: { status: 401, message: 'Unauthorized.' } } +[PLAYLIST COVER] Failed to upload cover image to Spotify playlist 3soGn0w8lRVvJrg26j4MFp, but playlist was created successfully +[MIXED PLAYLIST] Adding 25 tracks to creator playlist 3soGn0w8lRVvJrg26j4MFp +[MIXED PLAYLIST] Successfully added tracks to creator playlist +[MIXED PLAYLIST] Saving playlist to database: { + id: '88d544c9-b1d8-4ec5-9a4e-268430dff2e7', + name: 'Rhythmic Tune - Oct 16', + trackCount: 25, + creatorPlaylistId: '3soGn0w8lRVvJrg26j4MFp', + partnerPlaylistId: undefined, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg', + trackUris: [ + 'spotify:track:0TFTAtCYhp2tQ9KcJIZb55', + 'spotify:track:3DwQ7AH3xGD9h65ezslm6q', + 'spotify:track:6S9q9mEifNdnTNlli2xSuD' + ] +} +[MIXED PLAYLIST] Playlist creation completed successfully: { + id: '88d544c9-b1d8-4ec5-9a4e-268430dff2e7', + name: 'Rhythmic Tune - Oct 16', + creatorPlaylistId: '3soGn0w8lRVvJrg26j4MFp', + partnerPlaylistId: undefined, + trackCount: 25, + imageUrl: '/api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg' +} +POST /playlists/mixed 200 2897.898 ms - 1401 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.457 ms - 133957 +GET /api/playlist-covers/WhatsApp%20Image%202025-10-16%20at%2011.12.29%20(1).jpeg 200 2.064 ms - 133957 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 44.537 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.326 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.071 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 63.326 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 83.462 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 48.190 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 86.442 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 55.034 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 74.207 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 88.228 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 34.562 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 89.815 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 51.537 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 52.542 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 59.649 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 50.169 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 87.490 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.943 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 55.879 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 56.865 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.869 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 85.565 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 53.059 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 54.127 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 98.826 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 87.836 ms - 20 +GET /users/91416peucsefexd7z3q9875hw/now-playing 200 91.096 ms - 20 diff --git a/server-dev.pid b/server-dev.pid index 48c903f..54c4153 100644 --- a/server-dev.pid +++ b/server-dev.pid @@ -1 +1 @@ -592323 +619472 diff --git a/server/dist/lib/spotify.js b/server/dist/lib/spotify.js index 38ff9db..52a5b9a 100644 --- a/server/dist/lib/spotify.js +++ b/server/dist/lib/spotify.js @@ -6,28 +6,37 @@ import path from 'path'; function generateRandomPlaylistImage() { try { const coversDir = path.join(process.cwd(), 'public', 'playlist-covers'); + console.log(`[PLAYLIST COVER] Looking for images in directory: ${coversDir}`); // Check if directory exists if (!fs.existsSync(coversDir)) { - console.log('Playlist covers directory not found, creating it...'); + console.log('[PLAYLIST COVER] Directory not found, creating it...'); fs.mkdirSync(coversDir, { recursive: true }); } - // Get all image files from the directory + // Get all image files from the directory (Spotify only accepts JPEG for cover uploads) const files = fs.readdirSync(coversDir).filter(file => { const ext = path.extname(file).toLowerCase(); - return ['.jpg', '.jpeg', '.png', '.webp', '.gif'].includes(ext); + return ['.jpg', '.jpeg'].includes(ext); // Only JPEG files for Spotify upload + }); + console.log(`[PLAYLIST COVER] Found ${files.length} image files:`, files); + // Log file sizes for debugging + files.forEach(file => { + const filePath = path.join(coversDir, file); + const stats = fs.statSync(filePath); + const sizeKB = (stats.size / 1024).toFixed(2); + console.log(`[PLAYLIST COVER] File: ${file}, Size: ${sizeKB} KB`); }); if (files.length === 0) { - console.log('No playlist cover images found in public/playlist-covers/'); + console.log('[PLAYLIST COVER] No playlist cover images found in public/playlist-covers/'); return '/api/placeholder-playlist-cover'; } // Select a random image const randomFile = files[Math.floor(Math.random() * files.length)]; const imageUrl = `/api/playlist-covers/${encodeURIComponent(randomFile)}`; - console.log(`Selected random playlist cover: ${imageUrl}`); + console.log(`[PLAYLIST COVER] Selected random playlist cover: ${imageUrl} (from file: ${randomFile})`); return imageUrl; } catch (error) { - console.error('Error generating random playlist image:', error); + console.error('[PLAYLIST COVER] Error generating random playlist image:', error); return '/api/placeholder-playlist-cover'; } } @@ -94,10 +103,43 @@ export async function fetchRecommendations(accessToken, seeds, targets, limit = return fetchSimilarTrackUris(accessToken, seeds.seed_tracks, seeds.seed_artists, seeds.seed_genres, targets, limit); } export async function createSpotifyPlaylist(accessToken, userId, name, description) { + console.log(`[PLAYLIST CREATION] Creating Spotify playlist: "${name}" for user: ${userId}`); const resp = await axios.post(`https://api.spotify.com/v1/users/${encodeURIComponent(userId)}/playlists`, { name, description, public: false }, { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); const pl = resp.data; + console.log(`[PLAYLIST CREATION] Spotify playlist created successfully with ID: ${pl.id}`); // Generate a random local playlist cover image const imageUrl = generateRandomPlaylistImage(); + // Extract the filename from the imageUrl to use the SAME image for Spotify upload + const selectedFilename = decodeURIComponent(imageUrl.replace('/api/playlist-covers/', '')); + console.log(`[PLAYLIST COVER] Selected image for both website and Spotify: ${selectedFilename}`); + // Get the actual file path for uploading to Spotify (only JPEG files) + const coversDir = path.join(process.cwd(), 'public', 'playlist-covers'); + const files = fs.readdirSync(coversDir).filter(file => { + const ext = path.extname(file).toLowerCase(); + return ['.jpg', '.jpeg'].includes(ext); // Only JPEG files for Spotify upload + }); + if (files.length > 0) { + // Find the specific file that was selected for the website + const selectedFile = files.find(file => file === selectedFilename); + if (selectedFile) { + const imagePath = path.join(coversDir, selectedFile); + const stats = fs.statSync(imagePath); + const fileSizeKB = (stats.size / 1024).toFixed(2); + console.log(`[PLAYLIST COVER] Using SAME image for Spotify upload: ${selectedFile} (${fileSizeKB} KB)`); + // Upload the SAME cover image to Spotify + const uploadSuccess = await uploadPlaylistCover(accessToken, pl.id, imagePath); + if (uploadSuccess) { + console.log(`[PLAYLIST COVER] ✅ Successfully uploaded SAME cover image to Spotify playlist ${pl.id}`); + } + else { + console.log(`[PLAYLIST COVER] ❌ Failed to upload ${selectedFile} to Spotify, but website will still show it`); + } + } + else { + console.log(`[PLAYLIST COVER] ⚠️ Could not find selected file ${selectedFilename} for Spotify upload`); + console.log(`[PLAYLIST COVER] ✅ WEBSITE COVER: Random cover image will still be displayed on your website.`); + } + } return { id: pl.id, url: pl.external_urls?.spotify, imageUrl }; } export async function addTracks(accessToken, playlistId, trackUris) { @@ -105,6 +147,128 @@ export async function addTracks(accessToken, playlistId, trackUris) { return; await axios.post(`https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/tracks`, { uris: trackUris }, { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' } }); } +// Upload a playlist cover image to Spotify +export async function uploadPlaylistCover(accessToken, playlistId, imagePath) { + try { + console.log(`[PLAYLIST COVER] Attempting to upload cover image for playlist ${playlistId} from path: ${imagePath}`); + // Check if file exists + if (!fs.existsSync(imagePath)) { + console.error(`[PLAYLIST COVER] Image file not found: ${imagePath}`); + return false; + } + // Read the image file + let imageBuffer = fs.readFileSync(imagePath); + let fileSize = imageBuffer.length; + console.log(`[PLAYLIST COVER] Original image file size: ${fileSize} bytes (${(fileSize / 1024).toFixed(2)} KB)`); + // Check if we need to compress the image + // We need to account for base64 encoding overhead (33% increase) + // So we want the original file to be under ~190 KB to stay under 256 KB when base64 encoded + const maxOriginalSize = 190 * 1024; // 190 KB + if (fileSize > maxOriginalSize) { + console.log(`[PLAYLIST COVER] Image too large (${(fileSize / 1024).toFixed(2)} KB), attempting to compress...`); + // For now, let's skip files that are too large and try a different one + console.error(`[PLAYLIST COVER] Image file too large for Spotify upload: ${fileSize} bytes (max ~190 KB to account for base64 overhead)`); + return false; + } + // Convert to base64 + let base64Image = imageBuffer.toString('base64'); + const base64Size = base64Image.length; + console.log(`[PLAYLIST COVER] Base64 length: ${base64Size} characters (${(base64Size / 1024).toFixed(2)} KB)`); + // Ensure we don't have any data URL prefix + if (base64Image.startsWith('data:')) { + base64Image = base64Image.split(',')[1] || base64Image; + console.log(`[PLAYLIST COVER] Removed data URL prefix from base64`); + } + // Final check - ensure base64 size is reasonable + if (base64Size > 300 * 1024) { // 300 KB base64 limit + console.error(`[PLAYLIST COVER] Base64 encoded image too large: ${base64Size} characters`); + return false; + } + // Determine content type based on file extension + const ext = path.extname(imagePath).toLowerCase(); + let contentType = 'image/jpeg'; // default + switch (ext) { + case '.png': + contentType = 'image/png'; + break; + case '.gif': + contentType = 'image/gif'; + break; + case '.webp': + contentType = 'image/webp'; + break; + case '.svg': + contentType = 'image/svg+xml'; + break; + case '.jpg': + case '.jpeg': + contentType = 'image/jpeg'; + break; + } + console.log(`[PLAYLIST COVER] Using content type: ${contentType}`); + // Check token scopes first + try { + console.log(`[PLAYLIST COVER] Checking token scopes...`); + const meResponse = await axios.get('https://api.spotify.com/v1/me', { + headers: { 'Authorization': `Bearer ${accessToken}` } + }); + console.log(`[PLAYLIST COVER] Token is valid for user: ${meResponse.data.display_name}`); + // Test if we can access the playlist + const playlistResponse = await axios.get(`https://api.spotify.com/v1/playlists/${playlistId}`, { + headers: { 'Authorization': `Bearer ${accessToken}` } + }); + console.log(`[PLAYLIST COVER] Can access playlist: ${playlistResponse.data.name}`); + } + catch (error) { + console.error(`[PLAYLIST COVER] Token validation failed:`, error.response?.data || error.message); + } + // Upload to Spotify + console.log(`[PLAYLIST COVER] Making request to Spotify API: https://api.spotify.com/v1/playlists/${playlistId}/images`); + console.log(`[PLAYLIST COVER] Access token (first 20 chars): ${accessToken.substring(0, 20)}...`); + // Try different approaches for image upload + let response; + try { + // Method 1: Standard PUT request (requires ugc-image-upload scope) + response = await axios.put(`https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/images`, base64Image, { + headers: { + 'Authorization': `Bearer ${accessToken}`, + 'Content-Type': contentType + } + }); + } + catch (error) { + if (error.response?.status === 401) { + console.log(`[PLAYLIST COVER] Method 1 failed with 401, trying alternative approach...`); + // Method 2: Try with different content type + try { + response = await axios.put(`https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/images`, base64Image, { + headers: { + 'Authorization': `Bearer ${accessToken}`, + 'Content-Type': 'image/jpeg' // Force JPEG content type + } + }); + } + catch (error2) { + console.log(`[PLAYLIST COVER] Method 2 also failed: ${error2.response?.status}`); + throw error; // Re-throw original error + } + } + else { + throw error; // Re-throw if not 401 + } + } + console.log(`[PLAYLIST COVER] Successfully uploaded cover image for playlist ${playlistId}, response status: ${response.status}`); + console.log(`[PLAYLIST COVER] Response headers:`, response.headers); + return true; + } + catch (error) { + console.error(`[PLAYLIST COVER] Failed to upload cover image for playlist ${playlistId}:`); + console.error(`[PLAYLIST COVER] Error status:`, error.response?.status); + console.error(`[PLAYLIST COVER] Error data:`, error.response?.data); + console.error(`[PLAYLIST COVER] Error message:`, error.message); + return false; + } +} // ----- New: Similar tracks without recommendations endpoint ----- async function getRelatedArtists(accessToken, artistId) { const resp = await axios.get(`https://api.spotify.com/v1/artists/${encodeURIComponent(artistId)}/related-artists`, { diff --git a/server/dist/routes/playlists.js b/server/dist/routes/playlists.js index 45f9738..3565f29 100644 --- a/server/dist/routes/playlists.js +++ b/server/dist/routes/playlists.js @@ -54,16 +54,21 @@ playlistsRouter.post('/mixed', requireAuth, async (req, res) => { try { const creatorId = req.user.uid; const { name, description, vibe, genres, includeKnown = true, partnerId, createForBoth = false, limit = 25 } = req.body || {}; + console.log(`[MIXED PLAYLIST] Starting playlist creation process for creator: ${creatorId}, partner: ${partnerId}`); + console.log(`[MIXED PLAYLIST] Request parameters:`, { name, description, vibe, genres, includeKnown, createForBoth, limit }); if (!partnerId) return res.status(400).json({ error: 'partnerId required' }); // Collect seeds from both users' top tracks + console.log(`[MIXED PLAYLIST] Collecting seed tracks from creator (${creatorId}) and partner (${partnerId})`); const seedRows1 = db.db.prepare('SELECT track_json FROM top_tracks WHERE user_id=? AND time_range=? ORDER BY rank ASC LIMIT 20').all(creatorId, 'short_term'); const seedRows2 = db.db.prepare('SELECT track_json FROM top_tracks WHERE user_id=? AND time_range=? ORDER BY rank ASC LIMIT 20').all(partnerId, 'short_term'); const tracks1 = seedRows1.map((r) => JSON.parse(r.track_json)); const tracks2 = seedRows2.map((r) => JSON.parse(r.track_json)); + console.log(`[MIXED PLAYLIST] Found ${tracks1.length} tracks from creator, ${tracks2.length} tracks from partner`); let seedTrackUris = [...tracks1, ...tracks2] .map((t) => t.uri || (t.id ? `spotify:track:${t.id}` : null)) .filter((u) => !!u); + console.log(`[MIXED PLAYLIST] Total seed track URIs: ${seedTrackUris.length}`); // Fallback to artist seeds if track seeds are empty let seedArtistIds = []; if (seedTrackUris.length === 0) { @@ -123,36 +128,45 @@ playlistsRouter.post('/mixed', requireAuth, async (req, res) => { const playlistName = name || generateUniquePlaylistName(); const playlistDesc = description || 'An AI-blended mix with fresh recommendations'; // Always create for the creator + console.log(`[MIXED PLAYLIST] Creating Spotify playlist for creator: "${playlistName}"`); const creatorProfile = db.db.prepare('SELECT id FROM users WHERE id=?').get(creatorId); const { id: creatorPlaylistId, url: creatorUrl, imageUrl: creatorImageUrl } = await createSpotifyPlaylist(creatorToken, creatorProfile.id, playlistName, playlistDesc); + console.log(`[MIXED PLAYLIST] Adding ${finalUris.length} tracks to creator playlist ${creatorPlaylistId}`); await addTracks(creatorToken, creatorPlaylistId, finalUris); + console.log(`[MIXED PLAYLIST] Successfully added tracks to creator playlist`); let partnerResult = {}; if (createForBoth) { + console.log(`[MIXED PLAYLIST] Creating playlist for partner as well: ${partnerId}`); try { const partnerToken = await ensureValidAccessToken(partnerId); const partnerProfile = db.db.prepare('SELECT id FROM users WHERE id=?').get(partnerId); if (!partnerProfile) { throw new Error('Partner user not found'); } + console.log(`[MIXED PLAYLIST] Creating Spotify playlist for partner: "${playlistName}"`); const partnerPlaylist = await createSpotifyPlaylist(partnerToken, partnerProfile.id, playlistName, playlistDesc); partnerResult = partnerPlaylist; + console.log(`[MIXED PLAYLIST] Adding ${finalUris.length} tracks to partner playlist ${partnerResult.id}`); await addTracks(partnerToken, partnerResult.id, finalUris); - console.log(`Successfully created partner playlist: ${partnerResult.id}`); + console.log(`[MIXED PLAYLIST] Successfully created partner playlist: ${partnerResult.id}`); } catch (e) { // Partner creation may fail (revoked consent, user not found, etc.); still return creator playlist const errorMessage = e?.response?.data?.error?.message || e?.message || 'Unknown error'; - console.error('Partner playlist creation failed:', errorMessage); + console.error('[MIXED PLAYLIST] Partner playlist creation failed:', errorMessage); partnerResult.error = errorMessage; } } // Save playlist to database const playlistId = uuidv4(); const now = Date.now(); - console.log('Saving playlist to database:', { + console.log('[MIXED PLAYLIST] Saving playlist to database:', { id: playlistId, name: playlistName, trackCount: finalUris.length, + creatorPlaylistId, + partnerPlaylistId: partnerResult.id, + imageUrl: creatorImageUrl, trackUris: finalUris.slice(0, 3) // Log first 3 URIs for debugging }); db.db.prepare(` @@ -163,7 +177,7 @@ playlistsRouter.post('/mixed', requireAuth, async (req, res) => { created_at, updated_at ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run(playlistId, creatorId, partnerId, playlistName, playlistDesc, vibe || null, JSON.stringify(genres || []), JSON.stringify(finalUris), creatorPlaylistId, partnerResult.id || null, creatorUrl, partnerResult.url || null, creatorImageUrl || null, partnerResult.imageUrl || null, now, now); - res.json({ + const response = { id: playlistId, name: playlistName, description: playlistDesc, @@ -175,11 +189,21 @@ playlistsRouter.post('/mixed', requireAuth, async (req, res) => { partnerError: partnerResult.error || null, }, added: finalUris.length, + }; + console.log('[MIXED PLAYLIST] Playlist creation completed successfully:', { + id: playlistId, + name: playlistName, + creatorPlaylistId, + partnerPlaylistId: partnerResult.id, + trackCount: finalUris.length, + imageUrl: creatorImageUrl }); + res.json(response); } catch (err) { const detail = err?.response?.data || err?.message || 'Unknown error'; - console.error('Mixed playlist error:', detail); + console.error('[MIXED PLAYLIST] Error during playlist creation:', detail); + console.error('[MIXED PLAYLIST] Full error object:', err); res.status(500).json({ error: 'Failed to create mixed playlist', detail }); } }); diff --git a/server/node_modules/.package-lock.json b/server/node_modules/.package-lock.json index 3777df8..c725311 100644 --- a/server/node_modules/.package-lock.json +++ b/server/node_modules/.package-lock.json @@ -46,6 +46,22 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.3.tgz", + "integrity": "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@img/sharp-linux-x64": { "version": "0.34.4", "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.4.tgz", @@ -68,6 +84,28 @@ "@img/sharp-libvips-linux-x64": "1.2.3" } }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.4", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.4.tgz", + "integrity": "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + } + }, "node_modules/@types/better-sqlite3": { "version": "7.6.13", "resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz", diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md new file mode 100644 index 0000000..a220ae4 --- /dev/null +++ b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md @@ -0,0 +1,46 @@ +# `@img/sharp-libvips-linuxmusl-x64` + +Prebuilt libvips and dependencies for use with sharp on Linux (musl) x64. + +## Licensing + +This software contains third-party libraries +used under the terms of the following licences: + +| Library | Used under the terms of | +|---------------|-----------------------------------------------------------------------------------------------------------| +| aom | BSD 2-Clause + [Alliance for Open Media Patent License 1.0](https://aomedia.org/license/patent-license/) | +| cairo | Mozilla Public License 2.0 | +| cgif | MIT Licence | +| expat | MIT Licence | +| fontconfig | [fontconfig Licence](https://gitlab.freedesktop.org/fontconfig/fontconfig/blob/main/COPYING) (BSD-like) | +| freetype | [freetype Licence](https://git.savannah.gnu.org/cgit/freetype/freetype2.git/tree/docs/FTL.TXT) (BSD-like) | +| fribidi | LGPLv3 | +| glib | LGPLv3 | +| harfbuzz | MIT Licence | +| highway | Apache-2.0 License, BSD 3-Clause | +| lcms | MIT Licence | +| libarchive | BSD 2-Clause | +| libexif | LGPLv3 | +| libffi | MIT Licence | +| libheif | LGPLv3 | +| libimagequant | [BSD 2-Clause](https://github.com/lovell/libimagequant/blob/main/COPYRIGHT) | +| libnsgif | MIT Licence | +| libpng | [libpng License](https://github.com/pnggroup/libpng/blob/master/LICENSE) | +| librsvg | LGPLv3 | +| libspng | [BSD 2-Clause, libpng License](https://github.com/randy408/libspng/blob/master/LICENSE) | +| libtiff | [libtiff License](https://gitlab.com/libtiff/libtiff/blob/master/LICENSE.md) (BSD-like) | +| libvips | LGPLv3 | +| libwebp | New BSD License | +| libxml2 | MIT Licence | +| mozjpeg | [zlib License, IJG License, BSD-3-Clause](https://github.com/mozilla/mozjpeg/blob/master/LICENSE.md) | +| pango | LGPLv3 | +| pixman | MIT Licence | +| proxy-libintl | LGPLv3 | +| zlib-ng | [zlib Licence](https://github.com/zlib-ng/zlib-ng/blob/develop/LICENSE.md) | + +Use of libraries under the terms of the LGPLv3 is via the +"any later version" clause of the LGPLv2 or LGPLv2.1. + +Please report any errors or omissions via +https://github.com/lovell/sharp-libvips/issues/new diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h new file mode 100644 index 0000000..17473b8 --- /dev/null +++ b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h @@ -0,0 +1,221 @@ +/* glibconfig.h + * + * This is a generated file. Please modify 'glibconfig.h.in' + */ + +#ifndef __GLIBCONFIG_H__ +#define __GLIBCONFIG_H__ + +#include + +#include +#include +#define GLIB_HAVE_ALLOCA_H + +#define GLIB_STATIC_COMPILATION 1 +#define GOBJECT_STATIC_COMPILATION 1 +#define GIO_STATIC_COMPILATION 1 +#define GMODULE_STATIC_COMPILATION 1 +#define GI_STATIC_COMPILATION 1 +#define G_INTL_STATIC_COMPILATION 1 +#define FFI_STATIC_BUILD 1 + +/* Specifies that GLib's g_print*() functions wrap the + * system printf functions. This is useful to know, for example, + * when using glibc's register_printf_function(). + */ +#define GLIB_USING_SYSTEM_PRINTF + +G_BEGIN_DECLS + +#define G_MINFLOAT FLT_MIN +#define G_MAXFLOAT FLT_MAX +#define G_MINDOUBLE DBL_MIN +#define G_MAXDOUBLE DBL_MAX +#define G_MINSHORT SHRT_MIN +#define G_MAXSHORT SHRT_MAX +#define G_MAXUSHORT USHRT_MAX +#define G_MININT INT_MIN +#define G_MAXINT INT_MAX +#define G_MAXUINT UINT_MAX +#define G_MINLONG LONG_MIN +#define G_MAXLONG LONG_MAX +#define G_MAXULONG ULONG_MAX + +typedef signed char gint8; +typedef unsigned char guint8; + +typedef signed short gint16; +typedef unsigned short guint16; + +#define G_GINT16_MODIFIER "h" +#define G_GINT16_FORMAT "hi" +#define G_GUINT16_FORMAT "hu" + + +typedef signed int gint32; +typedef unsigned int guint32; + +#define G_GINT32_MODIFIER "" +#define G_GINT32_FORMAT "i" +#define G_GUINT32_FORMAT "u" + + +#define G_HAVE_GINT64 1 /* deprecated, always true */ + +typedef signed long gint64; +typedef unsigned long guint64; + +#define G_GINT64_CONSTANT(val) (val##L) +#define G_GUINT64_CONSTANT(val) (val##UL) + +#define G_GINT64_MODIFIER "l" +#define G_GINT64_FORMAT "li" +#define G_GUINT64_FORMAT "lu" + + +#define GLIB_SIZEOF_VOID_P 8 +#define GLIB_SIZEOF_LONG 8 +#define GLIB_SIZEOF_SIZE_T 8 +#define GLIB_SIZEOF_SSIZE_T 8 + +typedef signed long gssize; +typedef unsigned long gsize; +#define G_GSIZE_MODIFIER "l" +#define G_GSSIZE_MODIFIER "l" +#define G_GSIZE_FORMAT "lu" +#define G_GSSIZE_FORMAT "li" + +#define G_MAXSIZE G_MAXULONG +#define G_MINSSIZE G_MINLONG +#define G_MAXSSIZE G_MAXLONG + +typedef gint64 goffset; +#define G_MINOFFSET G_MININT64 +#define G_MAXOFFSET G_MAXINT64 + +#define G_GOFFSET_MODIFIER G_GINT64_MODIFIER +#define G_GOFFSET_FORMAT G_GINT64_FORMAT +#define G_GOFFSET_CONSTANT(val) G_GINT64_CONSTANT(val) + +#define G_POLLFD_FORMAT "%d" + +#define GPOINTER_TO_INT(p) ((gint) (glong) (p)) +#define GPOINTER_TO_UINT(p) ((guint) (gulong) (p)) + +#define GINT_TO_POINTER(i) ((gpointer) (glong) (i)) +#define GUINT_TO_POINTER(u) ((gpointer) (gulong) (u)) + +typedef signed long gintptr; +typedef unsigned long guintptr; + +#define G_GINTPTR_MODIFIER "l" +#define G_GINTPTR_FORMAT "li" +#define G_GUINTPTR_FORMAT "lu" + +#define GLIB_MAJOR_VERSION 2 +#define GLIB_MINOR_VERSION 86 +#define GLIB_MICRO_VERSION 0 + +#define G_OS_UNIX + +#define G_VA_COPY va_copy + +#define G_VA_COPY_AS_ARRAY 1 + +#define G_HAVE_ISO_VARARGS 1 + +/* gcc-2.95.x supports both gnu style and ISO varargs, but if -ansi + * is passed ISO vararg support is turned off, and there is no work + * around to turn it on, so we unconditionally turn it off. + */ +#if __GNUC__ == 2 && __GNUC_MINOR__ == 95 +# undef G_HAVE_ISO_VARARGS +#endif + +#define G_HAVE_GROWING_STACK 0 + +#ifndef _MSC_VER +# define G_HAVE_GNUC_VARARGS 1 +#endif + +#if defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590) +#define G_GNUC_INTERNAL __attribute__((visibility("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define G_GNUC_INTERNAL __hidden +#elif defined (__GNUC__) && defined (G_HAVE_GNUC_VISIBILITY) +#define G_GNUC_INTERNAL __attribute__((visibility("hidden"))) +#else +#define G_GNUC_INTERNAL +#endif + +#define G_THREADS_ENABLED +#define G_THREADS_IMPL_POSIX + +#define G_ATOMIC_LOCK_FREE + +#define GINT16_TO_LE(val) ((gint16) (val)) +#define GUINT16_TO_LE(val) ((guint16) (val)) +#define GINT16_TO_BE(val) ((gint16) GUINT16_SWAP_LE_BE (val)) +#define GUINT16_TO_BE(val) (GUINT16_SWAP_LE_BE (val)) + +#define GINT32_TO_LE(val) ((gint32) (val)) +#define GUINT32_TO_LE(val) ((guint32) (val)) +#define GINT32_TO_BE(val) ((gint32) GUINT32_SWAP_LE_BE (val)) +#define GUINT32_TO_BE(val) (GUINT32_SWAP_LE_BE (val)) + +#define GINT64_TO_LE(val) ((gint64) (val)) +#define GUINT64_TO_LE(val) ((guint64) (val)) +#define GINT64_TO_BE(val) ((gint64) GUINT64_SWAP_LE_BE (val)) +#define GUINT64_TO_BE(val) (GUINT64_SWAP_LE_BE (val)) + +#define GLONG_TO_LE(val) ((glong) GINT64_TO_LE (val)) +#define GULONG_TO_LE(val) ((gulong) GUINT64_TO_LE (val)) +#define GLONG_TO_BE(val) ((glong) GINT64_TO_BE (val)) +#define GULONG_TO_BE(val) ((gulong) GUINT64_TO_BE (val)) +#define GINT_TO_LE(val) ((gint) GINT32_TO_LE (val)) +#define GUINT_TO_LE(val) ((guint) GUINT32_TO_LE (val)) +#define GINT_TO_BE(val) ((gint) GINT32_TO_BE (val)) +#define GUINT_TO_BE(val) ((guint) GUINT32_TO_BE (val)) +#define GSIZE_TO_LE(val) ((gsize) GUINT64_TO_LE (val)) +#define GSSIZE_TO_LE(val) ((gssize) GINT64_TO_LE (val)) +#define GSIZE_TO_BE(val) ((gsize) GUINT64_TO_BE (val)) +#define GSSIZE_TO_BE(val) ((gssize) GINT64_TO_BE (val)) +#define G_BYTE_ORDER G_LITTLE_ENDIAN + +#define GLIB_SYSDEF_POLLIN =1 +#define GLIB_SYSDEF_POLLOUT =4 +#define GLIB_SYSDEF_POLLPRI =2 +#define GLIB_SYSDEF_POLLHUP =16 +#define GLIB_SYSDEF_POLLERR =8 +#define GLIB_SYSDEF_POLLNVAL =32 + +/* No way to disable deprecation warnings for macros, so only emit deprecation + * warnings on platforms where usage of this macro is broken */ +#if defined(__APPLE__) || defined(_MSC_VER) || defined(__CYGWIN__) +#define G_MODULE_SUFFIX "so" GLIB_DEPRECATED_MACRO_IN_2_76 +#else +#define G_MODULE_SUFFIX "so" +#endif + +typedef int GPid; +#define G_PID_FORMAT "i" + +#define GLIB_SYSDEF_AF_UNIX 1 +#define GLIB_SYSDEF_AF_INET 2 +#define GLIB_SYSDEF_AF_INET6 10 + +#define GLIB_SYSDEF_MSG_OOB 1 +#define GLIB_SYSDEF_MSG_PEEK 2 +#define GLIB_SYSDEF_MSG_DONTROUTE 4 + +#define G_DIR_SEPARATOR '/' +#define G_DIR_SEPARATOR_S "/" +#define G_SEARCHPATH_SEPARATOR ':' +#define G_SEARCHPATH_SEPARATOR_S ":" + +#undef G_HAVE_FREE_SIZED + +G_END_DECLS + +#endif /* __GLIBCONFIG_H__ */ diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js new file mode 100644 index 0000000..5092b4d --- /dev/null +++ b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js @@ -0,0 +1 @@ +module.exports = __dirname; diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.2 b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.2 new file mode 100644 index 0000000..70f27e6 Binary files /dev/null and b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.2 differ diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json new file mode 100644 index 0000000..b55f0d2 --- /dev/null +++ b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json @@ -0,0 +1,42 @@ +{ + "name": "@img/sharp-libvips-linuxmusl-x64", + "version": "1.2.3", + "description": "Prebuilt libvips and dependencies for use with sharp on Linux (musl) x64", + "author": "Lovell Fuller ", + "homepage": "https://sharp.pixelplumbing.com", + "repository": { + "type": "git", + "url": "git+https://github.com/lovell/sharp-libvips.git", + "directory": "npm/linuxmusl-x64" + }, + "license": "LGPL-3.0-or-later", + "funding": { + "url": "https://opencollective.com/libvips" + }, + "preferUnplugged": true, + "publishConfig": { + "access": "public" + }, + "files": [ + "lib", + "versions.json" + ], + "type": "commonjs", + "exports": { + "./lib": "./lib/index.js", + "./package": "./package.json", + "./versions": "./versions.json" + }, + "config": { + "musl": ">=1.2.2" + }, + "os": [ + "linux" + ], + "libc": [ + "musl" + ], + "cpu": [ + "x64" + ] +} diff --git a/server/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json new file mode 100644 index 0000000..d9cced1 --- /dev/null +++ b/server/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json @@ -0,0 +1,30 @@ +{ + "aom": "3.13.1", + "archive": "3.8.1", + "cairo": "1.18.4", + "cgif": "0.5.0", + "exif": "0.6.25", + "expat": "2.7.2", + "ffi": "3.5.2", + "fontconfig": "2.17.1", + "freetype": "2.14.1", + "fribidi": "1.0.16", + "glib": "2.86.0", + "harfbuzz": "11.5.0", + "heif": "1.20.2", + "highway": "1.3.0", + "imagequant": "2.4.1", + "lcms": "2.17", + "mozjpeg": "4.1.5", + "pango": "1.57.0", + "pixman": "0.46.4", + "png": "1.6.50", + "proxy-libintl": "0.5", + "rsvg": "2.61.1", + "spng": "0.7.4", + "tiff": "4.7.0", + "vips": "8.17.2", + "webp": "1.6.0", + "xml2": "2.15.0", + "zlib-ng": "2.2.5" +} \ No newline at end of file diff --git a/server/node_modules/@img/sharp-linuxmusl-x64/LICENSE b/server/node_modules/@img/sharp-linuxmusl-x64/LICENSE new file mode 100644 index 0000000..37ec93a --- /dev/null +++ b/server/node_modules/@img/sharp-linuxmusl-x64/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/server/node_modules/@img/sharp-linuxmusl-x64/README.md b/server/node_modules/@img/sharp-linuxmusl-x64/README.md new file mode 100644 index 0000000..f651f98 --- /dev/null +++ b/server/node_modules/@img/sharp-linuxmusl-x64/README.md @@ -0,0 +1,18 @@ +# `@img/sharp-linuxmusl-x64` + +Prebuilt sharp for use with Linux (musl) x64. + +## Licensing + +Copyright 2013 Lovell Fuller and others. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at +[https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0) + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/server/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node b/server/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node new file mode 100644 index 0000000..5e8b3ef Binary files /dev/null and b/server/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node differ diff --git a/server/node_modules/@img/sharp-linuxmusl-x64/package.json b/server/node_modules/@img/sharp-linuxmusl-x64/package.json new file mode 100644 index 0000000..3d21806 --- /dev/null +++ b/server/node_modules/@img/sharp-linuxmusl-x64/package.json @@ -0,0 +1,46 @@ +{ + "name": "@img/sharp-linuxmusl-x64", + "version": "0.34.4", + "description": "Prebuilt sharp for use with Linux (musl) x64", + "author": "Lovell Fuller ", + "homepage": "https://sharp.pixelplumbing.com", + "repository": { + "type": "git", + "url": "git+https://github.com/lovell/sharp.git", + "directory": "npm/linuxmusl-x64" + }, + "license": "Apache-2.0", + "funding": { + "url": "https://opencollective.com/libvips" + }, + "preferUnplugged": true, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.3" + }, + "files": [ + "lib" + ], + "publishConfig": { + "access": "public" + }, + "type": "commonjs", + "exports": { + "./sharp.node": "./lib/sharp-linuxmusl-x64.node", + "./package": "./package.json" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "config": { + "musl": ">=1.2.2" + }, + "os": [ + "linux" + ], + "libc": [ + "musl" + ], + "cpu": [ + "x64" + ] +} diff --git a/server/prod.pid b/server/prod.pid new file mode 100644 index 0000000..3dd3619 --- /dev/null +++ b/server/prod.pid @@ -0,0 +1 @@ +635326 diff --git a/server/public/playlist-covers/cover1.svg b/server/public/playlist-covers/cover1.svg deleted file mode 100644 index 38210d6..0000000 --- a/server/public/playlist-covers/cover1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - 🎵 - diff --git a/server/public/playlist-covers/cover2.svg b/server/public/playlist-covers/cover2.svg deleted file mode 100644 index 855d9c4..0000000 --- a/server/public/playlist-covers/cover2.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - 🎶 - diff --git a/server/public/playlist-covers/cover3.svg b/server/public/playlist-covers/cover3.svg deleted file mode 100644 index 6eac30f..0000000 --- a/server/public/playlist-covers/cover3.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - 🎤 - diff --git a/server/public/playlist-covers/cover4.svg b/server/public/playlist-covers/cover4.svg deleted file mode 100644 index 688ace4..0000000 --- a/server/public/playlist-covers/cover4.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - 🎸 - diff --git a/server/public/playlist-covers/cover5.svg b/server/public/playlist-covers/cover5.svg deleted file mode 100644 index d1beb86..0000000 --- a/server/public/playlist-covers/cover5.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - 🎹 - diff --git a/server/src/lib/spotify.ts b/server/src/lib/spotify.ts index 1160969..2c4a4db 100644 --- a/server/src/lib/spotify.ts +++ b/server/src/lib/spotify.ts @@ -8,20 +8,32 @@ function generateRandomPlaylistImage(): string { try { const coversDir = path.join(process.cwd(), 'public', 'playlist-covers'); + console.log(`[PLAYLIST COVER] Looking for images in directory: ${coversDir}`); + // Check if directory exists if (!fs.existsSync(coversDir)) { - console.log('Playlist covers directory not found, creating it...'); + console.log('[PLAYLIST COVER] Directory not found, creating it...'); fs.mkdirSync(coversDir, { recursive: true }); } - // Get all image files from the directory + // Get all image files from the directory (Spotify only accepts JPEG for cover uploads) const files = fs.readdirSync(coversDir).filter(file => { const ext = path.extname(file).toLowerCase(); - return ['.jpg', '.jpeg', '.png', '.webp', '.gif'].includes(ext); + return ['.jpg', '.jpeg'].includes(ext); // Only JPEG files for Spotify upload + }); + + console.log(`[PLAYLIST COVER] Found ${files.length} image files:`, files); + + // Log file sizes for debugging + files.forEach(file => { + const filePath = path.join(coversDir, file); + const stats = fs.statSync(filePath); + const sizeKB = (stats.size / 1024).toFixed(2); + console.log(`[PLAYLIST COVER] File: ${file}, Size: ${sizeKB} KB`); }); if (files.length === 0) { - console.log('No playlist cover images found in public/playlist-covers/'); + console.log('[PLAYLIST COVER] No playlist cover images found in public/playlist-covers/'); return '/api/placeholder-playlist-cover'; } @@ -29,11 +41,11 @@ function generateRandomPlaylistImage(): string { const randomFile = files[Math.floor(Math.random() * files.length)]; const imageUrl = `/api/playlist-covers/${encodeURIComponent(randomFile)}`; - console.log(`Selected random playlist cover: ${imageUrl}`); + console.log(`[PLAYLIST COVER] Selected random playlist cover: ${imageUrl} (from file: ${randomFile})`); return imageUrl; } catch (error) { - console.error('Error generating random playlist image:', error); + console.error('[PLAYLIST COVER] Error generating random playlist image:', error); return '/api/placeholder-playlist-cover'; } } @@ -130,6 +142,8 @@ export async function createSpotifyPlaylist( name: string, description: string ): Promise<{ id: string; url: string; imageUrl?: string }> { + console.log(`[PLAYLIST CREATION] Creating Spotify playlist: "${name}" for user: ${userId}`); + const resp = await axios.post( `https://api.spotify.com/v1/users/${encodeURIComponent(userId)}/playlists`, { name, description, public: false }, @@ -137,9 +151,47 @@ export async function createSpotifyPlaylist( ); const pl = resp.data as any; + console.log(`[PLAYLIST CREATION] Spotify playlist created successfully with ID: ${pl.id}`); + // Generate a random local playlist cover image const imageUrl = generateRandomPlaylistImage(); + // Extract the filename from the imageUrl to use the SAME image for Spotify upload + const selectedFilename = decodeURIComponent(imageUrl.replace('/api/playlist-covers/', '')); + console.log(`[PLAYLIST COVER] Selected image for both website and Spotify: ${selectedFilename}`); + + // Get the actual file path for uploading to Spotify (only JPEG files) + const coversDir = path.join(process.cwd(), 'public', 'playlist-covers'); + const files = fs.readdirSync(coversDir).filter(file => { + const ext = path.extname(file).toLowerCase(); + return ['.jpg', '.jpeg'].includes(ext); // Only JPEG files for Spotify upload + }); + + if (files.length > 0) { + // Find the specific file that was selected for the website + const selectedFile = files.find(file => file === selectedFilename); + + if (selectedFile) { + const imagePath = path.join(coversDir, selectedFile); + const stats = fs.statSync(imagePath); + const fileSizeKB = (stats.size / 1024).toFixed(2); + + console.log(`[PLAYLIST COVER] Using SAME image for Spotify upload: ${selectedFile} (${fileSizeKB} KB)`); + + // Upload the SAME cover image to Spotify + const uploadSuccess = await uploadPlaylistCover(accessToken, pl.id, imagePath); + + if (uploadSuccess) { + console.log(`[PLAYLIST COVER] ✅ Successfully uploaded SAME cover image to Spotify playlist ${pl.id}`); + } else { + console.log(`[PLAYLIST COVER] ❌ Failed to upload ${selectedFile} to Spotify, but website will still show it`); + } + } else { + console.log(`[PLAYLIST COVER] ⚠️ Could not find selected file ${selectedFilename} for Spotify upload`); + console.log(`[PLAYLIST COVER] ✅ WEBSITE COVER: Random cover image will still be displayed on your website.`); + } + } + return { id: pl.id, url: pl.external_urls?.spotify, imageUrl }; } @@ -156,6 +208,155 @@ export async function addTracks( ); } +// Upload a playlist cover image to Spotify +export async function uploadPlaylistCover( + accessToken: string, + playlistId: string, + imagePath: string +): Promise { + try { + console.log(`[PLAYLIST COVER] Attempting to upload cover image for playlist ${playlistId} from path: ${imagePath}`); + + // Check if file exists + if (!fs.existsSync(imagePath)) { + console.error(`[PLAYLIST COVER] Image file not found: ${imagePath}`); + return false; + } + + // Read the image file + let imageBuffer = fs.readFileSync(imagePath); + let fileSize = imageBuffer.length; + + console.log(`[PLAYLIST COVER] Original image file size: ${fileSize} bytes (${(fileSize / 1024).toFixed(2)} KB)`); + + // Check if we need to compress the image + // We need to account for base64 encoding overhead (33% increase) + // So we want the original file to be under ~190 KB to stay under 256 KB when base64 encoded + const maxOriginalSize = 190 * 1024; // 190 KB + + if (fileSize > maxOriginalSize) { + console.log(`[PLAYLIST COVER] Image too large (${(fileSize / 1024).toFixed(2)} KB), attempting to compress...`); + + // For now, let's skip files that are too large and try a different one + console.error(`[PLAYLIST COVER] Image file too large for Spotify upload: ${fileSize} bytes (max ~190 KB to account for base64 overhead)`); + return false; + } + + // Convert to base64 + let base64Image = imageBuffer.toString('base64'); + const base64Size = base64Image.length; + + console.log(`[PLAYLIST COVER] Base64 length: ${base64Size} characters (${(base64Size / 1024).toFixed(2)} KB)`); + + // Ensure we don't have any data URL prefix + if (base64Image.startsWith('data:')) { + base64Image = base64Image.split(',')[1] || base64Image; + console.log(`[PLAYLIST COVER] Removed data URL prefix from base64`); + } + + // Final check - ensure base64 size is reasonable + if (base64Size > 300 * 1024) { // 300 KB base64 limit + console.error(`[PLAYLIST COVER] Base64 encoded image too large: ${base64Size} characters`); + return false; + } + + // Determine content type based on file extension + const ext = path.extname(imagePath).toLowerCase(); + let contentType = 'image/jpeg'; // default + switch (ext) { + case '.png': + contentType = 'image/png'; + break; + case '.gif': + contentType = 'image/gif'; + break; + case '.webp': + contentType = 'image/webp'; + break; + case '.svg': + contentType = 'image/svg+xml'; + break; + case '.jpg': + case '.jpeg': + contentType = 'image/jpeg'; + break; + } + + console.log(`[PLAYLIST COVER] Using content type: ${contentType}`); + + // Check token scopes first + try { + console.log(`[PLAYLIST COVER] Checking token scopes...`); + const meResponse = await axios.get('https://api.spotify.com/v1/me', { + headers: { 'Authorization': `Bearer ${accessToken}` } + }); + console.log(`[PLAYLIST COVER] Token is valid for user: ${meResponse.data.display_name}`); + + // Test if we can access the playlist + const playlistResponse = await axios.get(`https://api.spotify.com/v1/playlists/${playlistId}`, { + headers: { 'Authorization': `Bearer ${accessToken}` } + }); + console.log(`[PLAYLIST COVER] Can access playlist: ${playlistResponse.data.name}`); + } catch (error: any) { + console.error(`[PLAYLIST COVER] Token validation failed:`, error.response?.data || error.message); + } + + // Upload to Spotify + console.log(`[PLAYLIST COVER] Making request to Spotify API: https://api.spotify.com/v1/playlists/${playlistId}/images`); + console.log(`[PLAYLIST COVER] Access token (first 20 chars): ${accessToken.substring(0, 20)}...`); + + // Try different approaches for image upload + let response; + try { + // Method 1: Standard PUT request (requires ugc-image-upload scope) + response = await axios.put( + `https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/images`, + base64Image, + { + headers: { + 'Authorization': `Bearer ${accessToken}`, + 'Content-Type': contentType + } + } + ); + } catch (error: any) { + if (error.response?.status === 401) { + console.log(`[PLAYLIST COVER] Method 1 failed with 401, trying alternative approach...`); + + // Method 2: Try with different content type + try { + response = await axios.put( + `https://api.spotify.com/v1/playlists/${encodeURIComponent(playlistId)}/images`, + base64Image, + { + headers: { + 'Authorization': `Bearer ${accessToken}`, + 'Content-Type': 'image/jpeg' // Force JPEG content type + } + } + ); + } catch (error2: any) { + console.log(`[PLAYLIST COVER] Method 2 also failed: ${error2.response?.status}`); + throw error; // Re-throw original error + } + } else { + throw error; // Re-throw if not 401 + } + } + + console.log(`[PLAYLIST COVER] Successfully uploaded cover image for playlist ${playlistId}, response status: ${response.status}`); + console.log(`[PLAYLIST COVER] Response headers:`, response.headers); + return true; + + } catch (error: any) { + console.error(`[PLAYLIST COVER] Failed to upload cover image for playlist ${playlistId}:`); + console.error(`[PLAYLIST COVER] Error status:`, error.response?.status); + console.error(`[PLAYLIST COVER] Error data:`, error.response?.data); + console.error(`[PLAYLIST COVER] Error message:`, error.message); + return false; + } +} + // ----- New: Similar tracks without recommendations endpoint ----- async function getRelatedArtists(accessToken: string, artistId: string): Promise { diff --git a/server/src/routes/playlists.ts b/server/src/routes/playlists.ts index 2ba80b6..a526a22 100644 --- a/server/src/routes/playlists.ts +++ b/server/src/routes/playlists.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import { requireAuth, AuthedRequest } from '../middleware/auth.js'; -import { addTracks, createSpotifyPlaylist, ensureValidAccessToken, fetchRecommendations, vibeToTargets } from '../lib/spotify.js'; +import { addTracks, createSpotifyPlaylist, ensureValidAccessToken, fetchRecommendations, vibeToTargets, uploadPlaylistCover } from '../lib/spotify.js'; import { db } from '../lib/db.js'; import { v4 as uuidv4 } from 'uuid'; @@ -66,16 +66,25 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { const creatorId = req.user!.uid; const { name, description, vibe, genres, includeKnown = true, partnerId, createForBoth = false, limit = 25 } = req.body || {}; + console.log(`[MIXED PLAYLIST] Starting playlist creation process for creator: ${creatorId}, partner: ${partnerId}`); + console.log(`[MIXED PLAYLIST] Request parameters:`, { name, description, vibe, genres, includeKnown, createForBoth, limit }); + if (!partnerId) return res.status(400).json({ error: 'partnerId required' }); // Collect seeds from both users' top tracks + console.log(`[MIXED PLAYLIST] Collecting seed tracks from creator (${creatorId}) and partner (${partnerId})`); const seedRows1 = db.db.prepare('SELECT track_json FROM top_tracks WHERE user_id=? AND time_range=? ORDER BY rank ASC LIMIT 20').all(creatorId, 'short_term'); const seedRows2 = db.db.prepare('SELECT track_json FROM top_tracks WHERE user_id=? AND time_range=? ORDER BY rank ASC LIMIT 20').all(partnerId, 'short_term'); const tracks1: Array<{ id?: string; uri?: string; artists?: Array<{ id?: string }> }> = seedRows1.map((r: any) => JSON.parse(r.track_json)); const tracks2: Array<{ id?: string; uri?: string; artists?: Array<{ id?: string }> }> = seedRows2.map((r: any) => JSON.parse(r.track_json)); + + console.log(`[MIXED PLAYLIST] Found ${tracks1.length} tracks from creator, ${tracks2.length} tracks from partner`); + let seedTrackUris = [...tracks1, ...tracks2] .map((t) => t.uri || (t.id ? `spotify:track:${t.id}` : null)) .filter((u): u is string => !!u); + + console.log(`[MIXED PLAYLIST] Total seed track URIs: ${seedTrackUris.length}`); // Fallback to artist seeds if track seeds are empty let seedArtistIds: string[] = []; @@ -150,12 +159,17 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { const playlistDesc = description || 'An AI-blended mix with fresh recommendations'; // Always create for the creator + console.log(`[MIXED PLAYLIST] Creating Spotify playlist for creator: "${playlistName}"`); const creatorProfile = db.db.prepare('SELECT id FROM users WHERE id=?').get(creatorId) as { id: string }; const { id: creatorPlaylistId, url: creatorUrl, imageUrl: creatorImageUrl } = await createSpotifyPlaylist(creatorToken, creatorProfile.id, playlistName, playlistDesc); + + console.log(`[MIXED PLAYLIST] Adding ${finalUris.length} tracks to creator playlist ${creatorPlaylistId}`); await addTracks(creatorToken, creatorPlaylistId, finalUris); + console.log(`[MIXED PLAYLIST] Successfully added tracks to creator playlist`); let partnerResult: { id?: string; url?: string; imageUrl?: string; error?: string } = {}; if (createForBoth) { + console.log(`[MIXED PLAYLIST] Creating playlist for partner as well: ${partnerId}`); try { const partnerToken = await ensureValidAccessToken(partnerId); const partnerProfile = db.db.prepare('SELECT id FROM users WHERE id=?').get(partnerId) as { id: string }; @@ -164,15 +178,17 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { throw new Error('Partner user not found'); } + console.log(`[MIXED PLAYLIST] Creating Spotify playlist for partner: "${playlistName}"`); const partnerPlaylist = await createSpotifyPlaylist(partnerToken, partnerProfile.id, playlistName, playlistDesc); partnerResult = partnerPlaylist; - await addTracks(partnerToken, partnerResult.id!, finalUris); - console.log(`Successfully created partner playlist: ${partnerResult.id}`); + console.log(`[MIXED PLAYLIST] Adding ${finalUris.length} tracks to partner playlist ${partnerResult.id}`); + await addTracks(partnerToken, partnerResult.id!, finalUris); + console.log(`[MIXED PLAYLIST] Successfully created partner playlist: ${partnerResult.id}`); } catch (e) { // Partner creation may fail (revoked consent, user not found, etc.); still return creator playlist const errorMessage = (e as any)?.response?.data?.error?.message || (e as any)?.message || 'Unknown error'; - console.error('Partner playlist creation failed:', errorMessage); + console.error('[MIXED PLAYLIST] Partner playlist creation failed:', errorMessage); partnerResult.error = errorMessage; } } @@ -181,10 +197,13 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { const playlistId = uuidv4(); const now = Date.now(); - console.log('Saving playlist to database:', { + console.log('[MIXED PLAYLIST] Saving playlist to database:', { id: playlistId, name: playlistName, trackCount: finalUris.length, + creatorPlaylistId, + partnerPlaylistId: partnerResult.id, + imageUrl: creatorImageUrl, trackUris: finalUris.slice(0, 3) // Log first 3 URIs for debugging }); @@ -214,7 +233,7 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { now ); - res.json({ + const response = { id: playlistId, name: playlistName, description: playlistDesc, @@ -226,10 +245,22 @@ playlistsRouter.post('/mixed', requireAuth, async (req: AuthedRequest, res) => { partnerError: partnerResult.error || null, }, added: finalUris.length, + }; + + console.log('[MIXED PLAYLIST] Playlist creation completed successfully:', { + id: playlistId, + name: playlistName, + creatorPlaylistId, + partnerPlaylistId: partnerResult.id, + trackCount: finalUris.length, + imageUrl: creatorImageUrl }); + + res.json(response); } catch (err: any) { const detail = err?.response?.data || err?.message || 'Unknown error'; - console.error('Mixed playlist error:', detail); + console.error('[MIXED PLAYLIST] Error during playlist creation:', detail); + console.error('[MIXED PLAYLIST] Full error object:', err); res.status(500).json({ error: 'Failed to create mixed playlist', detail }); } }); diff --git a/spotify.db b/spotify.db index 8722fa7..9454a2a 100644 Binary files a/spotify.db and b/spotify.db differ diff --git a/spotify.db-shm b/spotify.db-shm index 0eaf464..65439a8 100644 Binary files a/spotify.db-shm and b/spotify.db-shm differ diff --git a/spotify.db-wal b/spotify.db-wal index 3b07afb..6302c34 100644 Binary files a/spotify.db-wal and b/spotify.db-wal differ diff --git a/src/utils/api.ts b/src/utils/api.ts index f16ba48..63704fc 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -8,7 +8,7 @@ function getApiBase(): string { const isHttpsPage = typeof window !== 'undefined' && window.location.protocol === 'https:'; const u = new URL(base, window.location.origin); if (isHttpsPage && u.protocol === 'http:' && u.hostname === '159.195.9.107' && (u.port === '8081' || u.port === '')) { - return 'https://159.195.9.107:8082'; + return 'https://159.195.9.107:3443'; } } catch { // ignore URL parse issues and fall through to returned base @@ -24,7 +24,7 @@ function getApiBase(): string { // For production/self-hosted: choose port based on protocol to avoid mixed content if (window.location.hostname === '159.195.9.107') { const isHttps = window.location.protocol === 'https:'; - return isHttps ? 'https://159.195.9.107:8082' : 'http://159.195.9.107:8081'; + return isHttps ? 'https://159.195.9.107:3443' : 'http://159.195.9.107:8081'; } // Default fallback diff --git a/src/utils/spotify.ts b/src/utils/spotify.ts index 236f45e..8058078 100644 --- a/src/utils/spotify.ts +++ b/src/utils/spotify.ts @@ -25,6 +25,7 @@ export const getSpotifyAuthUrl = (): string => { 'user-read-playback-state', 'user-modify-playback-state', 'user-read-currently-playing', + 'ugc-image-upload', // Required for uploading playlist cover images ].join(' '); const params = new URLSearchParams({