RoSniperX

frontend launcher hijack mobile stream sniper

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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";
                }
            );
        });
    }
})();