Greasy Fork is available in English.
frontend launcher hijack mobile stream sniper
// ==UserScript==
// @name RoSniperX
// @namespace http://tampermonkey.net/
// @version 6.1
// @description frontend launcher hijack mobile stream sniper
// @author Lukas Dobbles (fixed by Grok-Raw)
// @match https://www.roblox.com/*
// @grant none
// ==/UserScript==
(function () {
"use strict";
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const getJSON = async (url, args = {}) => {
args.headers = args.headers || {};
args.credentials = "include";
let retries = 5;
while (retries--) {
try {
const res = await fetch(url, args);
if (res.status === 429) {
await sleep(2000);
continue;
}
return await res.json();
} catch (e) {
if (retries <= 0) throw e;
await sleep(1500);
}
}
};
const getUserId = (name) =>
getJSON("https://users.roblox.com/v1/usernames/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
usernames: [name],
excludeBannedUsers: true
})
}).then(d => d?.data?.[0]?.id);
const getThumb = (id) =>
getJSON(`https://thumbnails.roblox.com/v1/users/avatar-headshot?userIds=${id}&format=Png&size=150x150`)
.then(d => d.data[0].imageUrl);
const getServer = (placeId, cursor) => {
let url = `https://games.roblox.com/v1/games/${placeId}/servers/Public?limit=100`;
if (cursor) url += "&cursor=" + cursor;
return getJSON(url);
};
const fetchThumbs = (tokens) => {
const body = tokens.map(token => ({
requestId: `0:${token}:AvatarHeadshot:150x150:png:regular`,
type: "AvatarHeadShot",
token,
format: "png",
size: "150x150"
}));
return getJSON("https://thumbnails.roblox.com/v1/batch", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json"
},
body: JSON.stringify(body)
});
};
const search = async (placeId, name, setStatus, cb, setThumb) => {
try {
const userId = await getUserId(name);
if (!userId) {
setStatus("User not found.");
cb({ found: false });
return;
}
const thumbUrl = await getThumb(userId);
setThumb(thumbUrl);
setStatus("Target avatar loaded...");
let cursor = null;
let serverQueue = [];
let serversScraped = 0;
let playersScraped = 0;
const startTime = Date.now();
do {
const servers = await getServer(placeId, cursor);
if (!servers || !servers.data) break;
for (const place of servers.data) {
serversScraped++;
if (place.playerTokens && place.playerTokens.length) {
playersScraped += place.playerTokens.length;
for (const token of place.playerTokens) {
serverQueue.push({ token, place });
}
}
}
cursor = servers.nextPageCursor;
setStatus(`Scanned ${serversScraped} servers / ${playersScraped} players / queued ${serverQueue.length}`);
await sleep(700);
} while (cursor);
setStatus(`Finished full scrape. Comparing ${serverQueue.length} player thumbnails...`);
let checked = 0;
while (serverQueue.length > 0) {
const batch = serverQueue.splice(0, 100);
try {
const thumbs = await fetchThumbs(batch.map(x => x.token));
if (!thumbs || !thumbs.data) {
await sleep(1000);
continue;
}
checked += batch.length;
setStatus(`Compared \( {checked}/ \){playersScraped} thumbnails...`);
for (const thumb of thumbs.data) {
if (!thumb || !thumb.imageUrl) continue;
if (thumb.imageUrl === thumbUrl) {
const thumbToken = thumb.requestId.split(":")[1];
const matchedPlace = batch.find(x => x.token === thumbToken)?.place;
if (matchedPlace) {
setStatus(`FOUND TARGET after ${(Date.now() - startTime) / 1000}s`);
cb({ found: true, place: matchedPlace });
return;
}
}
}
await sleep(500);
} catch {
await sleep(1200);
}
}
cb({ found: false });
} catch (e) {
setStatus("Search failed: " + e.message);
cb({ found: false });
}
};
// FIXED & AGGRESSIVE LAUNCH HIJACK
const hijackLaunchAndJoin = async (targetGameId, setStatus) => {
try {
setStatus("Hijacking Roblox frontend launcher...");
let captured = null;
const tryCapture = (url) => {
if (typeof url === "string" && url.includes("robloxmobile://")) {
captured = url;
return true;
}
return false;
};
// Backup originals
const oldOpen = window.open;
const oldAssign = window.location.assign;
const oldReplace = window.location.replace;
// Override window.open
window.open = function (url, ...args) {
if (tryCapture(url)) return null;
return oldOpen.apply(this, [url, ...args]);
};
// Aggressive location overrides
let originalHref = window.location.href;
try {
Object.defineProperty(window.location, "href", {
configurable: true,
enumerable: true,
get() { return originalHref; },
set(v) {
if (tryCapture(v)) return;
originalHref = v;
oldAssign.call(window.location, v);
}
});
} catch (e) {}
window.location.assign = function (url) {
if (tryCapture(url)) return;
return oldAssign.call(window.location, url);
};
window.location.replace = function (url) {
if (tryCapture(url)) return;
return oldReplace.call(window.location, url);
};
// Find play button
const playBtn =
document.querySelector('[data-testid="play-button"]') ||
document.querySelector('.btn-common-play-game-lg') ||
document.querySelector('.game-play-button') ||
document.querySelector('#game-detail-play-button') ||
document.querySelector('button[aria-label*="Play"]');
if (!playBtn) {
setStatus("Could not locate Roblox Play button.");
restore();
return;
}
setStatus("Clicking Play button...");
playBtn.click();
// Wait for capture
let waited = 0;
while (!captured && waited < 15000) {
await sleep(400);
waited += 400;
}
restore();
if (!captured) {
setStatus("Failed to capture robloxmobile:// URI.");
return;
}
setStatus("Captured launcher. Rewriting target server...");
let finalUrl = captured;
if (finalUrl.includes("gameInstanceId=")) {
finalUrl = finalUrl.replace(/gameInstanceId=[^&]+/, `gameInstanceId=${targetGameId}`);
} else {
finalUrl += (finalUrl.includes("?") ? "&" : "?") + `gameInstanceId=${targetGameId}`;
}
setStatus("Launching exact target server...");
// Final launch methods (multiple fallbacks)
setTimeout(() => {
window.location.href = finalUrl;
}, 50);
setTimeout(() => {
if (document.hidden) return;
window.open(finalUrl, "_self");
}, 300);
} catch (e) {
setStatus("Launch hijack failed: " + e.message);
restore();
}
function restore() {
try {
window.open = oldOpen;
window.location.assign = oldAssign;
window.location.replace = oldReplace;
} catch {}
}
};
// UI Injection
const instancesContainer = document.getElementById("running-game-instances-container");
if (instancesContainer) {
const containerHeader = document.createElement("div");
containerHeader.id = "rosniperx";
containerHeader.style.marginBottom = "15px";
const headerText = document.createElement("h2");
headerText.innerText = "RoSniperX v6.1";
containerHeader.appendChild(headerText);
const form = document.createElement("form");
const thumbImage = document.createElement("img");
thumbImage.height = "50";
thumbImage.style.display = "none";
thumbImage.style.borderRadius = "8px";
thumbImage.style.marginBottom = "8px";
containerHeader.appendChild(thumbImage);
const usernameInput = document.createElement("input");
usernameInput.classList = "input-field";
usernameInput.placeholder = "Target Username";
usernameInput.style.width = "100%";
usernameInput.style.marginBottom = "8px";
form.appendChild(usernameInput);
const submitButton = document.createElement("button");
submitButton.classList = "btn-primary-md";
submitButton.innerText = "Search & Snipe";
submitButton.disabled = true;
form.appendChild(submitButton);
usernameInput.addEventListener("keyup", e => {
submitButton.disabled = e.target.value.trim().length === 0;
});
const statusText = document.createElement("p");
statusText.style.margin = "8px 0";
statusText.style.fontSize = "14px";
form.appendChild(statusText);
const joinBtn = document.createElement("button");
joinBtn.style.display = "none";
joinBtn.innerText = "🚀 Join Exact Server";
joinBtn.classList = "btn-control-xs btn-primary-md";
joinBtn.style.width = "100%";
joinBtn.style.marginTop = "8px";
containerHeader.appendChild(form);
containerHeader.appendChild(joinBtn);
instancesContainer.insertBefore(containerHeader, instancesContainer.firstChild);
form.addEventListener("submit", evt => {
evt.preventDefault();
joinBtn.style.display = "none";
const placeId = location.href.match(/games\/(\d+)/)?.[1];
if (!placeId) {
statusText.innerText = "Not on a game page.";
return;
}
search(
placeId,
usernameInput.value.trim(),
txt => statusText.innerText = txt,
result => {
if (!result.found) {
statusText.innerText = "Target not found after full scan.";
return;
}
joinBtn.style.display = "block";
joinBtn.onclick = () => {
hijackLaunchAndJoin(result.place.id, txt => statusText.innerText = txt);
};
},
src => {
thumbImage.src = src;
thumbImage.style.display = "block";
}
);
});
}
})();