PageSourceSearch

https://clutch-app.co/lfg/cover.js

js clutch-app.co collected 2026-10-06 13:16:05 UTC 4,944 bytes, 158 lines download raw bytes

1(() => {
2  const slugMeta = document.querySelector('meta[name="lfg:slug"]');
3  if (!slugMeta) return;
4
5  const slug = slugMeta.getAttribute("content")?.trim();
6  if (!slug) return;
7
8  const gameName =
9    document
10      .querySelector('meta[name="lfg:game"]')
11      ?.getAttribute("content")
12      ?.trim() ||
13    document.querySelector("h1")?.textContent?.trim() ||
14    "";
15
16  const coverImg = document.getElementById("coverImage");
17  if (!coverImg) return;
18
19  const isAndroid = /Android/i.test(navigator.userAgent);
20
21  const SUPABASE_URL = window.CLUTCH_SUPABASE_URL || "";
22  const SUPABASE_ANON_KEY = window.CLUTCH_SUPABASE_ANON_KEY || "";
23
24  const headers = {
25    apikey: SUPABASE_ANON_KEY,
26    Authorization: `Bearer ${SUPABASE_ANON_KEY}`,
27  };
28
29  function fetchBySlug() {
30    const endpoint = new URL(`${SUPABASE_URL}/rest/v1/hubs`);
31    endpoint.searchParams.set("select", "id,cover_image,name,slug");
32    endpoint.searchParams.set("slug", `eq.${slug}`);
33    endpoint.searchParams.set("is_visible", "eq.true");
34    endpoint.searchParams.set("limit", "1");
35    return fetch(endpoint.toString(), { headers }).then((res) =>
36      res.ok ? res.json() : Promise.reject(res),
37    );
38  }
39
40  function fetchByName(candidate) {
41    const endpoint = new URL(`${SUPABASE_URL}/rest/v1/hubs`);
42    endpoint.searchParams.set("select", "id,cover_image,name,slug");
43    endpoint.searchParams.set("name", `ilike.%${candidate}%`);
44    endpoint.searchParams.set("is_visible", "eq.true");
45    endpoint.searchParams.set("limit", "1");
46    return fetch(endpoint.toString(), { headers }).then((res) =>
47      res.ok ? res.json() : Promise.reject(res),
48    );
49  }
50
51  const slugToNameMap = {
52    "gta-5": "Grand Theft Auto V",
53    warzone: "Call of Duty: Warzone",
54    cs2: "Counter-Strike",
55    "counter-strike-2": "Counter-Strike",
56    fortnite: "Fortnite",
57  };
58
59  const nameCandidates = [];
60  if (slugToNameMap[slug]) nameCandidates.push(slugToNameMap[slug]);
61  if (gameName) nameCandidates.push(gameName);
62  if (gameName && gameName.endsWith(" 2")) {
63    nameCandidates.push(gameName.replace(/\s2$/, ""));
64  }
65  if (slug && slug.includes("counter-strike")) {
66    nameCandidates.push("Counter-Strike");
67  }
68
69  fetchBySlug()
70    .then((rows) => {
71      const item = Array.isArray(rows) ? rows[0] : null;
72      if (item) return item;
73      return null;
74    })
75    .then((item) => {
76      if (item) return item;
77      let chain = Promise.resolve(null);
78      nameCandidates.forEach((candidate) => {
79        chain = chain.then((found) => {
80          if (found) return found;
81          return fetchByName(candidate).then((rows) =>
82            Array.isArray(rows) ? rows[0] : null,
83          );
84        });
85      });
86      return chain;
87    })
88    .then((item) => {
89      if (!item) return;
90
91      if (item.cover_image) {
92        coverImg.setAttribute("src", item.cover_image);
93        const altText = item.name || gameName || "Game cover art";
94        coverImg.setAttribute("alt", `${altText} cover art`);
95      }
96
97      if (item.id) {
98        window.__clutch = window.__clutch || {};
99        window.__clutch.lfgId = item.id;
100      }
101
102      const lfgLinks = document.querySelectorAll('a[href^="clutchapp://lfg/"]');
103      lfgLinks.forEach((link) => {
104        if (item.id) {
105          link.dataset.hubId = item.id;
106          link.setAttribute(
107            "href",
108            `clutchapp://lfg/${encodeURIComponent(item.id)}`,
109          );
110        } else {
111          link.removeAttribute("data-hub-id");
112          link.setAttribute(
113            "href",
114            `clutchapp://lfg/${encodeURIComponent(slug)}`,
115          );
116        }
117      });
118    })
119    .catch(() => {
120      // Fail silently; keep fallback image.
121    });
122
123  if (isAndroid) {
124    const FALLBACK = "/download.html";
125    const openIntent = (url, fb) => {
126      const appendAttribution =
127        window.ClutchAttribution?.appendAttributionToUrl;
128      const fallback =
129        typeof appendAttribution === "function"
130          ? appendAttribution(fb || FALLBACK)
131          : fb || FALLBACK;
132      const targetUrl =
133        typeof appendAttribution === "function"
134          ? appendAttribution(String(url || ""))
135          : String(url || "");
136      const raw = targetUrl.startsWith("clutchapp://")
137        ? targetUrl.slice("clutchapp://".length)
138        : targetUrl.replace(/^\/+/, "");
139      const intent = `intent://${raw}#Intent;scheme=clutchapp;package=com.erniec1.ClutchApp;end`;
140
141      let didHide = false;
142      const onVis = () => {
143        if (document.visibilityState === "hidden") didHide = true;
144      };
145      document.addEventListener("visibilitychange", onVis, { passive: true });
146
147      window.location.href = intent;
148
149      setTimeout(() => {
150        document.removeEventListener("visibilitychange", onVis);
151        if (!didHide) window.location.href = fallback;
152      }, 1400);
153    };
154
155    window.__clutch = window.__clutch || {};
156    window.__clutch.openApp = openIntent;
157  }
158})();

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.