FEATURED ARTIST
Loading Artist...
Loading biography data...
Read Full Bio >
TOP TRACKS
No track selected
skip_previous
play_arrow
skip_next
0:00
0:00
volume_up
var woo_appProperties = (function() { var woo_appProperties_Global = {}; var self = document.getElementById('woo_appProperties'); self.classList.add("woo-ui-gadget"); woo_appProperties_Global.unload = () => { //Unload callbacks here console.log("Unloaded woo_appProperties"); } return woo_appProperties_Global; })();
var gkxwvsqf_2026029184420_485 = (function() { var self = document.getElementById('gkxwvsqf_2026029184420_485'); var gkxwvsqf_2026029184420_485_Global = {}; // Fixed database IDs – no "-shared-" anymore // Replace or adjust these if your actual names are different const PROFILES_DB = "indiepulse-profiles"; const VISITS_DB = "indiepulse-visits"; const TEMPFILES_DB = "indiepulse-tempfiles"; // Array of DB IDs to set up (add more shared DBs here if needed) const dbIdsToSync = [PROFILES_DB, VISITS_DB]; function initDbSync(dbID) { var defaultOpts = { live: true, retry: true }; // Check if sync already exists if (woo.getSync(dbID + "Sync")) { console.log(`Sync already running for ${dbID} — skipping`); return; } const pouchDb = woo.getDB(dbID + "PouchDB"); const couchDb = woo.getDB(dbID + "CouchDB"); if (!pouchDb || !couchDb) { console.warn(`Cannot start sync for ${dbID} — DB instances not ready`); return; } // Start bidirectional sync const sync = pouchDb.sync(couchDb, defaultOpts); // Store it woo.addSync(dbID + "Sync", sync); // Attach events sync.on('paused', () => { console.log(`DB sync paused for ${dbID} — data should be up-to-date`); document.dispatchEvent(new CustomEvent('dbSynced', { detail: { dbID } })); }); sync.on('error', err => { console.error(`Sync error for ${dbID}:`, err); }); sync.on('active', () => { console.log(`Sync active for ${dbID}`); }); sync.on('denied', err => { console.warn(`Sync denied for ${dbID}:`, err); }); console.log(`Bidirectional sync started for ${dbID}`); } function initGuestPull(dbID) { var defaultOpts = { live: true, retry: true }; // Check if pull already exists if (woo.getSync(dbID + "GuestPull")) { console.log(`Guest pull already running for ${dbID} — skipping`); return; } const pouchDb = woo.getDB(dbID + "PouchDB"); const couchDb = woo.getDB(dbID + "CouchDB"); if (!pouchDb || !couchDb) { console.warn(`Cannot start guest pull for ${dbID} — DB instances not ready`); return; } // One-way pull replication (guest/read-only caching) const replication = pouchDb.replicate.from(couchDb, defaultOpts); // Store it woo.addSync(dbID + "GuestPull", replication); // Attach events replication.on('paused', () => { console.log(`Guest pull paused for ${dbID} — data up-to-date (offline cached)`); document.dispatchEvent(new CustomEvent('dbSynced', { detail: { dbID } })); }); replication.on('active', () => { console.log(`Guest pull active for ${dbID}`); }); replication.on('error', err => { console.error(`Guest pull error for ${dbID}:`, err); }); replication.on('denied', err => { console.warn(`Guest pull denied for ${dbID}:`, err); }); console.log(`Guest one-way pull started for ${dbID}`); } // Setup all shared databases (instantiate PouchDB + remote + sync/pull) function setupSharedDatabases() { dbIdsToSync.forEach(dbID => { const dbName = "profile$" + dbID; // keeps your existing prefix convention const remoteUrl = woo.getRemoteCouch() + "/" + dbName; console.log(`Setting up database: ${dbID} → remote: ${remoteUrl}`); // Remote CouchDB instance with options for credentials woo.addDB(dbID + "CouchDB", new PouchDB(remoteUrl, { skip_setup: true, adapter: 'http', ajax: { withCredentials: true, timeout: 10000, cache: false } })); // Local PouchDB woo.addDB(dbID + "PouchDB", new PouchDB(dbName)); // Start sync or pull depending on login status if (woo.sessionData?.user_id) { console.log(`Logged-in user → starting bidirectional sync for ${dbID}`); initDbSync(dbID); } else { console.log(`Guest → starting one-way pull for ${dbID}`); initGuestPull(dbID); } }); console.log("All shared databases and syncs initialised"); } // Run setup immediately setupSharedDatabases(); gkxwvsqf_2026029184420_485_Global.unload = () => { console.log("Unloaded gkxwvsqf_2026029184420_485"); // Optional: cancel syncs here if needed // dbIdsToSync.forEach(dbID => { // woo.getSync(dbID + "Sync")?.cancel(); // woo.getSync(dbID + "GuestPull")?.cancel(); // }); }; return gkxwvsqf_2026029184420_485_Global; })();
var gkxwvsqf_202624121918_402 = (function() { var self = document.getElementById('gkxwvsqf_202624121918_402'); var gkxwvsqf_202624121918_402_Global = {}; // ──────────────────────────────────────────────── // Admin check + current user // ──────────────────────────────────────────────── let isSiteAdmin = false; if (woo.sessionData) { if (woo.sessionData.roles.includes("indiepulse$admin")) { isSiteAdmin = true; } } const currentUserId = woo.sessionData?.user_id || null; // ──────────────────────────────────────────────── // Database setup — custom visit log DB // ──────────────────────────────────────────────── const dbId = "indiepulse$visit-log"; const localDbId = dbId + "PouchDB"; const remoteDbId = dbId + "CouchDB"; let localDb = woo.getDB(localDbId); let remoteDb = woo.getDB(remoteDbId); if (!localDb) { try { localDb = new PouchDB(localDbId); woo.addDB(localDbId, localDb); console.log(`[VISIT] Created and registered local PouchDB: ${localDbId}`); } catch (err) { console.error("[VISIT] Failed to create local PouchDB:", err); localDb = null; } } if (!remoteDb) { try { remoteDb = new PouchDB(woo.getRemoteCouch() + "/" + dbId, { skip_setup: true }); woo.addDB(remoteDbId, remoteDb); console.log(`[VISIT] Registered remote CouchDB reference: ${dbId}`); } catch (err) { console.warn("[VISIT] Remote DB not accessible yet:", err); remoteDb = null; } } // ──────────────────────────────────────────────── // Helper functions // ──────────────────────────────────────────────── function getDeviceType(ua) { if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(ua)) return "tablet"; if (/Mobile|iP(hone|od)|Android|BlackBerry|IEMobile|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(ua)) return "mobile"; return "desktop"; } function getOS(ua) { if (/windows/i.test(ua)) return "Windows"; if (/mac\sos\sx/i.test(ua)) return "macOS"; if (/android/i.test(ua)) return "Android"; if (/linux/i.test(ua)) return "Linux"; if (/(ipod|iphone|ipad)/i.test(ua)) return "iOS"; return "Unknown"; } function getBrowser(ua) { if (/chrome/i.test(ua) && !/edge/i.test(ua) && !/opr/i.test(ua)) return "Chrome"; if (/firefox/i.test(ua)) return "Firefox"; if (/safari/i.test(ua) && !/chrome/i.test(ua)) return "Safari"; if (/edg/i.test(ua)) return "Edge"; if (/opr/i.test(ua) || /opera/i.test(ua)) return "Opera"; if (/trident/i.test(ua) || /msie/i.test(ua)) return "IE"; return "Unknown"; } function getReferrerType(ref) { if (!ref) return "direct"; try { const refOrigin = new URL(ref).origin; if (refOrigin === location.origin) return "internal"; if (/google\.com/i.test(ref)) return "google"; if (/bing\.com/i.test(ref)) return "bing"; if (/yahoo\.com/i.test(ref)) return "yahoo"; if (/duckduckgo\.com/i.test(ref)) return "duckduckgo"; return "external"; } catch (e) { return "unknown"; } } // ──────────────────────────────────────────────── // Record visit + duration // ──────────────────────────────────────────────── function recordVisit() { if (!localDb) { console.warn("[VISIT] Skipping — local DB not ready"); return; } const ua = navigator.userAgent; const ref = document.referrer; const now = new Date(); const ts = now.toISOString(); const random = Math.random().toString(36).slice(2, 10); const visit_id = `visit-${ts}-${random}`; // ── Locale-based country guess (zero network, no CORS) ── const regionNames = new Intl.DisplayNames(['en'], { type: 'region' }); const localeRegion = navigator.language.split('-')[1] || 'NZ'; let country = regionNames.of(localeRegion) || 'Unknown'; let country_code = localeRegion; const doc = { _id: visit_id, type: "page-visit", page: window.location.href, ts: ts, user_id: currentUserId, is_logged_in: !!woo.sessionData, is_admin: isSiteAdmin, referrer: ref, referrer_type: getReferrerType(ref), user_agent: ua, device: getDeviceType(ua), os: getOS(ua), browser: getBrowser(ua), // ── Newly added locale-based fields ── country: country, country_code: country_code }; localDb.put(doc) .then(putRes => { console.log("[VISIT] Recorded:", putRes.id); if (remoteDb) { console.log("[VISIT] Starting one-shot sync..."); localDb.sync(remoteDb, { live: false, retry: true }) .on('complete', () => console.log("[VISIT] Sync complete")) .on('error', err => console.error("[VISIT] Sync error:", err)); } }) .catch(err => console.error("[VISIT] Put failed:", err)); const startTime = now.getTime(); function logDuration() { if (!localDb) return; const duration_ms = new Date().getTime() - startTime; const dur_ts = new Date().toISOString(); const dur_id = `duration-${dur_ts}-${random}`; const dur_doc = { _id: dur_id, type: "page-duration", visit_id: visit_id, page: window.location.href, ts_start: ts, ts_end: dur_ts, duration_ms: duration_ms, user_id: currentUserId, is_admin: isSiteAdmin }; localDb.put(dur_doc).catch(err => { console.error("[DURATION] Put failed:", err); }); } window.addEventListener('beforeunload', logDuration); gkxwvsqf_202624121918_402_Global.durationLogger = logDuration; } // ──────────────────────────────────────────────── // Unload handler // ──────────────────────────────────────────────── gkxwvsqf_202624121918_402_Global.unload = function() { if (gkxwvsqf_202624121918_402_Global.durationLogger) { window.removeEventListener('beforeunload', gkxwvsqf_202624121918_402_Global.durationLogger); } console.log("Unloaded gkxwvsqf_202624121918_402"); }; // Start recording if DB is usable if (localDb) { recordVisit(); } else { console.error("Visit log DB still unavailable after init attempt"); } return gkxwvsqf_202624121918_402_Global; })();
var gkxwvsqf_2026429111145_558 = (function() { var self = document.getElementById('gkxwvsqf_2026429111145_558'); var gkxwvsqf_2026429111145_558_Global = {}; if (!self) { console.warn("[EmbedPlayer] Shell element identifier missing. Target structural fallback engaged."); self = document.body; } // --- CONFIG & DATABASE RESOLUTION --- var orgId = "indiepulse"; var targetDocId = "gkxwvsqf_20264714538_276"; var artistProfileId = ""; // --- PATH RESOLUTION PARSER ENGINE --- function getProfileIdFromUrl() { var url = window.location.href || ''; var pathname = window.location.pathname || ''; console.log("[Embed Router] Scanning URL context string:", url); var pathRegex = /profileid\/([a-zA-Z0-9_-]+)/i; var pathMatch = url.match(pathRegex) || pathname.match(pathRegex); if (pathMatch && pathMatch[1]) { console.log("[Embed Router] Route Match found:", pathMatch[1]); return pathMatch[1]; } var urlParams = new URLSearchParams(window.location.search); var idFromQuery = urlParams.get('profileid'); if (idFromQuery) { console.log("[Embed Router] Parameter Match found:", idFromQuery); return idFromQuery; } if (url.indexOf('profileid/') !== -1) { var parts = url.split('profileid/'); if (parts.length > 1) { var parsedSplitId = parts[1].split(/[?#\/]/)[0]; console.log("[Embed Router] Character split match found:", parsedSplitId); return parsedSplitId; } } console.log("[Embed Router] No profile ID found in URL."); return null; } // --- DATABASE & SYNC INITIALIZATION CHUNK (STANDALONE FIX) --- function ensureDatabaseHandles() { return new Promise(function(resolve) { var playlistsDb = woo.getDB(orgId + "SharedPlaylistsPouchDB"); var profilesDb = woo.getDB(orgId + "-profilesPouchDB"); // FIX: Robust instantiation if missing if (!playlistsDb) { playlistsDb = new PouchDB("music$" + orgId + "-playlists"); woo.addDB(orgId + "SharedPlaylistsCouchDB", new PouchDB(woo.getRemoteCouch() + "/music$" + orgId + "-playlists", { skip_setup: true })); woo.addDB(orgId + "SharedPlaylistsPouchDB", playlistsDb); if (woo.getSync(orgId + "PlaylistsSync")) { try { woo.getSync(orgId + "PlaylistsSync").cancel(); } catch(e) {} } var opts = { live: true, retry: true }; woo.addSync(orgId + "PlaylistsSync", playlistsDb.sync(woo.getDB(orgId + "SharedPlaylistsCouchDB"), opts)); } if (!profilesDb) { profilesDb = new PouchDB(orgId + "-profiles"); woo.addDB(orgId + "-profilesPouchDB", profilesDb); } resolve({ profilesDb: profilesDb, playlistsDb: playlistsDb }); }); } // --- COGNITIVE CORE BACKGROUND ENGINE OVERRIDES --- function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2; if (max === min) { h = s = 0; } else { var d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: h * 360, s: s, l: l }; } function processGradientFromSource(imageSrcString) { if (!imageSrcString) return; var cleanUrl = imageSrcString; if (imageSrcString.length > 500 && imageSrcString.indexOf('data:') === -1 && imageSrcString.indexOf('/') !== 0) { cleanUrl = 'data:image/png;base64,' + imageSrcString.replace(/\s/g, ''); } var img = new Image(); img.crossOrigin = 'Anonymous'; img.src = cleanUrl; img.onload = function() { try { var canvas = document.createElement('canvas'), ctx = canvas.getContext('2d'); canvas.width = img.width; canvas.height = img.height; ctx.drawImage(img, 0, 0); var imageData = ctx.getImageData(0, 0, img.width, img.height).data; var hueWeights = {}, maxWeight = 0, dominantColor = [0, 0, 0]; for (var i = 0; i < imageData.length; i += 40) { var r = imageData[i], g = imageData[i+1], b = imageData[i+2], a = imageData[i+3]; var hsl = rgbToHsl(r, g, b); if (a > 50 && hsl.l > 0.10 && hsl.l < 0.85 && hsl.s > 0.15) { var k = Math.round(hsl.h / 10) * 10; hueWeights[k] = (hueWeights[k] || 0) + hsl.s; if (!hueWeights[k + '_rgb']) hueWeights[k + '_rgb'] = []; hueWeights[k + '_rgb'].push([r, g, b]); } } var domHue = 0; for (var h in hueWeights) { if (h.indexOf('_rgb') === -1 && hueWeights[h] > maxWeight) { maxWeight = hueWeights[h]; domHue = h; } } if (maxWeight > 0) { var rgbs = hueWeights[domHue + '_rgb'], rS = 0, gS = 0, bS = 0; rgbs.forEach(c => { rS += c[0]; gS += c[1]; bS += c[2]; }); dominantColor = [Math.round(rS/rgbs.length), Math.round(gS/rgbs.length), Math.round(bS/rgbs.length)]; var grad = 'linear-gradient(to bottom, rgb(' + dominantColor.join(',') + ') 0px, rgb(0,0,0) 90%)'; // FIX: Added DOM protection lookup retry logic if container element isn't fully ready var $targetEl = $(self).find('.embed-standalone-player'); if ($targetEl.length === 0 && self !== document.body) { $targetEl = $('.embed-standalone-player'); // Global layout search fallback } $targetEl.css({'background-image': grad, 'background-color': '#000'}); } } catch (e) { console.warn("Gradient rendering context parsing exception:", e); } }; } function applyImageBg(elementSelector, imageStringOrPath) { if (!imageStringOrPath) return; var cleanUrl = imageStringOrPath; if (imageStringOrPath.length > 500 && imageStringOrPath.indexOf('data:') === -1 && imageStringOrPath.indexOf('/') !== 0) { cleanUrl = 'data:image/png;base64,' + imageStringOrPath.replace(/\s/g, ''); } if (cleanUrl.indexOf('url(') !== 0) { cleanUrl = "url('" + cleanUrl + "')"; } $(self).find(elementSelector).css({ "background-image": cleanUrl }); } function buildSongCompoundId(trackKey) { return 'gkxwvsqf_2026429111145_558_' + artistProfileId + '_' + trackKey; } // --- RESOLUTION RUNTIME TEMPLATE DEPLOYMENT --- function renderEmbedView(profilesDb, playlistsDb, targetArtistId) { console.log("[Embed Router] Compiling views for:", targetArtistId); profilesDb.get(targetArtistId).then(function(profileDoc) { var inputPages = profileDoc.inputPages || {}; if (inputPages.Standard) { inputPages = inputPages.Standard; } var artistName = profileDoc.createdBy || "Featured Artist"; if (inputPages["2"] && inputPages["2"].inputValues && inputPages["2"].inputValues.main) { artistName = inputPages["2"].inputValues.main; } var rawBioHTML = (inputPages["3"] && inputPages["3"].inputValues && inputPages["3"].inputValues.main) || "No biography info listed."; var tempDiv = document.createElement("div"); tempDiv.innerHTML = rawBioHTML; var cleanBioText = tempDiv.textContent || tempDiv.innerText || ""; var profilePicData = (inputPages["1"] && inputPages["1"].inputValues && inputPages["1"].inputValues.main) || ""; var bannerPicData = (inputPages["14"] && inputPages["14"].inputValues && inputPages["14"].inputValues.main) || ""; $(self).find("#embedName_gkxwvsqf_2026429111145_558").text(artistName); $(self).find("#embedBio_gkxwvsqf_2026429111145_558").text(cleanBioText); var bioExternalRedirectUrl = window.location.origin + '/artist-profile/profileid/' + targetArtistId; $(self).find("#embedLink_gkxwvsqf_2026429111145_558").attr('href', bioExternalRedirectUrl); if (profilePicData) { applyImageBg("#embedAvatar_gkxwvsqf_2026429111145_558", profilePicData); } else { applyImageBg("#embedAvatar_gkxwvsqf_2026429111145_558", "/resources/" + orgId + "/uploads/default-artist.jpg"); } var tracksContainer = $(self).find("#embedTracks_gkxwvsqf_2026429111145_558"); tracksContainer.empty(); playlistsDb.get(targetDocId).then(function(playlistDoc) { if (playlistDoc && playlistDoc.data && playlistDoc.data[targetArtistId]) { var songsMap = playlistDoc.data[targetArtistId]; var rawKeys = Object.keys(songsMap).filter(k => songsMap[k] && songsMap[k].name); if (rawKeys.length > 0) { var displayKeys = rawKeys.slice(0, 3); var firstSong = songsMap[displayKeys[0]]; var firstSongPic = firstSong.picture || firstSong.image || firstSong.img; var gradientSourceUrl = firstSongPic ? (firstSongPic.indexOf('/') === 0 ? firstSongPic : '/resources/' + orgId + '/uploads/' + firstSongPic) : (bannerPicData || profilePicData || ""); if (gradientSourceUrl) { // Executed directly without wrapper timeouts processGradientFromSource(gradientSourceUrl); applyImageBg("#embedSongImg_gkxwvsqf_2026429111145_558", gradientSourceUrl); } displayKeys.forEach(function(key) { var song = songsMap[key]; var folderName = song.audio || 'default'; var audioSrc = '/resources/' + orgId + '/uploads/' + folderName + '/stream.m3u8'; var trackPic = song.picture || song.image || song.img; var trackImgUrl = trackPic ? (trackPic.indexOf('/') === 0 ? trackPic : '/resources/' + orgId + '/uploads/' + trackPic) : '/resources/default-music.png'; var finalArtistId = song.artistId || targetArtistId; var trackHtml = $( '
' + '
' + '
' + '
' + song.name + '
' + '
' + '
' + '
' + '
' ); trackHtml.on('click', function() { var compoundId = buildSongCompoundId(key); var savedState = localStorage.getItem('woo_player_state'); var playerCurrent = savedState ? JSON.parse(savedState) : null; var isCurrentSong = playerCurrent && (playerCurrent.blockId === compoundId); var currentState = $(this).find('.playButton').attr('data-state'); if (isCurrentSong && currentState === 'playing') { window.dispatchEvent(new CustomEvent('wooPlayerAction', { detail: { action: 'pause', payload: { blockId: compoundId }, senderId: 'gkxwvsqf_2026429111145_558' } })); } else if (isCurrentSong && currentState === 'paused') { window.dispatchEvent(new CustomEvent('wooPlayerAction', { detail: { action: 'resume', payload: { blockId: compoundId }, senderId: 'gkxwvsqf_2026429111145_558' } })); } else { var newQueue = $(self).find('.block').map(function() { var itemKey = $(this).data('block-id'); var itemSong = songsMap[itemKey]; if (!itemSong) return null; var itemFolder = itemSong.audio || 'default'; var itemPic = itemSong.picture || itemSong.image || itemSong.img; var itemImgUrl = itemPic ? (itemPic.indexOf('/') === 0 ? itemPic : '/resources/' + orgId + '/uploads/' + itemPic) : '/resources/default-music.png'; return { blockId: buildSongCompoundId(itemKey), src: '/resources/' + orgId + '/uploads/' + itemFolder + '/stream.m3u8', folder: itemFolder, audioFolder: itemFolder, songName: itemSong.name, artistName: artistName, artistId: itemSong.artistId || targetArtistId, picture: itemImgUrl }; }).get().filter(Boolean); var currentData = { senderId: 'gkxwvsqf_2026429111145_558', blockId: compoundId, src: audioSrc, folder: folderName, audioFolder: folderName, songName: song.name, artistName: artistName, artistId: finalArtistId, picture: trackImgUrl, queue: newQueue }; localStorage.setItem('woo_player_state', JSON.stringify(currentData)); localStorage.setItem('woo_player_queue', JSON.stringify(newQueue)); window.dispatchEvent(new CustomEvent('wooPlayerAction', { detail: { action: 'play', payload: currentData, senderId: 'gkxwvsqf_2026429111145_558' } })); } }); tracksContainer.append(trackHtml); }); return; } } tracksContainer.html('
No tracks listed.
'); }).catch(function() { tracksContainer.html('
No tracks listed.
'); }); }).catch(function(err) { console.error("[Embed Router] Failed fetching profile layout configuration data:", err); }); } function initializeAndFetch() { console.log("[Embed Router] Booting standalone initialization chain..."); ensureDatabaseHandles().then(function(dbGroup) { var profilesDb = dbGroup.profilesDb; var playlistsDb = dbGroup.playlistsDb; if (!profilesDb || !playlistsDb) { console.warn("[Embed Router] Initialization database allocation failure. Retrying..."); setTimeout(initializeAndFetch, 200); return; } var explicitId = getProfileIdFromUrl(); if (explicitId) { artistProfileId = explicitId; renderEmbedView(profilesDb, playlistsDb, artistProfileId); } else { console.log("[Embed Router] Profile context missing from URL parameters, drawing fallback sample..."); playlistsDb.get(targetDocId).then(function(playlistDoc) { var keys = Object.keys(playlistDoc.data || {}); if (keys.length > 0) { artistProfileId = keys[Math.floor(Math.random() * keys.length)]; renderEmbedView(profilesDb, playlistsDb, artistProfileId); } }).catch(function(err) { console.error("[Embed Router] Fallback collection document mapping missing:", err); }); } }); } // --- AUDIO SYNCHRONIZER PLAYER HOOKS --- var playerUpdateListener = function(e) { var update = e.detail; var updateParts = String(update.blockId || '').split('_'); var incomingSongId = updateParts[updateParts.length - 1]; var incomingArtistId = updateParts.length >= 3 ? updateParts[updateParts.length - 2] : null; var $targetBlock = $(self).find('.block').filter(function() { return (String($(this).data('block-id')) === incomingSongId && incomingArtistId === artistProfileId); }); if (update.state === 'playing' || update.state === 'progress') { $(self).find('.block').not($targetBlock).removeClass('highlighted'); $(self).find('.block').not($targetBlock).find('.playButton').removeClass('playing paused').attr('data-state', 'stopped'); $(self).find('.block').not($targetBlock).find('.progressBar').hide(); } if ($targetBlock.length > 0) { var $playBtn = $targetBlock.find('.playButton'); if (update.state === 'playing') { $targetBlock.addClass('highlighted'); $playBtn.addClass('playing').removeClass('paused').attr('data-state', 'playing'); } else if (update.state === 'paused') { $playBtn.removeClass('playing').addClass('paused').attr('data-state', 'paused'); } else if (update.state === 'progress') { $targetBlock.addClass('highlighted'); $targetBlock.find('.progressBar').show().css('width', Math.min(update.percent, 100) + '%'); } } }; window.addEventListener('wooPlayerStateUpdate', playerUpdateListener); // FIX: Run directly when script lands instead of betting on a 200ms timeout window if (document.readyState === 'complete' || document.readyState === 'interactive') { initializeAndFetch(); } else { document.addEventListener('DOMContentLoaded', initializeAndFetch); } gkxwvsqf_2026429111145_558_Global.unload = function() { window.removeEventListener('wooPlayerStateUpdate', playerUpdateListener); }; return gkxwvsqf_2026429111145_558_Global; })();
var gkxwvsqf_2026429115040_649 = (function() { var self = document.getElementById('gkxwvsqf_2026429115040_649'); var gkxwvsqf_2026429115040_649_Global = {}; var orgId = "indiepulse"; var targetDocId = "undefined"; // --- INITIALIZE EMBED RUNTIME VIDEO TARGET NODE LAYER --- if (!window.wooGlobalVideo) { window.wooGlobalVideo = document.createElement('video'); window.wooGlobalVideo.style.display = 'none'; window.wooGlobalVideo.setAttribute('playsinline', 'true'); window.wooGlobalVideo.setAttribute('webkit-playsinline', 'true'); window.wooGlobalVideo.setAttribute('preload', 'auto'); window.wooGlobalVideo.setAttribute('x-webkit-airplay', 'allow'); document.body.appendChild(window.wooGlobalVideo); } var videoEl = window.wooGlobalVideo; var savedState = localStorage.getItem('woo_player_state'); var savedQueue = localStorage.getItem('woo_player_queue'); if (!videoEl.wooPlaylistQueue) { videoEl.wooPlaylistQueue = savedQueue ? JSON.parse(savedQueue) : []; } var historicalData = savedState ? JSON.parse(savedState) : null; if (historicalData && videoEl.currentTime > 0 && !videoEl.paused && !videoEl.ended) { videoEl.wooCurrentData = historicalData; } else { videoEl.wooCurrentData = null; } var wooPlayerTransitioning = false; var wooTransitionToken = 0; function extractSongId(compoundId) { var parts = String(compoundId || '').split('_'); return parts[parts.length - 1]; } function updateMediaSession() { if (!('mediaSession' in navigator)) return; if (videoEl.wooCurrentData) { navigator.mediaSession.metadata = new MediaMetadata({ title: videoEl.wooCurrentData.songName || 'Unknown', artist: videoEl.wooCurrentData.artistName || 'Unknown Artist', artwork: [{ src: videoEl.wooCurrentData.picture || '/resources/indiepulse/iPhone_icon.png', sizes: '512x512', type: 'image/png' }] }); navigator.mediaSession.playbackState = videoEl.paused ? "paused" : "playing"; if ('setPositionState' in navigator.mediaSession && videoEl.duration && isFinite(videoEl.duration)) { navigator.mediaSession.setPositionState({ duration: videoEl.duration, playbackRate: videoEl.playbackRate || 1, position: videoEl.currentTime || 0 }); } } } // --- BULLETPROOF ADJACENT NAVIGATION PARSER --- function playAdjacent(direction) { wooTransitionToken++; var transitionId = wooTransitionToken; wooPlayerTransitioning = true; if (!videoEl.wooCurrentData || !videoEl.wooPlaylistQueue || !videoEl.wooPlaylistQueue.length) { console.warn("[Player Embed] Blocked navigation: Active track payload data or queue list is empty."); return; } var currentTrackSrc = videoEl.wooCurrentData.src || videoEl.wooCurrentData.audioSrc; var currentSongName = videoEl.wooCurrentData.songName; // Multi-tier matching: Find item by file path or matching song titles var currentIndex = videoEl.wooPlaylistQueue.findIndex(function(item) { if (!item) return false; var itemSrc = item.src || item.audioSrc; var itemName = item.songName || item.name; return itemSrc === currentTrackSrc || (itemName && itemName === currentSongName); }); // Fallback look-up method matching base ID hashes if path references differ if (currentIndex === -1) { var currentSongId = extractSongId(videoEl.wooCurrentData.blockId); currentIndex = videoEl.wooPlaylistQueue.findIndex(function(item) { if (!item) return false; var itemBlockId = item.blockId || item.id || ''; return extractSongId(itemBlockId) === currentSongId; }); } console.log("[Player Embed] Found current index location inside track layout array:", currentIndex); var nextIndex = currentIndex + direction; if (nextIndex >= 0 && nextIndex < videoEl.wooPlaylistQueue.length) { var next = videoEl.wooPlaylistQueue[nextIndex]; console.log("[Player Embed] Changing track index target to:", nextIndex, next); videoEl.wooCurrentData = { blockId: next.blockId || next.id, src: next.src || next.audioSrc, audioSrc: next.audioSrc || next.src, folder: next.folder || next.audioFolder, audioFolder: next.audioFolder || next.folder, songName: next.songName || next.name, artistName: next.artistName || next.artist, artistId: next.artistId, picture: next.picture, senderId: next.senderId || (videoEl.wooCurrentData ? videoEl.wooCurrentData.senderId : null), loggedPlay: false }; localStorage.setItem('woo_player_state', JSON.stringify(videoEl.wooCurrentData)); refreshUI(); initHls(transitionId).loadSource(videoEl.wooCurrentData.src || videoEl.wooCurrentData.audioSrc); } else { console.log("[Player Embed] Navigation boundaries exceeded. Index limit dropped."); } } function bindMediaActions() { if (!('mediaSession' in navigator)) return; navigator.mediaSession.setActionHandler('play', () => { videoEl.play(); }); navigator.mediaSession.setActionHandler('pause', () => { videoEl.pause(); }); navigator.mediaSession.setActionHandler('previoustrack', () => { if (videoEl.currentTime > 2) { videoEl.currentTime = 0; if (videoEl.paused) videoEl.play(); } else { playAdjacent(-1); } }); navigator.mediaSession.setActionHandler('nexttrack', () => { playAdjacent(1); }); } if ('mediaSession' in navigator) { bindMediaActions(); videoEl.wooMediaSessionBound = true; } function logSongPlay(data) { if (!data || !data.artistId) return; try { const doc = { _id: `play-${data.artistId}-${data.blockId}-${new Date().getTime()}`, type: "song-play", artist: data.artistId, song: data.blockId, name: data.songName, artist_name: data.artistName, ts: new Date().toISOString(), player: (woo.sessionData && woo.sessionData.user_id) || "guest", admin: !!(woo.sessionData && woo.sessionData.roles && woo.sessionData.roles.includes(orgId + "$admin")) }; const dbNameVisits = "profile$" + orgId + "-visits"; var logDB = new PouchDB(dbNameVisits); var logRemote = new PouchDB(woo.getRemoteCouch() + "/" + dbNameVisits, { skip_setup: true }); logDB.put(doc).then(function() { logDB.replicate.to(logRemote).catch(function(e) { console.warn("[Log Sync Interrupted]", e); }); }).catch(function(err) { console.error("[Log Entry Failed]", err); }); } catch (e) { console.error("Logging execution error:", e); } } function formatTime(seconds) { if (isNaN(seconds)) return "0:00"; var min = Math.floor(seconds / 60); var sec = Math.floor(seconds % 60); return min + ":" + (sec < 10 ? "0" : "") + sec; } function refreshUI() { var $playerContainer = $('#' + 'gkxwvsqf_2026429115040_649' + ' .player-container'); if (!videoEl.wooCurrentData) { $playerContainer.addClass('is-hidden'); return; } $playerContainer.removeClass('is-hidden'); $('#player-song-title').text(videoEl.wooCurrentData.songName || 'Unknown'); $('#player-artist-name').text(videoEl.wooCurrentData.artistName || 'Unknown Artist'); var artworkUrl = videoEl.wooCurrentData.picture || '/resources/indiepulse/iPhone_icon.png'; $('#player-album-art').attr('src', artworkUrl); updateMediaSession(); var shouldShowPause = wooPlayerTransitioning || (!videoEl.paused && !videoEl.ended); if (shouldShowPause) { $('#player-play-pause').addClass('paused').text('pause'); } else { $('#player-play-pause').removeClass('paused').text('play_arrow'); } window.dispatchEvent(new CustomEvent('wooPlayerStateUpdate', { detail: { state: shouldShowPause ? 'playing' : 'paused', blockId: videoEl.wooCurrentData.blockId, senderId: videoEl.wooCurrentData.senderId } })); } function initHls(transitionId) { wooPlayerTransitioning = true; videoEl.pause(); if (window.wooGlobalHls) { window.wooGlobalHls.destroy(); window.wooGlobalHls = null; } var sourceUrl = videoEl.wooCurrentData.src || videoEl.wooCurrentData.audioSrc; bindMediaActions(); if (videoEl.canPlayType('application/vnd.apple.mpegurl')) { videoEl.src = sourceUrl; videoEl.load(); videoEl.onloadedmetadata = function() { if (transitionId === wooTransitionToken) updateMediaSession(); }; videoEl.play().then(() => { if (transitionId === wooTransitionToken) { wooPlayerTransitioning = false; updateMediaSession(); refreshUI(); } }).catch(e => { if (transitionId === wooTransitionToken) { wooPlayerTransitioning = false; refreshUI(); } }); return { loadSource: function() {} }; } if (typeof Hls === 'undefined') { console.error("HLS fallback library unresolvable"); return; } var hls = new Hls({ enableWorker: true, lowLatencyMode: true }); hls.attachMedia(videoEl); window.wooGlobalHls = hls; hls.on(Hls.Events.KEY_LOADING, function(event, data) { var folder = videoEl.wooCurrentData.folder || videoEl.wooCurrentData.audioFolder; if (!folder) return; var xhr = new XMLHttpRequest(); xhr.open('GET', '/resources/' + woo.getAppID() + '/uploads/' + folder + '-key.bin', true); xhr.responseType = 'arraybuffer'; xhr.onload = function() { if (xhr.status >= 200 && xhr.status < 300) { data.frag.decryptdata.key = new Uint8Array(xhr.response); hls.trigger(Hls.Events.KEY_LOADED, { frag: data.frag }); } }; xhr.send(); }); hls.on(Hls.Events.MANIFEST_PARSED, function() { if (transitionId !== wooTransitionToken) return; videoEl.play().then(() => { if (transitionId !== wooTransitionToken) return; wooPlayerTransitioning = false; updateMediaSession(); refreshUI(); }).catch(e => { if (transitionId !== wooTransitionToken) return; wooPlayerTransitioning = false; refreshUI(); }); }); return hls; } if (!videoEl.wooActionListenerBound) { videoEl.wooActionListenerBound = true; window.addEventListener('wooPlayerAction', function(e) { var action = e.detail.action; var p = e.detail.payload; if (action === 'play') { executePlayTrack(p); } else if (action === 'pause') { videoEl.pause(); } else if (action === 'resume') { if (p && p.senderId && videoEl.wooCurrentData) { videoEl.wooCurrentData.senderId = p.senderId; } videoEl.play(); } }); } function executePlayTrack(payload) { wooTransitionToken++; wooPlayerTransitioning = true; videoEl.wooCurrentData = payload; videoEl.wooCurrentData.loggedPlay = false; if (payload.queue) { videoEl.wooPlaylistQueue = payload.queue; localStorage.setItem('woo_player_queue', JSON.stringify(payload.queue)); } localStorage.setItem('woo_player_state', JSON.stringify(videoEl.wooCurrentData)); refreshUI(); var hlsObj = initHls(wooTransitionToken); if (hlsObj && typeof hlsObj.loadSource === 'function') { hlsObj.loadSource(payload.src || payload.audioSrc); } } // --- NATIVE DOM UI ACTION ASSIGNMENTS --- $(document).off('click', '#player-play-pause').on('click', '#player-play-pause', function(e) { e.preventDefault(); if (videoEl.paused) { videoEl.play(); } else { videoEl.pause(); } }); $(document).off('click', '#player-prev').on('click', '#player-prev', function() { if (videoEl.currentTime > 2) { videoEl.currentTime = 0; if (videoEl.paused) videoEl.play(); } else { playAdjacent(-1); } }); $(document).off('click', '#player-next').on('click', '#player-next', function() { playAdjacent(1); }); $(document).off('keydown.gadget_space_gkxwvsqf_2026429115040_649').on('keydown.gadget_space_gkxwvsqf_2026429115040_649', function(e) { if ((e.key === ' ' || e.keyCode === 32) && !$(e.target).is('input, textarea, [contenteditable]')) { e.preventDefault(); if (videoEl.wooCurrentData) { if (videoEl.paused) { videoEl.play(); } else { videoEl.pause(); } } } }); if (!videoEl.dataset.eventsBound) { var lastDispatchedPercent = -1; videoEl.addEventListener('timeupdate', function() { if (wooPlayerTransitioning || !videoEl.duration) return; var per = (videoEl.currentTime / videoEl.duration) * 100; $('#player-seekbar').val(per); $('#current-time').text(formatTime(videoEl.currentTime)); $('#total-time').text(formatTime(videoEl.duration)); if (Math.abs(per - lastDispatchedPercent) >= 2.0) { updateMediaSession(); } if (videoEl.wooCurrentData && videoEl.wooCurrentData.blockId && Math.abs(per - lastDispatchedPercent) >= 0.5) { lastDispatchedPercent = per; window.dispatchEvent(new CustomEvent('wooPlayerStateUpdate', { detail: { state: 'progress', percent: per, blockId: videoEl.wooCurrentData.blockId, senderId: videoEl.wooCurrentData.senderId } })); } if (per >= 5 && videoEl.wooCurrentData && !videoEl.wooCurrentData.loggedPlay) { videoEl.wooCurrentData.loggedPlay = true; logSongPlay(videoEl.wooCurrentData); } }); videoEl.addEventListener('play', function() { wooPlayerTransitioning = false; refreshUI(); }); videoEl.addEventListener('pause', function() { if (!wooPlayerTransitioning) refreshUI(); }); videoEl.addEventListener('ended', function() { playAdjacent(1); }); videoEl.dataset.eventsBound = "true"; } // --- INITIALIZE VOLUME ADJUSTMENT METRICS --- var savedVol = localStorage.getItem('woo_player_volume'); var volSlider = document.getElementById('player-volume'); if (savedVol !== null) { videoEl.volume = parseFloat(savedVol); if (volSlider) { volSlider.value = savedVol; } } $(document).on('input change', '#player-volume', function() { videoEl.volume = this.value; localStorage.setItem('woo_player_volume', this.value); }); $(document).on('change', '#player-seekbar', function() { if (videoEl.duration) { videoEl.currentTime = (this.value / 100) * videoEl.duration; } }); var seekbarEl = document.getElementById('player-seekbar'); if (seekbarEl) { var isDraggingSeekbar = false; seekbarEl.addEventListener('touchstart', function(e) { isDraggingSeekbar = true; e.stopPropagation(); }, { passive: true }); seekbarEl.addEventListener('input', function() { if (isDraggingSeekbar && videoEl.duration) { $('#current-time').text(formatTime((this.value / 100) * videoEl.duration)); } }); seekbarEl.addEventListener('touchend', function(e) { isDraggingSeekbar = false; if (videoEl.duration) { videoEl.currentTime = (this.value / 100) * videoEl.duration; } e.stopPropagation(); }, { passive: true }); } var volIcon = document.getElementById('player-volume-icon'); var airplayBtn = document.getElementById('player-airplay-btn'); if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream) { if (airplayBtn) { airplayBtn.style.display = 'flex'; airplayBtn.addEventListener('click', function(e) { e.stopPropagation(); if (videoEl.webkitShowPlaybackTargetPicker) { videoEl.webkitShowPlaybackTargetPicker(); } }); } } else { if (volSlider) volSlider.style.display = "none"; if (volIcon) { volIcon.addEventListener("click", function(e) { e.stopPropagation(); volSlider.style.display = (volSlider.style.display === "none") ? "block" : "none"; }); } document.addEventListener("click", function() { if (volSlider) volSlider.style.display = "none"; }); } refreshUI(); gkxwvsqf_2026429115040_649_Global.unload = function() { $(document).off('.gadget_gkxwvsqf_2026429115040_649'); $(document).off('keydown.gadget_space_gkxwvsqf_2026429115040_649'); }; return gkxwvsqf_2026429115040_649_Global; })();