Auto extract and display Twitch raid IDs
// ==UserScript==
// @name Twitch Raid ID Extractor
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Auto extract and display Twitch raid IDs
// @author Catrine Omar
// @match https://www.twitch.tv/*
// @license CC BY-NC-ND 4.0
// @grant none
// ==/UserScript==
(function () {
'use strict';
let raidWidget = null;
let currentRaidId = null;
function createWidget() {
const widget = document.createElement('div');
widget.style.cssText = `
position:fixed;
top:80px;
right:20px;
background:#18181b;
border:1px solid #2a2a2d;
border-radius:6px;
padding:12px;
z-index:9999;
display:none;
width:280px;
font-family:system-ui;
`;
widget.innerHTML = `
<div style="display:flex;justify-content:space-between;cursor:move">
<span style="color:#fff;font-size:13px">Raid ID</span>
<button id="closeBtn" style="background:none;border:none;color:#aaa;font-size:18px">×</button>
</div>
<div style="margin-top:8px;background:#0e0e10;padding:8px;border-radius:4px">
<div id="raidText" style="font-family:monospace;font-size:11px;color:#adadb8"></div>
</div>
<button id="copyBtn" style="margin-top:8px;width:100%;background:#9147ff;border:none;color:#fff;padding:6px;border-radius:4px">
Copy
</button>
`;
document.body.appendChild(widget);
makeDraggable(widget);
widget.querySelector('#copyBtn').onclick = () => {
navigator.clipboard.writeText(currentRaidId || '');
};
widget.querySelector('#closeBtn').onclick = () => {
widget.style.display = 'none';
currentRaidId = null;
};
return widget;
}
function makeDraggable(el) {
let x = 0, y = 0, mx = 0, my = 0;
el.firstElementChild.onmousedown = e => {
mx = e.clientX;
my = e.clientY;
document.onmousemove = ev => {
x = mx - ev.clientX;
y = my - ev.clientY;
mx = ev.clientX;
my = ev.clientY;
el.style.top = el.offsetTop - y + 'px';
el.style.left = el.offsetLeft - x + 'px';
el.style.right = 'auto';
};
document.onmouseup = () => {
document.onmousemove = null;
};
};
}
function showRaidId(id) {
if (id === currentRaidId) return;
currentRaidId = id;
if (!raidWidget) raidWidget = createWidget();
raidWidget.querySelector('#raidText').textContent = id;
raidWidget.style.display = 'block';
console.log('[Raid Extractor] Raid detected:', id);
}
function parseGQL(text) {
try {
const json = JSON.parse(text);
if (!Array.isArray(json)) return;
json.forEach(e => {
if (e?.data?.createRaid?.raid?.id) {
showRaidId(e.data.createRaid.raid.id);
}
});
} catch {}
}
const originalFetch = window.fetch;
window.fetch = function (...args) {
return originalFetch.apply(this, args).then(res => {
if (args[0]?.includes('gql.twitch.tv')) {
res.clone().text().then(parseGQL);
}
return res;
});
};
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (m, u) {
this.addEventListener('load', () => {
if (u?.includes('gql.twitch.tv')) {
parseGQL(this.responseText);
}
});
return originalOpen.apply(this, arguments);
};
console.log('[Raid Extractor] Active');
})();