(function() { var CHANNELS = [ { id: "angelw1re", name: "Angelw1re" }, { id: "vikotheghost", name: "Vikotheghost" }, { id: "raiinelive", name: "RaiineLive" }, { id: "viuryse", name: "Viuryse" }, { id: "sarielleenvt", name: "Sarielleenvt" }, { id: "cawmfy", name: "Cawmfy" }, { id: "grimiable", name: "Grimiable" }, { id: "meepstic", name: "Meepstic" }, { id: "taintedtinta", name: "Taintedtinta" }, { id: "paroposa", name: "Paroposa" } ]; var WORKER = "https://black-feather-ba2a.rinaisuofficial.workers.dev"; var intervals = {}; function safeKey(ch) { return ch.replace(/[^a-z0-9]/gi, "_"); } function pad(n) { return n < 10 ? "0" + n : "" + n; } function formatElapsed(seconds) { var h = Math.floor(seconds / 3600); var m = Math.floor((seconds % 3600) / 60); var s = seconds % 60; if (h > 0) return pad(h) + ":" + pad(m) + ":" + pad(s); return pad(m) + ":" + pad(s); } function startTimer(ch, startedAt) { if (intervals[ch]) clearInterval(intervals[ch]); var el = document.getElementById("twtimer-" + ch); function tick() { if (!el) return; var elapsed = Math.floor((Date.now() - new Date(startedAt).getTime()) / 1000); el.textContent = formatElapsed(elapsed); } tick(); intervals[ch] = setInterval(tick, 1000); } function stopTimer(ch) { if (intervals[ch]) { clearInterval(intervals[ch]); delete intervals[ch]; } var el = document.getElementById("twtimer-" + ch); if (el) el.textContent = "--:--"; } var style = document.createElement("style"); style.textContent = [ ".tw-wrap{max-width:900px;margin:0 auto;font-family:sans-serif}", ".tw-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}", "@media(max-width:540px){.tw-grid{grid-template-columns:1fr}}", ".tw-card{border:1px solid #2a2a2a;border-radius:10px;overflow:hidden;background:#1a1a1a;transition:border-color 0.2s,box-shadow 0.2s,transform 0.15s;cursor:pointer;text-decoration:none;display:block}", ".tw-card:hover{transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,0.4)}", ".tw-card.is-live{border-color:#cc0000;box-shadow:0 0 0 1px #cc000044}", ".tw-card.is-live:hover{box-shadow:0 0 0 1px #cc000044,0 6px 20px rgba(0,0,0,0.4)}", ".tw-card-inner{display:flex;align-items:stretch;height:120px}", ".tw-pfp{width:120px;flex-shrink:0;object-fit:cover;object-position:center;display:block}", ".tw-pfp-ph{width:120px;flex-shrink:0;background:#2a2a2a;display:flex;align-items:center;justify-content:center;color:#555;font-size:11px}", ".tw-mid{flex:1;padding:10px 12px;display:flex;flex-direction:column;justify-content:center;gap:4px;min-width:0;overflow:hidden}", ".tw-top-row{display:flex;align-items:center;gap:6px}", ".tw-timer{font-size:11px;color:#888;font-variant-numeric:tabular-nums;flex-shrink:0}", ".tw-card.is-live .tw-timer{color:#cc0000}", ".tw-live-badge{font-size:10px;font-weight:700;padding:2px 6px;border-radius:4px;background:#cc0000;color:#fff;letter-spacing:0.05em;flex-shrink:0}", ".tw-name{font-size:14px;font-weight:700;color:#eee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}", ".tw-title{font-size:11px;color:#aaa;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.4}", ".tw-game{font-size:11px;color:#666;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}", ".tw-thumb-wrap{width:160px;flex-shrink:0;position:relative;overflow:hidden;background:#111}", ".tw-thumb{width:100%;height:100%;object-fit:cover;display:block;transition:filter 0.3s}", ".tw-thumb.greyed{filter:grayscale(100%) brightness(0.4)}", ".tw-thumb-offline{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#444;font-size:11px}" ].join(""); document.head.appendChild(style); var wrap = document.createElement("div"); wrap.className = "tw-wrap"; var grid = document.createElement("div"); grid.className = "tw-grid"; grid.id = "tw-grid"; wrap.appendChild(grid); function sortCards() { var cards = Array.prototype.slice.call(grid.querySelectorAll(".tw-card")); cards.sort(function(a, b) { return (a.classList.contains("is-live") ? 0 : 1) - (b.classList.contains("is-live") ? 0 : 1); }); cards.forEach(function(c) { grid.appendChild(c); }); } CHANNELS.forEach(function(ch) { var card = document.createElement("a"); card.className = "tw-card"; card.id = "twcard-" + ch.id; card.href = "https://www.twitch.tv/" + ch.id; card.target = "_blank"; card.rel = "noopener noreferrer"; var inner = document.createElement("div"); inner.className = "tw-card-inner"; var pfp = document.createElement("img"); pfp.className = "tw-pfp"; pfp.id = "twpfp-" + ch.id; pfp.alt = ch.name; pfp.src = ""; pfp.style.background = "#2a2a2a"; inner.appendChild(pfp); var mid = document.createElement("div"); mid.className = "tw-mid"; var topRow = document.createElement("div"); topRow.className = "tw-top-row"; var timer = document.createElement("span"); timer.className = "tw-timer"; timer.id = "twtimer-" + ch.id; timer.textContent = "--:--"; var liveBadge = document.createElement("span"); liveBadge.className = "tw-live-badge"; liveBadge.id = "twlive-" + ch.id; liveBadge.textContent = "LIVE"; liveBadge.style.display = "none"; topRow.appendChild(timer); topRow.appendChild(liveBadge); var nameEl = document.createElement("div"); nameEl.className = "tw-name"; nameEl.textContent = ch.name; var titleEl = document.createElement("div"); titleEl.className = "tw-title"; titleEl.id = "twtitle-" + ch.id; titleEl.textContent = ""; var gameEl = document.createElement("div"); gameEl.className = "tw-game"; gameEl.id = "twgame-" + ch.id; gameEl.textContent = "Offline"; mid.appendChild(topRow); mid.appendChild(nameEl); mid.appendChild(titleEl); mid.appendChild(gameEl); inner.appendChild(mid); var thumbWrap = document.createElement("div"); thumbWrap.className = "tw-thumb-wrap"; var thumb = document.createElement("img"); thumb.className = "tw-thumb greyed"; thumb.id = "twthumb-" + ch.id; thumb.src = "https://static-cdn.jtvnw.net/previews-ttv/live_user_" + ch.id + "-320x180.jpg"; thumb.alt = ""; thumbWrap.appendChild(thumb); var thumbOff = document.createElement("div"); thumbOff.className = "tw-thumb-offline"; thumbOff.id = "twthumboff-" + ch.id; thumbOff.textContent = "offline"; thumbWrap.appendChild(thumbOff); inner.appendChild(thumbWrap); card.appendChild(inner); grid.appendChild(card); }); function fetchProfiles() { var logins = CHANNELS.map(function(ch) { return ch.id; }).join(","); fetch(WORKER + "?logins=" + logins) .then(function(r) { return r.json(); }) .then(function(profiles) { CHANNELS.forEach(function(ch) { var img = document.getElementById("twpfp-" + ch.id); if (img && profiles[ch.id]) img.src = profiles[ch.id]; }); }) .catch(function(e) { console.warn("Profile fetch failed:", e); }); } function checkStatus() { var gql = "{" + CHANNELS.map(function(ch) { return "ch_" + safeKey(ch.id) + ':user(login:"' + ch.id + '"){stream{viewersCount,game{name},createdAt,title}}'; }).join("") + "}"; fetch("https://gql.twitch.tv/gql", { method: "POST", headers: { "Client-Id": "kimne78kx3ncx6brgo4mv6wki5h1ko", "Content-Type": "application/json" }, body: JSON.stringify({ query: gql }) }) .then(function(r) { return r.json(); }) .then(function(json) { var data = json.data || {}; CHANNELS.forEach(function(ch) { var stream = (data["ch_" + safeKey(ch.id)] || {}).stream; var card = document.getElementById("twcard-" + ch.id); var badge = document.getElementById("twlive-" + ch.id); var titleEl = document.getElementById("twtitle-" + ch.id); var gameEl = document.getElementById("twgame-" + ch.id); var thumb = document.getElementById("twthumb-" + ch.id); var thumbOff = document.getElementById("twthumboff-"+ ch.id); if (stream) { if (card) card.classList.add("is-live"); if (badge) badge.style.display = "inline-block"; if (thumb) { thumb.classList.remove("greyed"); thumb.src = "https://static-cdn.jtvnw.net/previews-ttv/live_user_" + ch.id + "-320x180.jpg?t=" + Date.now(); } if (thumbOff) thumbOff.style.display = "none"; if (titleEl) titleEl.textContent = stream.title || ""; if (gameEl) gameEl.textContent = (stream.game && stream.game.name) ? stream.game.name : "Live"; if (stream.createdAt) startTimer(ch.id, stream.createdAt); } else { if (card) card.classList.remove("is-live"); if (badge) badge.style.display = "none"; if (thumb) thumb.classList.add("greyed"); if (thumbOff) thumbOff.style.display = "flex"; if (titleEl) titleEl.textContent = ""; if (gameEl) gameEl.textContent = "Offline"; stopTimer(ch.id); } }); sortCards(); }) .catch(function(e) { console.warn("Twitch status check failed:", e); }); } var currentScript = document.currentScript; if (currentScript && currentScript.parentNode) { currentScript.parentNode.insertBefore(wrap, currentScript); } else { document.body.appendChild(wrap); } fetchProfiles(); checkStatus(); setInterval(checkStatus, 90000); setInterval(fetchProfiles, 3600000); })();