diff --git a/blog.html b/blog.html index f7c562af..d569d71e 100644 --- a/blog.html +++ b/blog.html @@ -40,7 +40,6 @@ bitvid Blog - diff --git a/js/analytics.js b/js/analytics.js deleted file mode 100644 index c4038f95..00000000 --- a/js/analytics.js +++ /dev/null @@ -1,195 +0,0 @@ -// js/analytics.js -import { ANALYTICS_CONFIG } from "./analyticsConfig.js"; -import { userLogger } from "./utils/logger.js"; - -const SCRIPT_ATTR = "data-bitvid-analytics"; -const SCRIPT_IDENTIFIER = "umami"; -const pendingCalls = []; -let flushTimerId = null; -let scriptLoadedOnce = false; - -function isBrowserEnvironment() { - return typeof window !== "undefined" && typeof document !== "undefined"; -} - -function flushPendingCalls() { - if (!isBrowserEnvironment()) { - return; - } - - const umami = window.umami; - if (!umami) { - return; - } - - while (pendingCalls.length > 0) { - const { method, args } = pendingCalls.shift(); - const fn = typeof umami[method] === "function" ? umami[method] : null; - if (!fn) { - continue; - } - try { - fn.apply(umami, args); - } catch (err) { - userLogger.warn("[analytics] Failed to call", method, err); - } - } -} - -function scheduleFlush() { - if (!isBrowserEnvironment()) { - return; - } - - if (flushTimerId !== null) { - return; - } - - // 🔧 merged conflicting changes from codex/add-tracking-script-to-all-pages vs unstable - flushTimerId = window.setInterval(() => { - if (window.umami && typeof window.umami.track === "function") { - window.clearInterval(flushTimerId); - flushTimerId = null; - flushPendingCalls(); - } - }, 500); -} - -export function ensureAnalyticsLoaded(doc = typeof document !== "undefined" ? document : null) { - if (!doc) { - return null; - } - - let script = doc.querySelector(`script[${SCRIPT_ATTR}]`); - if (script) { - if (!scriptLoadedOnce) { - // If a server rendered script already exists, make sure we flush asap. - scriptLoadedOnce = true; - flushPendingCalls(); - } - return script; - } - - script = doc.createElement("script"); - script.defer = true; - script.src = ANALYTICS_CONFIG.scriptSrc; - script.setAttribute(SCRIPT_ATTR, SCRIPT_IDENTIFIER); - script.dataset.websiteId = ANALYTICS_CONFIG.websiteId; - // Allow Umami to handle automatic pageview tracking by default. - script.addEventListener("load", () => { - scriptLoadedOnce = true; - flushPendingCalls(); - }); - doc.head.appendChild(script); - - scheduleFlush(); - - return script; -} - -function queueCall(method, args) { - pendingCalls.push({ method, args }); - scheduleFlush(); -} - -function invokeUmami(method, args) { - if (!isBrowserEnvironment()) { - return; - } - - ensureAnalyticsLoaded(); - - const umami = window.umami; - if (umami && typeof umami[method] === "function") { - try { - umami[method].apply(umami, args); - } catch (err) { - userLogger.warn("[analytics] Failed to call", method, err); - } - return; - } - - queueCall(method, args); -} - -export function trackPageView(path, referrer) { - if (!isBrowserEnvironment()) { - return; - } - - const resolvedPath = - typeof path === "string" && path.length > 0 - ? path - : `${window.location.pathname}${window.location.hash || ""}`; - - const resolvedReferrer = - typeof referrer === "string" ? referrer : document.referrer || ""; - - // 🔧 merged conflicting changes from codex/add-tracking-script-to-all-pages vs unstable - let absoluteUrl = resolvedPath; - try { - absoluteUrl = new URL(resolvedPath, window.location.origin).toString(); - } catch (err) { - // Fall back to the provided path if it cannot be resolved. - } - - let absoluteReferrer = resolvedReferrer; - if (resolvedReferrer) { - try { - absoluteReferrer = new URL(resolvedReferrer, window.location.origin).toString(); - } catch (err) { - // Keep original referrer if it cannot be normalized. - } - } - - invokeUmami("track", [ - (basePayload = {}) => ({ - ...basePayload, - url: absoluteUrl || basePayload.url, - referrer: absoluteReferrer || basePayload.referrer, - }), - "pageview", - ]); -} - -export function trackVideoView({ - videoId, - title, - source, - hasMagnet, - hasUrl, -} = {}) { - if (!isBrowserEnvironment()) { - return; - } - - const payload = {}; - - if (videoId) { - payload.videoId = String(videoId); - } - - if (title) { - payload.title = String(title); - } - - if (source) { - payload.source = String(source); - } - - if (typeof hasMagnet === "boolean") { - payload.hasMagnet = hasMagnet; - } - - if (typeof hasUrl === "boolean") { - payload.hasUrl = hasUrl; - } - - // 🔧 merged conflicting changes from codex/add-tracking-script-to-all-pages vs unstable - invokeUmami("track", [ANALYTICS_CONFIG.videoViewEventName, payload]); -} - -// Immediately queue the analytics script so page views are captured early. -if (isBrowserEnvironment()) { - ensureAnalyticsLoaded(); -} diff --git a/js/analyticsConfig.js b/js/analyticsConfig.js deleted file mode 100644 index a4bf0749..00000000 --- a/js/analyticsConfig.js +++ /dev/null @@ -1,18 +0,0 @@ -// js/analyticsConfig.js -// Central configuration for site-wide analytics tracking. - -export const ANALYTICS_CONFIG = Object.freeze({ - /** - * Hosted Umami script that powers analytics. - * Update this value if the tracker is relocated. - */ - scriptSrc: "https://umami.malin.onl/script.js", - /** - * The Umami website identifier for this deployment. - */ - websiteId: "1f8eead2-79f0-4dba-8c3b-ed9b08b6e877", - /** - * Event name used when recording individual video views. - */ - videoViewEventName: "video_view", -}); diff --git a/js/app.js b/js/app.js index cd0ab0c1..6008e37b 100644 --- a/js/app.js +++ b/js/app.js @@ -15,7 +15,6 @@ import { safeDecodeMagnet } from "./magnetUtils.js"; import { extractMagnetHints, normalizeAndAugmentMagnet } from "./magnet.js"; import { deriveTorrentPlaybackConfig } from "./playbackUtils.js"; import { URL_FIRST_ENABLED } from "./constants.js"; -import { trackVideoView } from "./analytics.js"; import { attachHealthBadges } from "./gridHealth.js"; import { attachUrlHealthBadges } from "./urlHealthObserver.js"; import { updateVideoCardSourceVisibility } from "./utils/cardSourceVisibility.js"; @@ -6592,14 +6591,6 @@ class Application { const sanitizedMagnet = magnetSupported ? usableMagnetCandidate : ""; - trackVideoView({ - videoId: video.id || eventId, - title: video.title || "Untitled", - source: "event", - hasMagnet: !!sanitizedMagnet, - hasUrl: !!trimmedUrl, - }); - const knownPostedAt = this.getKnownVideoPostedAt(video); const normalizedEditedAt = Number.isFinite(video.created_at) ? Math.floor(video.created_at) @@ -6963,17 +6954,6 @@ class Application { this.zapController?.setVisibility(false); this.zapController?.resetState(); - trackVideoView({ - videoId: - typeof title === "string" && title.trim().length > 0 - ? `direct:${title.trim()}` - : "direct-playback", - title, - source: "direct", - hasMagnet: !!sanitizedMagnet, - hasUrl: !!sanitizedUrl, - }); - if (!sanitizedUrl && !sanitizedMagnet) { const message = trimmedMagnet && !magnetSupported ? UNSUPPORTED_BTITH_MESSAGE diff --git a/js/index.js b/js/index.js index 13d0d68e..17c7f8e2 100644 --- a/js/index.js +++ b/js/index.js @@ -137,14 +137,9 @@ const fetchPartial = async (url) => { async function loadModal(url) { try { const html = await fetchPartial(url); - // Remove analytics loader tags from modal partials to avoid duplicate pageview events. - const sanitizedHtml = html.replace( - /]*src=["'][^"']*tracking\.js[^"']*["'][^>]*>\s*<\/script>/gi, - "" - ); document .getElementById("modalContainer") - .insertAdjacentHTML("beforeend", sanitizedHtml); + .insertAdjacentHTML("beforeend", html); const modalContainer = document.getElementById("modalContainer"); if (modalContainer) { applyDesignSystemAttributes(modalContainer); diff --git a/js/tracking.js b/js/tracking.js deleted file mode 100644 index f19158c7..00000000 --- a/js/tracking.js +++ /dev/null @@ -1,41 +0,0 @@ -// js/tracking.js -// Centralized configuration and loader for the site's analytics script. -// Update `bitvidTrackingConfig` to change the tracking provider or settings. -window.bitvidTrackingConfig = window.bitvidTrackingConfig || { - src: "https://umami.malin.onl/script.js", - websiteId: "1f8eead2-79f0-4dba-8c3b-ed9b08b6e877", -}; - -(function loadTrackingScript(config) { - if (!config || !config.src) { - return; - } - - if (document.querySelector(`script[src="${config.src}"]`)) { - return; - } - - const script = document.createElement("script"); - script.src = config.src; - script.defer = true; - - if (config.websiteId) { - script.setAttribute("data-website-id", config.websiteId); - } - - const additionalAttributes = config.attributes || {}; - Object.entries(additionalAttributes).forEach(([key, value]) => { - if (key === "defer") { - script.defer = Boolean(value); - return; - } - - if (value === false || value === null || typeof value === "undefined") { - return; - } - - script.setAttribute(key, value); - }); - - document.head.appendChild(script); -})(window.bitvidTrackingConfig); diff --git a/tests/nostr-ephemeral-dm-tester.html b/tests/nostr-ephemeral-dm-tester.html index c3f9b36a..be393b09 100644 --- a/tests/nostr-ephemeral-dm-tester.html +++ b/tests/nostr-ephemeral-dm-tester.html @@ -3,7 +3,6 @@ Nostr Ephemeral DM Tester (Using finalizeEvent) -