1(function () { 2 "use strict"; 3 4 var endpoint = window.PLAYMB_ANALYTICS_ENDPOINT; 5 if (!endpoint || !window.fetch) return; 6 7 var STORAGE_ANON = "playmb_analytics_anon"; 8 var STORAGE_SESSION = "playmb_analytics_session"; 9 var SESSION_TTL = 30 * 60 * 1000; 10 11 function id() { 12 if (window.crypto && typeof window.crypto.randomUUID === "function") { 13 return window.crypto.randomUUID(); 14 } 15 return "pm_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2) + Math.random().toString(36).slice(2); 16 } 17 18 function storageGet(key) { 19 try { return window.localStorage.getItem(key); } catch (error) { return null; } 20 } 21 22 function storageSet(key, value) { 23 try { window.localStorage.setItem(key, value); } catch (error) {} 24 } 25 26 var anonymousId = storageGet(STORAGE_ANON); 27 if (!anonymousId) { 28 anonymousId = id(); 29 storageSet(STORAGE_ANON, anonymousId); 30 } 31 32 function campaign() { 33 var query = new URLSearchParams(window.location.search || ""); 34 var referrerHost = ""; 35 try { referrerHost = document.referrer ? new URL(document.referrer).hostname : ""; } catch (error) {} 36 return { 37 source: query.get("utm_source") || (referrerHost && referrerHost !== window.location.hostname ? referrerHost : "direct"), 38 medium: query.get("utm_medium") || "", 39 campaign: query.get("utm_campaign") || "" 40 }; 41 } 42 43 function currentSession() { 44 var now = Date.now(); 45 var stored = null; 46 try { stored = JSON.parse(storageGet(STORAGE_SESSION) || "null"); } catch (error) {} 47 if (!stored || !stored.key || !stored.lastSeen || now - stored.lastSeen > SESSION_TTL) { 48 var attribution = campaign(); 49 stored = { 50 key: id(), 51 lastSeen: now, 52 source: attribution.source, 53 medium: attribution.medium, 54 campaign: attribution.campaign 55 }; 56 } else { 57 stored.lastSeen = now; 58 } 59 storageSet(STORAGE_SESSION, JSON.stringify(stored)); 60 return stored; 61 } 62 63 function track(eventName, options) { 64 options = options || {}; 65 var session = currentSession(); 66 var payload = { 67 event_id: id(), 68 event_name: eventName, 69 anonymous_id: anonymousId, 70 session_key: session.key, 71 path: window.location.pathname, 72 referrer: document.referrer || "", 73 source: session.source, 74 medium: session.medium, 75 campaign: session.campaign 76 }; 77 if (options.content_type) payload.content_type = options.content_type; 78 if (options.content_id) payload.content_id = Number(options.content_id); 79 if (options.properties) payload.properties = options.properties; 80 81 return window.fetch(endpoint, { 82 method: "POST", 83 credentials: "same-origin", 84 keepalive: true, 85 headers: { "Content-Type": "application/json", "Accept": "application/json" }, 86 body: JSON.stringify(payload) 87 }).catch(function () { return null; }); 88 } 89 90 window.PlayMBAnalytics = { track: track }; 91 92 track("visit"); 93 var context = window.PLAYMB_ANALYTICS_CONTEXT || {}; 94 if (context.page === "release" && context.content_id) { 95 track("release_view", { content_type: "album", content_id: context.content_id }); 96 } 97 if (context.page === "checkout" && Array.isArray(context.items)) { 98 context.items.forEach(function (item) { 99 track("checkout_start", item); 100 }); 101 } 102 103 document.addEventListener("click", function (event) { 104 var target = event.target && event.target.closest ? event.target.closest("[data-playmb-analytics]") : null; 105 if (!target) return; 106 track(target.getAttribute("data-playmb-analytics"), { 107 content_type: target.getAttribute("data-content-type") || "", 108 content_id: target.getAttribute("data-content-id") || "" 109 }); 110 }, true); 111 112 var lastPreviewTrack = null; 113 window.addEventListener("playmb:audio-state", function (event) { 114 var state = event.detail || {}; 115 var trackData = state.track || {}; 116 var trackId = Number(trackData.id || 0); 117 if (!state.isPreview || !state.playing || !trackId || trackId === lastPreviewTrack) return; 118 lastPreviewTrack = trackId; 119 track("track_preview_start", { content_type: "track", content_id: trackId }); 120 }); 121})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.